feat: redis, fileserver, httpclient 런타임 시점 구현 추가
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
readonly JQ_VERSION='1.8.1'
|
||||
readonly JQ_SHA256_AMD64='020468de7539ce70ef1bceaf7cde2e8c4f2ca6c3afb84642aabc5c97d9fc2a0d'
|
||||
readonly JQ_SHA256_ARM64='6bc62f25981328edd3cfcfe6fe51b073f2d7e7710d7ef7fcdac28d4e384fc3d4'
|
||||
readonly DOWNLOAD_BASE_URL="${JQ_DOWNLOAD_BASE_URL:-https://github.com/jqlang/jq/releases/download/jq-${JQ_VERSION}}"
|
||||
|
||||
: "${RUNNER_TEMP:?RUNNER_TEMP must be set by the CI runner}"
|
||||
: "${GITHUB_PATH:?GITHUB_PATH must be set by the CI runner}"
|
||||
|
||||
architecture="${RUNNER_ARCH:-$(uname -m)}"
|
||||
case "${architecture}" in
|
||||
X64 | x86_64 | amd64)
|
||||
asset='jq-linux-amd64'
|
||||
expected_sha256="${JQ_SHA256_AMD64}"
|
||||
;;
|
||||
ARM64 | aarch64 | arm64)
|
||||
asset='jq-linux-arm64'
|
||||
expected_sha256="${JQ_SHA256_ARM64}"
|
||||
;;
|
||||
*)
|
||||
printf '::error::install-jq: unsupported runner architecture: %s\n' "${architecture}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
install_dir="${RUNNER_TEMP}/jq-${JQ_VERSION}/bin"
|
||||
destination="${install_dir}/jq"
|
||||
mkdir -p "${install_dir}"
|
||||
|
||||
temporary="$(mktemp "${RUNNER_TEMP}/jq-${JQ_VERSION}.XXXXXX")"
|
||||
trap 'rm -f "${temporary}"' EXIT
|
||||
|
||||
curl --fail --show-error --silent --location --retry 3 \
|
||||
--proto '=https' --tlsv1.2 \
|
||||
"${DOWNLOAD_BASE_URL}/${asset}" \
|
||||
--output "${temporary}"
|
||||
printf '%s %s\n' "${expected_sha256}" "${temporary}" | sha256sum -c -
|
||||
chmod 0755 "${temporary}"
|
||||
mv "${temporary}" "${destination}"
|
||||
trap - EXIT
|
||||
|
||||
printf '%s\n' "${install_dir}" >> "${GITHUB_PATH}"
|
||||
installed_version="$("${destination}" --version)"
|
||||
if [[ "${installed_version}" != "jq-${JQ_VERSION}" ]]; then
|
||||
printf '::error::install-jq: expected jq-%s, got %s\n' "${JQ_VERSION}" "${installed_version}" >&2
|
||||
exit 1
|
||||
fi
|
||||
printf 'install-jq: %s installed under RUNNER_TEMP\n' "${installed_version}"
|
||||
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
||||
readonly REPO_ROOT="$(git -C "${SCRIPT_DIR}" rev-parse --show-toplevel)"
|
||||
readonly EXPECTED_SCRIPT_DIR="$(cd -- "${REPO_ROOT}/.github/scripts" && pwd -P)"
|
||||
readonly MATRIX="${REPO_ROOT}/.github/ci-gate-matrix.yml"
|
||||
readonly EXPECTED_GATE_COUNT=19
|
||||
|
||||
if [[ "${SCRIPT_DIR}" != "${EXPECTED_SCRIPT_DIR}" ]]; then
|
||||
printf '::error::gate-matrix-lint: script resolved outside the repository .github/scripts directory\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "${MATRIX}" ]]; then
|
||||
printf '::error::gate-matrix-lint: missing %s\n' "${MATRIX}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
records="$(
|
||||
awk '
|
||||
function flush() {
|
||||
if (id != "") {
|
||||
printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", id, blocking, mechanism, ref, workflow, job, execution
|
||||
}
|
||||
}
|
||||
/^[[:space:]]*-[[:space:]]+id:[[:space:]]*/ {
|
||||
flush()
|
||||
id=$0
|
||||
sub(/^[[:space:]]*-[[:space:]]+id:[[:space:]]*/, "", id)
|
||||
blocking=mechanism=ref=workflow=job=execution=""
|
||||
next
|
||||
}
|
||||
/^[[:space:]]+release_blocking:[[:space:]]*/ {
|
||||
blocking=$0
|
||||
sub(/^[[:space:]]+release_blocking:[[:space:]]*/, "", blocking)
|
||||
next
|
||||
}
|
||||
/^[[:space:]]+mechanism:[[:space:]]*/ {
|
||||
mechanism=$0
|
||||
sub(/^[[:space:]]+mechanism:[[:space:]]*/, "", mechanism)
|
||||
next
|
||||
}
|
||||
/^[[:space:]]+ref:[[:space:]]*/ {
|
||||
ref=$0
|
||||
sub(/^[[:space:]]+ref:[[:space:]]*/, "", ref)
|
||||
next
|
||||
}
|
||||
/^[[:space:]]+workflow:[[:space:]]*/ {
|
||||
workflow=$0
|
||||
sub(/^[[:space:]]+workflow:[[:space:]]*/, "", workflow)
|
||||
next
|
||||
}
|
||||
/^[[:space:]]+job:[[:space:]]*/ {
|
||||
job=$0
|
||||
sub(/^[[:space:]]+job:[[:space:]]*/, "", job)
|
||||
next
|
||||
}
|
||||
/^[[:space:]]+execution:[[:space:]]*/ {
|
||||
execution=$0
|
||||
sub(/^[[:space:]]+execution:[[:space:]]*/, "", execution)
|
||||
next
|
||||
}
|
||||
END { flush() }
|
||||
' "${MATRIX}"
|
||||
)"
|
||||
|
||||
declare -A seen_ids=()
|
||||
declare -a failures=()
|
||||
total=0
|
||||
verified=0
|
||||
delegated=0
|
||||
|
||||
job_body() {
|
||||
local workflow_file="$1"
|
||||
local job_id="$2"
|
||||
awk -v target="${job_id}" '
|
||||
$0 ~ "^ " target ":[[:space:]]*$" { inside=1; print; next }
|
||||
inside && $0 ~ "^ [A-Za-z0-9_-]+:[[:space:]]*$" { exit }
|
||||
inside { print }
|
||||
' "${workflow_file}"
|
||||
}
|
||||
|
||||
while IFS=$'\t' read -r id blocking mechanism ref workflow job execution; do
|
||||
[[ -z "${id}" ]] && continue
|
||||
total=$((total + 1))
|
||||
|
||||
if [[ -n "${seen_ids[${id}]:-}" ]]; then
|
||||
failures+=("duplicate gate id '${id}'")
|
||||
fi
|
||||
seen_ids["${id}"]=1
|
||||
|
||||
if [[ -z "${blocking}" || -z "${mechanism}" || -z "${ref}" || -z "${workflow}" \
|
||||
|| -z "${job}" || -z "${execution}" ]]; then
|
||||
failures+=("gate '${id}' has an empty required field")
|
||||
continue
|
||||
fi
|
||||
if [[ ! "${blocking}" =~ ^(true|false|conditional)$ ]]; then
|
||||
failures+=("gate '${id}' has invalid release_blocking '${blocking}'")
|
||||
fi
|
||||
if [[ ! "${workflow}" =~ ^[A-Za-z0-9._-]+\.ya?ml$ || ! "${job}" =~ ^[A-Za-z0-9_-]+$ ]]; then
|
||||
failures+=("gate '${id}' has an unsafe workflow or job identifier")
|
||||
continue
|
||||
fi
|
||||
|
||||
workflow_file="${REPO_ROOT}/.github/workflows/${workflow}"
|
||||
if [[ ! -f "${workflow_file}" ]]; then
|
||||
failures+=("gate '${id}' references missing workflow '.github/workflows/${workflow}'")
|
||||
continue
|
||||
fi
|
||||
if ! grep -Eqs -- "^[[:space:]]{2}${job}:[[:space:]]*$" "${workflow_file}"; then
|
||||
failures+=("gate '${id}' references missing job '${job}' in '${workflow}'")
|
||||
continue
|
||||
fi
|
||||
|
||||
case "${mechanism}" in
|
||||
gradle-custom-task)
|
||||
if ! grep -RqsE -- "tasks\\.register\\(['\"]${ref}['\"]" "${REPO_ROOT}/src" \
|
||||
--include='build.gradle'; then
|
||||
failures+=("gate '${id}' references unregistered Gradle task '${ref}'")
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
gradle-plugin-task)
|
||||
plugin="${ref%@*}"
|
||||
task="${ref#*@}"
|
||||
if [[ "${plugin}" == "${ref}" || -z "${task}" ]]; then
|
||||
failures+=("gate '${id}' must use plugin@task for gradle-plugin-task")
|
||||
continue
|
||||
fi
|
||||
if ! grep -RqsE -- "(id|apply plugin:)[[:space:]]+['\"]${plugin}['\"]" "${REPO_ROOT}/src" \
|
||||
--include='build.gradle'; then
|
||||
failures+=("gate '${id}' references unapplied Gradle plugin '${plugin}'")
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
contract-test)
|
||||
if [[ "${ref}" == /* || "${ref}" == *".."* || ! -f "${REPO_ROOT}/src/${ref}" ]]; then
|
||||
failures+=("gate '${id}' references missing or unsafe contract test 'src/${ref}'")
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
workflow-job)
|
||||
if [[ "${ref}" != "${job}" ]]; then
|
||||
failures+=("gate '${id}' workflow-job ref '${ref}' must equal job '${job}'")
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
delegated-pending)
|
||||
delegated=$((delegated + 1))
|
||||
printf "gate '%s': explicitly delegated-pending\n" "${id}"
|
||||
continue
|
||||
;;
|
||||
*)
|
||||
failures+=("gate '${id}' has unknown mechanism '${mechanism}'")
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${execution}" in
|
||||
check)
|
||||
if ! job_body "${workflow_file}" "${job}" | grep -Eqs -- '\./gradlew[[:space:]]+check([[:space:]]|$)'; then
|
||||
failures+=("gate '${id}' expects Gradle check in job '${job}'")
|
||||
continue
|
||||
fi
|
||||
if [[ "${mechanism}" == "gradle-custom-task" ]] \
|
||||
&& ! grep -RqsE -- "dependsOn.*named\\(['\"]${ref}['\"]\\)" "${REPO_ROOT}/src" \
|
||||
--include='build.gradle'; then
|
||||
failures+=("gate '${id}' task '${ref}' exists but is not wired into Gradle check")
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
explicit)
|
||||
if ! job_body "${workflow_file}" "${job}" | grep -Fqs -- "${ref}"; then
|
||||
failures+=("gate '${id}' task '${ref}' is not explicit in job '${job}'")
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
job)
|
||||
;;
|
||||
*)
|
||||
failures+=("gate '${id}' has unknown execution '${execution}'")
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
verified=$((verified + 1))
|
||||
done <<< "${records}"
|
||||
|
||||
if (( total != EXPECTED_GATE_COUNT )); then
|
||||
failures+=("matrix has ${total} gates; expected ${EXPECTED_GATE_COUNT}")
|
||||
fi
|
||||
|
||||
printf 'gate-matrix-lint: %d gates, %d verified, %d delegated-pending\n' \
|
||||
"${total}" "${verified}" "${delegated}"
|
||||
if (( ${#failures[@]} > 0 )); then
|
||||
printf '::error::gate-matrix-lint: %d drift(s) found\n' "${#failures[@]}" >&2
|
||||
for failure in "${failures[@]}"; do
|
||||
printf ' - %s\n' "${failure}" >&2
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
printf 'gate-matrix-lint: OK\n'
|
||||
Reference in New Issue
Block a user