From c8c0065f95cbffeecf4e6795a65c46b12545ad4e Mon Sep 17 00:00:00 2001 From: panicboat Date: Sun, 25 Oct 2026 08:59:37 +0900 Subject: [PATCH] ci: call the shared workflows from panicboat/.github The reusable workflows and scripts now live in panicboat/.github v1.0.0, so each workflow here only calls the shared version and the local copies are removed. The kubernetes stack is renamed to helmfile to match the stack names the shared resolver dispatches on. The Renovate config extends the shared preset and keeps only the rules specific to this repository. Claude-Session: https://claude.ai/code/session_01R7jQZQj1VyeBbYR7P1ssV7 Signed-off-by: panicboat --- .github/prompts/renovate-major-review.md | 4 +- .github/renovate.json | 64 +-- .../kubernetes-hydrate/hydrate-component.sh | 43 -- .../kubernetes-hydrate/hydrate-index.sh | 50 --- .../scripts/kubernetes-hydrate/render-diff.sh | 77 ---- .../summarize-manifest-diff.sh | 106 ----- .../tests/fixtures/identical/expected.md | 11 - .../tests/fixtures/identical/manifest.yaml | 4 - .../tests/fixtures/invalid/manifest.yaml | 2 - .../tests/fixtures/summarize/base.yaml | 62 --- .../tests/fixtures/summarize/expected.md | 29 -- .../tests/fixtures/summarize/head.yaml | 63 --- .../tests/render-diff.test.sh | 88 ----- .../tests/summarize-manifest-diff.test.sh | 35 -- .../check-release-configs.sh | 69 ---- .../terragrunt-release/release-service.sh | 29 -- .../terragrunt-release/release-targets.sh | 39 -- .github/scripts/terragrunt-release/test.sh | 374 ------------------ .../validate-apply-trigger.sh | 18 - .github/workflows/ci-gatekeeper.yaml | 20 +- .../label-base-deploy--dispatcher.yaml | 41 +- .../label-base-deploy--resolver.yaml | 148 +------ .github/workflows/lint-actions.yml | 11 +- .github/workflows/release--deploy.yaml | 52 +-- .github/workflows/release--plan.yaml | 44 +-- .github/workflows/release--please.yaml | 44 +-- .github/workflows/renovate-major-review.yaml | 102 +---- .../reusable--kubernetes-builder.yaml | 101 ----- .../reusable--kubernetes-hydrator.yaml | 125 ------ .../reusable--terragrunt-runner.yaml | 95 ----- .github/workflows/semantic-pull-request.yml | 23 +- .../workflows/test-terragrunt-release.yaml | 17 +- README-ja.md | 14 +- README.md | 14 +- docs/runbooks/eks-production-recreate.md | 6 +- workflow-config.yaml | 2 +- 36 files changed, 76 insertions(+), 1950 deletions(-) delete mode 100755 .github/scripts/kubernetes-hydrate/hydrate-component.sh delete mode 100755 .github/scripts/kubernetes-hydrate/hydrate-index.sh delete mode 100755 .github/scripts/kubernetes-hydrate/render-diff.sh delete mode 100755 .github/scripts/kubernetes-hydrate/summarize-manifest-diff.sh delete mode 100644 .github/scripts/kubernetes-hydrate/tests/fixtures/identical/expected.md delete mode 100644 .github/scripts/kubernetes-hydrate/tests/fixtures/identical/manifest.yaml delete mode 100644 .github/scripts/kubernetes-hydrate/tests/fixtures/invalid/manifest.yaml delete mode 100644 .github/scripts/kubernetes-hydrate/tests/fixtures/summarize/base.yaml delete mode 100644 .github/scripts/kubernetes-hydrate/tests/fixtures/summarize/expected.md delete mode 100644 .github/scripts/kubernetes-hydrate/tests/fixtures/summarize/head.yaml delete mode 100755 .github/scripts/kubernetes-hydrate/tests/render-diff.test.sh delete mode 100755 .github/scripts/kubernetes-hydrate/tests/summarize-manifest-diff.test.sh delete mode 100755 .github/scripts/terragrunt-release/check-release-configs.sh delete mode 100755 .github/scripts/terragrunt-release/release-service.sh delete mode 100755 .github/scripts/terragrunt-release/release-targets.sh delete mode 100755 .github/scripts/terragrunt-release/test.sh delete mode 100755 .github/scripts/terragrunt-release/validate-apply-trigger.sh delete mode 100644 .github/workflows/reusable--kubernetes-builder.yaml delete mode 100644 .github/workflows/reusable--kubernetes-hydrator.yaml delete mode 100644 .github/workflows/reusable--terragrunt-runner.yaml diff --git a/.github/prompts/renovate-major-review.md b/.github/prompts/renovate-major-review.md index bac6aed0..2c6edf42 100644 --- a/.github/prompts/renovate-major-review.md +++ b/.github/prompts/renovate-major-review.md @@ -7,7 +7,7 @@ You only read. Never modify files, push, approve, label, or comment yourself. ## How this repository deploys - Helm charts are never installed with `helm install` / `helm upgrade`. - `.github/scripts/kubernetes-hydrate/hydrate-component.sh` renders `kubernetes/components///` with `helmfile template --include-crds` (plus `kustomize build kustomization/`) into `kubernetes/manifests///manifest.yaml`, and Flux applies them after merge (production only: the `flux-system` Kustomization syncs `kubernetes/clusters/production`, which includes `kubernetes/manifests/production`, with `prune: true`). + `scripts/kubernetes-hydrate/hydrate-component.sh` of `panicboat/.github` renders `kubernetes/components///` with `helmfile template --include-crds` (plus `kustomize build kustomization/`) into `kubernetes/manifests///manifest.yaml`, and Flux applies them after merge (production only: the `flux-system` Kustomization syncs `kubernetes/clusters/production`, which includes `kubernetes/manifests/production`, with `prune: true`). - Consequences for upgrade guides written for `helm upgrade`: - CRDs rendered from the chart with this repository's values are applied by Flux with everything else, so "apply the CRDs manually before `helm upgrade`" steps are already satisfied for them; do not report them as manual work. CRDs the guide expects from another source (e.g. Gateway API CRDs managed by `kubernetes/components/gateway-api`) are not covered; report the needed change to that component as ⚠️. @@ -27,7 +27,7 @@ You only read. Never modify files, push, approve, label, or comment yourself. - the files Renovate changed 3. Ignore changes under `kubernetes/manifests/`; the hydrator generates them in parallel with this review, so they may be stale. 4. Read `.render-diff/summary.md` (the rendered diff). - For every component directory the pull request changes, it compares the base and the head rendered with this repository's values (`.github/scripts/kubernetes-hydrate/render-diff.sh`): image references, CRD versions, and added / removed resources. + For every component directory the pull request changes, it compares the base and the head rendered with this repository's values (`scripts/kubernetes-hydrate/render-diff.sh` of `panicboat/.github`): image references, CRD versions, and added / removed resources. Its `Full diff` paths are relative to `.render-diff/`; the files can be large, so Grep them instead of reading them whole. A component marked `Rendering failed` or `Summarizing failed` is uncovered (for `Summarizing failed`, still Grep its full diff). A component marked `Not rendered` is not deployed by the hydrator; review it from its files only. diff --git a/.github/renovate.json b/.github/renovate.json index 2ccd1180..c3fc610e 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,71 +1,9 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ - "config:recommended", - ":semanticCommits", - ":separateMajorReleases", - "group:monorepos", - "group:recommended", - "helpers:pinGitHubActionDigests" + "github>panicboat/.github" ], - "semanticCommitScope": "{{packageFileDir}}", - "timezone": "Asia/Tokyo", - "labels": [ - "🤖 renovate" - ], - "assigneesFromCodeOwners": false, - "reviewersFromCodeOwners": true, - "automergeType": "pr", - "automergeStrategy": "squash", - "platformAutomerge": true, - "prConcurrentLimit": 15, - "prHourlyLimit": 5, - "branchPrefix": "renovate/", - "rangeStrategy": "bump", - "schedule": [ - "before 4am every weekday" - ], - "minimumReleaseAge": "1 day", - "separateMinorPatch": false, "packageRules": [ - { - "description": "Default: separate PRs per package", - "groupName": "{{packageFileDir}}/{{depName}}", - "matchPackageNames": [ - "*" - ] - }, - { - "description": "🚫 Production environments - disable automerge", - "matchFileNames": [ - "**/production/**" - ], - "automerge": false, - "prPriority": -1, - "addLabels": [ - "⚠️ production" - ] - }, - { - "description": "🚫 Major updates - disable automerge", - "matchUpdateTypes": [ - "major" - ], - "automerge": false, - "addLabels": [ - "📈 major-update" - ] - }, - { - "description": "✅ Minor/Patch updates - enable automerge", - "matchUpdateTypes": [ - "minor", - "patch", - "pin", - "digest" - ], - "automerge": true - }, { "description": "Track OpenTofu releases instead of Terraform for required_version", "matchDepTypes": [ diff --git a/.github/scripts/kubernetes-hydrate/hydrate-component.sh b/.github/scripts/kubernetes-hydrate/hydrate-component.sh deleted file mode 100755 index 13034217..00000000 --- a/.github/scripts/kubernetes-hydrate/hydrate-component.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -component="${1:?component name required}" -env="${2:?environment name required}" - -cd "$(git rev-parse --show-toplevel)" - -component_dir="kubernetes/components/${component}/${env}" -out_dir="kubernetes/manifests/${env}/${component}" - -# Explicit --kube-version prevents template divergence caused by varying default helm binary versions. -env_hcl="aws/eks/${env}/env.hcl" -if [ ! -f "${env_hcl}" ]; then - echo "hydrate-component.sh: ${env_hcl} not found; cannot determine cluster version" >&2 - exit 1 -fi -kube_version=$(sed -n 's/^[[:space:]]*cluster_version[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' "${env_hcl}") -if [ -z "${kube_version}" ]; then - echo "hydrate-component.sh: cluster_version not set in ${env_hcl}" >&2 - exit 1 -fi - -mkdir -p "${out_dir}" -: > "${out_dir}/manifest.yaml" - -if [ -f "${component_dir}/helmfile.yaml" ]; then - helmfile -f "${component_dir}/helmfile.yaml" -e "${env}" template \ - --include-crds --skip-tests --kube-version "${kube_version}" >> "${out_dir}/manifest.yaml" -fi - -if [ -d "${component_dir}/kustomization" ]; then - echo "---" >> "${out_dir}/manifest.yaml" - kustomize build "${component_dir}/kustomization" >> "${out_dir}/manifest.yaml" -fi - -printf "resources:\n - manifest.yaml\n" > "${out_dir}/kustomization.yaml" - -if git ls-files --error-unmatch "${out_dir}/manifest.yaml" >/dev/null 2>&1; then - if git diff --quiet -I '^[[:space:]]*(ca\.crt|ca\.key|tls\.crt|tls\.key|caBundle):' -- "${out_dir}/manifest.yaml"; then - git checkout -- "${out_dir}/manifest.yaml" - fi -fi diff --git a/.github/scripts/kubernetes-hydrate/hydrate-index.sh b/.github/scripts/kubernetes-hydrate/hydrate-index.sh deleted file mode 100755 index 291dbd42..00000000 --- a/.github/scripts/kubernetes-hydrate/hydrate-index.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -env="${1:?environment name required}" - -cd "$(git rev-parse --show-toplevel)" - -env_dir="kubernetes/manifests/${env}" - -mkdir -p "${env_dir}/00-namespaces" -: > "${env_dir}/00-namespaces/namespaces.yaml" - -for comp_dir in kubernetes/components/*/"${env}"/; do - [ -d "${comp_dir}" ] || continue - comp_name=$(basename "$(dirname "${comp_dir}")") - if [ -f "kubernetes/components/${comp_name}/${env}/namespace.yaml" ]; then - echo "---" >> "${env_dir}/00-namespaces/namespaces.yaml" - cat "kubernetes/components/${comp_name}/${env}/namespace.yaml" >> "${env_dir}/00-namespaces/namespaces.yaml" - elif [ -f "kubernetes/components/${comp_name}/namespace.yaml" ]; then - echo "---" >> "${env_dir}/00-namespaces/namespaces.yaml" - cat "kubernetes/components/${comp_name}/namespace.yaml" >> "${env_dir}/00-namespaces/namespaces.yaml" - fi -done - -printf "resources:\n - namespaces.yaml\n" > "${env_dir}/00-namespaces/kustomization.yaml" - -for dir in "${env_dir}"/*/; do - [ -d "${dir}" ] || continue - name=$(basename "${dir}") - if [ "${name}" = "00-namespaces" ]; then - continue - fi - if [ ! -d "kubernetes/components/${name}/${env}" ]; then - rm -rf "${dir}" - fi -done - -{ - echo "resources:" - echo " - ./00-namespaces" - # Sort by full path in C locale so prefix pairs like opentelemetry-collector precede opentelemetry. - for dir in "${env_dir}"/*/; do - [ -d "${dir}" ] || continue - name=$(basename "${dir}") - [ "${name}" = "00-namespaces" ] && continue - printf '%s\n' "${dir}" - done | LC_ALL=C sort | while IFS= read -r dir; do - echo " - ./$(basename "${dir}")" - done -} > "${env_dir}/kustomization.yaml" diff --git a/.github/scripts/kubernetes-hydrate/render-diff.sh b/.github/scripts/kubernetes-hydrate/render-diff.sh deleted file mode 100755 index 1446774f..00000000 --- a/.github/scripts/kubernetes-hydrate/render-diff.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -base_ref="${1:?base revision required}" -out_dir="${2:?output directory required}" - -cd "$(git rev-parse --show-toplevel)" -script_dir="$(pwd)/.github/scripts/kubernetes-hydrate" -mkdir -p "${out_dir}" -out_dir="$(cd "${out_dir}" && pwd)" -summary="${out_dir}/summary.md" - -components="$(git diff --name-only --no-renames "${base_ref}" HEAD -- kubernetes/components/ | awk -F/ 'NF >= 5 { print $3 "/" $4 }' | sort -u)" -if [ -z "${components}" ]; then - echo "No Kubernetes components changed." > "${summary}" - exit 0 -fi - -work="$(mktemp -d)" -cleanup() { - git worktree remove --force "${work}/base" 2>/dev/null || true # SILENT: the worktree may not exist when setup failed - git worktree remove --force "${work}/head" 2>/dev/null || true # SILENT: the worktree may not exist when setup failed - rm -rf "${work}" -} -trap cleanup EXIT -# Separate worktrees keep hydrate-component.sh from rewriting kubernetes/manifests in this checkout. -git worktree add -q --detach "${work}/base" "${base_ref}" -git worktree add -q --detach "${work}/head" HEAD - -render() { - local side="$1" svc="$2" env="$3" dir="$4" - (cd "${work}/${side}" && bash "${script_dir}/hydrate-component.sh" "${svc}" "${env}") > "${dir}/${side}.log" 2>&1 && - cp "${work}/${side}/kubernetes/manifests/${env}/${svc}/manifest.yaml" "${dir}/${side}.yaml" -} - -: > "${summary}" -for component in ${components}; do - svc="${component%/*}" - env="${component#*/}" - dir="${out_dir}/${env}/${svc}" - { - echo "## ${svc} (${env})" - echo - if [ ! -f "aws/eks/${env}/env.hcl" ]; then - echo "Not rendered: \`${env}\` has no \`aws/eks/${env}/env.hcl\`, so the hydrator never deploys it." - echo - continue - fi - mkdir -p "${dir}" - failed="" - render base "${svc}" "${env}" "${dir}" || failed="base" - render head "${svc}" "${env}" "${dir}" || failed="${failed:+${failed} }head" - if [ -n "${failed}" ]; then - echo "Rendering failed (${failed}):" - echo - echo '```' - for side in ${failed}; do - tail -n 20 "${dir}/${side}.log" - done - echo '```' - else - diff -u "${dir}/base.yaml" "${dir}/head.yaml" > "${dir}/manifest.diff" || true # SILENT: diff exits 1 when the manifests differ - echo "Full diff: \`${env}/${svc}/manifest.diff\`" - echo - if bash "${script_dir}/summarize-manifest-diff.sh" "${dir}/base.yaml" "${dir}/head.yaml" > "${dir}/summary.part" 2> "${dir}/summarize.log"; then - cat "${dir}/summary.part" - else - echo "Summarizing failed; use the full diff:" - echo - echo '```' - tail -n 20 "${dir}/summarize.log" - echo '```' - fi - fi - echo - } >> "${summary}" -done diff --git a/.github/scripts/kubernetes-hydrate/summarize-manifest-diff.sh b/.github/scripts/kubernetes-hydrate/summarize-manifest-diff.sh deleted file mode 100755 index c3f23faa..00000000 --- a/.github/scripts/kubernetes-hydrate/summarize-manifest-diff.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -base="${1:?base manifest required}" -head="${2:?head manifest required}" - -export LC_ALL=C - -image_refs() { - { - yq -N '.. | select(tag == "!!map" and has("image")) | .image | select(tag == "!!str")' "$1" - yq -N '.. | select(tag == "!!str") | select(test("^(--[A-Za-z0-9-]+=)?[a-z0-9.-]+(:[0-9]+)?/[a-z0-9./_-]+:[A-Za-z0-9._-]+(@sha256:[a-f0-9]+)?$")) | sub("^--[A-Za-z0-9-]+=", "")' "$1" - } | sort -u -} - -split_image_refs() { - awk -v side="$1" '{ - ref = $0; digest = ""; tag = ""; repo = ref - at = index(ref, "@") - if (at > 0) { digest = substr(ref, at); ref = substr(ref, 1, at - 1); repo = ref } - n = split(ref, parts, "/"); last = parts[n] - colon = index(last, ":") - if (colon > 0) { tag = substr(last, colon + 1); repo = substr(ref, 1, length(ref) - length(last) + colon - 1) } - tag = tag digest - if (tag == "") tag = "(untagged)" - print repo "\t" side "\t" tag - }' -} - -crd_versions() { - yq -N 'select(.kind == "CustomResourceDefinition") | .metadata.name + "\t" + ([.spec.versions[] | .name + (if .served == false then " (not served)" else "" end) + (if .storage then "*" else "" end)] | join(", "))' "$1" | sort -u -} - -resources() { - yq -N 'select(.kind != null) | .kind + " " + (if .metadata.namespace then .metadata.namespace + "/" else "" end) + .metadata.name' "$1" | sort -u -} - -pair_rows() { - awk -F '\t' '{ - key[$1] = 1 - if ($2 == "base") base[$1] = (base[$1] == "" ? $3 : base[$1] ", " $3) - else head[$1] = (head[$1] == "" ? $3 : head[$1] ", " $3) - } - END { - for (k in key) if (base[k] != head[k]) print k "\t" (base[k] == "" ? "-" : base[k]) "\t" (head[k] == "" ? "-" : head[k]) - }' | sort -} - -print_table() { - local header="$1" rows="$2" - if [ -z "${rows}" ]; then - echo "No changes." - return - fi - echo "| ${header} | Base | Head |" - echo "|---|---|---|" - printf '%s\n' "${rows}" | awk -F '\t' '{ print "| " $1 " | " $2 " | " $3 " |" }' -} - -tmp="$(mktemp -d)" -trap 'rm -rf "${tmp}"' EXIT -# Extracting into files first lets set -e catch yq failures that command substitutions and process substitutions would hide. -for side in base head; do - if [ "${side}" = base ]; then manifest="${base}"; else manifest="${head}"; fi - image_refs "${manifest}" | split_image_refs "${side}" > "${tmp}/${side}.images" - crd_versions "${manifest}" | awk -F '\t' -v side="${side}" '{ print $1 "\t" side "\t" $2 }' > "${tmp}/${side}.crds" - resources "${manifest}" > "${tmp}/${side}.resources" -done - -image_rows="$(cat "${tmp}/base.images" "${tmp}/head.images" | pair_rows)" -crd_rows="$(cat "${tmp}/base.crds" "${tmp}/head.crds" | pair_rows)" -added="$(comm -13 "${tmp}/base.resources" "${tmp}/head.resources")" -removed="$(comm -23 "${tmp}/base.resources" "${tmp}/head.resources")" - -echo "### Images" -echo -if [ -n "${image_rows}" ]; then - echo 'Collected from `image` fields and from other string values shaped like `registry/repository:tag` (args, env).' - echo -fi -print_table "Repository" "${image_rows}" -echo -echo "### CustomResourceDefinitions" -echo -if [ -n "${crd_rows}" ]; then - echo '`*` marks the storage version.' - echo -fi -print_table "Name" "${crd_rows}" -echo -echo "### Resources" -echo -if [ -z "${added}" ] && [ -z "${removed}" ]; then - echo "No changes." -fi -if [ -n "${added}" ]; then - echo "Added:" - printf '%s\n' "${added}" | sed 's/^/- /' -fi -if [ -n "${added}" ] && [ -n "${removed}" ]; then - echo -fi -if [ -n "${removed}" ]; then - echo "Removed:" - printf '%s\n' "${removed}" | sed 's/^/- /' -fi diff --git a/.github/scripts/kubernetes-hydrate/tests/fixtures/identical/expected.md b/.github/scripts/kubernetes-hydrate/tests/fixtures/identical/expected.md deleted file mode 100644 index 73262562..00000000 --- a/.github/scripts/kubernetes-hydrate/tests/fixtures/identical/expected.md +++ /dev/null @@ -1,11 +0,0 @@ -### Images - -No changes. - -### CustomResourceDefinitions - -No changes. - -### Resources - -No changes. diff --git a/.github/scripts/kubernetes-hydrate/tests/fixtures/identical/manifest.yaml b/.github/scripts/kubernetes-hydrate/tests/fixtures/identical/manifest.yaml deleted file mode 100644 index c05d945e..00000000 --- a/.github/scripts/kubernetes-hydrate/tests/fixtures/identical/manifest.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: same diff --git a/.github/scripts/kubernetes-hydrate/tests/fixtures/invalid/manifest.yaml b/.github/scripts/kubernetes-hydrate/tests/fixtures/invalid/manifest.yaml deleted file mode 100644 index c2b6f361..00000000 --- a/.github/scripts/kubernetes-hydrate/tests/fixtures/invalid/manifest.yaml +++ /dev/null @@ -1,2 +0,0 @@ -kind: ConfigMap -metadata: [ diff --git a/.github/scripts/kubernetes-hydrate/tests/fixtures/summarize/base.yaml b/.github/scripts/kubernetes-hydrate/tests/fixtures/summarize/base.yaml deleted file mode 100644 index 69182fe2..00000000 --- a/.github/scripts/kubernetes-hydrate/tests/fixtures/summarize/base.yaml +++ /dev/null @@ -1,62 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: widgets.example.com -spec: - versions: - - name: v1alpha1 - served: true - storage: true ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: gadgets.example.com -spec: - versions: - - name: v1 - served: true - storage: true ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: app - namespace: ns-a -spec: - template: - spec: - initContainers: - - name: init - image: busybox:1.36 - containers: - - name: app - image: registry.example.com/app:1.0 - args: - - --config-reloader=quay.io/example/reloader:v0.93.1 - - --log-level=info - env: - - name: HELPER_IMAGE - value: ghcr.io/example/helper:2.0 - - name: ENDPOINT - value: http://example.com/path:8080 ---- -apiVersion: monitoring.coreos.com/v1 -kind: Prometheus -metadata: - name: main - namespace: ns-a -spec: - image: quay.io/prometheus/prometheus:v3.14.0 - version: v3.14.0 ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: old - namespace: ns-a ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: reader diff --git a/.github/scripts/kubernetes-hydrate/tests/fixtures/summarize/expected.md b/.github/scripts/kubernetes-hydrate/tests/fixtures/summarize/expected.md deleted file mode 100644 index d46e01ca..00000000 --- a/.github/scripts/kubernetes-hydrate/tests/fixtures/summarize/expected.md +++ /dev/null @@ -1,29 +0,0 @@ -### Images - -Collected from `image` fields and from other string values shaped like `registry/repository:tag` (args, env). - -| Repository | Base | Head | -|---|---|---| -| localhost:5000/sidecar | - | 0.1@sha256:abc | -| nginx | - | (untagged) | -| quay.io/example/reloader | v0.93.1 | v0.94.1 | -| quay.io/prometheus/prometheus | v3.14.0 | v3.15.0 | -| registry.example.com/app | 1.0 | 2.0 | - -### CustomResourceDefinitions - -`*` marks the storage version. - -| Name | Base | Head | -|---|---|---| -| gadgets.example.com | v1* | - | -| widgets.example.com | v1alpha1* | v1alpha1 (not served), v1* | - -### Resources - -Added: -- ConfigMap ns-a/new - -Removed: -- ConfigMap ns-a/old -- CustomResourceDefinition gadgets.example.com diff --git a/.github/scripts/kubernetes-hydrate/tests/fixtures/summarize/head.yaml b/.github/scripts/kubernetes-hydrate/tests/fixtures/summarize/head.yaml deleted file mode 100644 index 07a34d59..00000000 --- a/.github/scripts/kubernetes-hydrate/tests/fixtures/summarize/head.yaml +++ /dev/null @@ -1,63 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: widgets.example.com -spec: - versions: - - name: v1alpha1 - served: false - storage: false - - name: v1 - served: true - storage: true ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: app - namespace: ns-a -spec: - template: - spec: - initContainers: - - name: init - image: busybox:1.36 - containers: - - name: app - image: registry.example.com/app:2.0 - args: - - --config-reloader=quay.io/example/reloader:v0.94.1 - - --log-level=info - env: - - name: HELPER_IMAGE - value: ghcr.io/example/helper:2.0 - - name: ENDPOINT - value: http://example.com/path:8080 - - name: sidecar - image: localhost:5000/sidecar:0.1@sha256:abc - - name: untagged - image: nginx ---- ---- -apiVersion: monitoring.coreos.com/v1 -kind: Prometheus -metadata: - name: main - namespace: ns-a -spec: - image: quay.io/prometheus/prometheus:v3.15.0 - version: v3.15.0 - thanos: - image: - repository: quay.io/thanos/thanos ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: new - namespace: ns-a ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: reader diff --git a/.github/scripts/kubernetes-hydrate/tests/render-diff.test.sh b/.github/scripts/kubernetes-hydrate/tests/render-diff.test.sh deleted file mode 100755 index 04a9650e..00000000 --- a/.github/scripts/kubernetes-hydrate/tests/render-diff.test.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -here="$(cd "$(dirname "$0")" && pwd)" -scripts="${here}/.." -work="$(mktemp -d)" -trap 'rm -rf "${work}"' EXIT -failures=0 - -pass() { echo "ok - $1"; } -fail() { echo "not ok - $1"; failures=$((failures + 1)); } -expect_contains() { if grep -qF -- "$2" "$3"; then pass "$1"; else fail "$1"; sed 's/^/# /' "$3"; fi; } -expect_absent() { if grep -qF -- "$2" "$3"; then fail "$1"; sed 's/^/# /' "$3"; else pass "$1"; fi; } - -write_deployment() { - local dir="$1" name="$2" image="$3" - mkdir -p "${dir}/kustomization" - printf 'resources:\n - deployment.yaml\n' > "${dir}/kustomization/kustomization.yaml" - cat > "${dir}/kustomization/deployment.yaml" < "${repo}/aws/eks/production/env.hcl" -write_deployment "${repo}/kubernetes/components/demo/production" demo nginx:1.0 -write_deployment "${repo}/kubernetes/components/gone/production" gone busybox:1.36 -write_deployment "${repo}/kubernetes/components/untouched/production" untouched redis:7 -touch "${repo}/kubernetes/components/demo/namespace.yaml" -git -C "${repo}" init -q -b main -git -C "${repo}" -c user.name=test -c user.email=test@example.com add -A -git -C "${repo}" -c user.name=test -c user.email=test@example.com commit -q -m base - -write_deployment "${repo}/kubernetes/components/demo/production" demo nginx:1.1 -echo "# changed" >> "${repo}/kubernetes/components/demo/namespace.yaml" -git -C "${repo}" rm -q -r kubernetes/components/gone -write_deployment "${repo}/kubernetes/components/pending-only/pending" pending-only busybox:1.36 -write_deployment "${repo}/kubernetes/components/broken/production" broken busybox:1.36 -printf 'resources:\n - missing.yaml\n' > "${repo}/kubernetes/components/broken/production/kustomization/kustomization.yaml" -git -C "${repo}" -c user.name=test -c user.email=test@example.com add -A -git -C "${repo}" -c user.name=test -c user.email=test@example.com commit -q -m head - -out="${work}/out" -(cd "${repo}" && bash .github/scripts/kubernetes-hydrate/render-diff.sh HEAD^ "${out}") > "${work}/stdout" 2>&1 || { fail "render-diff exits 0"; sed 's/^/# /' "${work}/stdout"; } -summary="${out}/summary.md" - -expect_contains "lists a changed component" "## demo (production)" "${summary}" -expect_contains "reports the changed image" "| nginx | 1.0 | 1.1 |" "${summary}" -expect_contains "links the full diff" "production/demo/manifest.diff" "${summary}" -expect_contains "writes the full diff" "+ - image: nginx:1.1" "${out}/production/demo/manifest.diff" -expect_contains "lists a deleted component" "## gone (production)" "${summary}" -expect_contains "reports resources of a deleted component as removed" "- Deployment gone" "${summary}" -expect_contains "reports a render failure instead of aborting" "Rendering failed (head)" "${summary}" -expect_contains "skips directories that are not hydrated environments" "Not rendered:" "${summary}" -if [ -d "${out}/pending" ]; then fail "does not render directories that are not hydrated environments"; else pass "does not render directories that are not hydrated environments"; fi -expect_absent "skips components without changes" "untouched" "${summary}" -if [ -z "$(git -C "${repo}" status --porcelain)" ] && [ "$(git -C "${repo}" worktree list | wc -l)" -eq 1 ]; then - pass "leaves the checkout and worktree list clean" -else - fail "leaves the checkout and worktree list clean" - git -C "${repo}" status --porcelain | sed 's/^/# /' -fi - -failing_bin="${work}/failing-bin" -mkdir -p "${failing_bin}" -printf '#!/bin/sh\nexit 1\n' > "${failing_bin}/yq" -chmod +x "${failing_bin}/yq" -(cd "${repo}" && PATH="${failing_bin}:${PATH}" bash .github/scripts/kubernetes-hydrate/render-diff.sh HEAD^ "${work}/out-failing") > /dev/null 2>&1 || fail "render-diff exits 0 when summarizing fails" -expect_contains "reports a summarizing failure instead of aborting" "Summarizing failed" "${work}/out-failing/summary.md" - -echo "# changed" >> "${repo}/README.md" -git -C "${repo}" -c user.name=test -c user.email=test@example.com add -A -git -C "${repo}" -c user.name=test -c user.email=test@example.com commit -q -m docs -(cd "${repo}" && bash .github/scripts/kubernetes-hydrate/render-diff.sh HEAD^ "${work}/out-none") > /dev/null 2>&1 || fail "render-diff exits 0 without components" -expect_contains "reports when no component changed" "No Kubernetes components changed." "${work}/out-none/summary.md" - -exit "${failures}" diff --git a/.github/scripts/kubernetes-hydrate/tests/summarize-manifest-diff.test.sh b/.github/scripts/kubernetes-hydrate/tests/summarize-manifest-diff.test.sh deleted file mode 100755 index 1d7d7c0e..00000000 --- a/.github/scripts/kubernetes-hydrate/tests/summarize-manifest-diff.test.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -here="$(cd "$(dirname "$0")" && pwd)" -summarize="${here}/../summarize-manifest-diff.sh" -fixtures="${here}/fixtures" -failures=0 - -check() { - local name="$1" base="$2" head="$3" expected="$4" actual - if actual="$(bash "${summarize}" "${base}" "${head}" 2>&1)" && diff -u "${expected}" <(printf '%s\n' "${actual}"); then - echo "ok - ${name}" - else - echo "not ok - ${name}" - printf '%s\n' "${actual}" | sed 's/^/# /' - failures=$((failures + 1)) - fi -} - -check "reports image, CRD and resource changes" \ - "${fixtures}/summarize/base.yaml" "${fixtures}/summarize/head.yaml" "${fixtures}/summarize/expected.md" -check "reports no changes for identical manifests" \ - "${fixtures}/identical/manifest.yaml" "${fixtures}/identical/manifest.yaml" "${fixtures}/identical/expected.md" - -for side in base head; do - if [ "${side}" = base ]; then args=("${fixtures}/invalid/manifest.yaml" "${fixtures}/identical/manifest.yaml"); else args=("${fixtures}/identical/manifest.yaml" "${fixtures}/invalid/manifest.yaml"); fi - if bash "${summarize}" "${args[@]}" > /dev/null 2>&1; then - echo "not ok - fails on an unparsable ${side} manifest" - failures=$((failures + 1)) - else - echo "ok - fails on an unparsable ${side} manifest" - fi -done - -exit "${failures}" diff --git a/.github/scripts/terragrunt-release/check-release-configs.sh b/.github/scripts/terragrunt-release/check-release-configs.sh deleted file mode 100755 index 0d669b6e..00000000 --- a/.github/scripts/terragrunt-release/check-release-configs.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -config_path="${1:-workflow-config.yaml}" - -# release-targets.sh stderr is hidden below, so an unreadable config would otherwise look like "no release services" -yq '.' "${config_path}" >/dev/null - -merge_environments="$(yq -o=json '.' "${config_path}" | jq -c ' - [.stacks[] | select(.name == "terragrunt") | .environments | to_entries[] | select(.value.apply_trigger == "merge") | .key] -')" - -failed=0 - -report() { - echo "::error::$*" >&2 - failed=1 -} - -shopt -s nullglob -for service_dir in aws/*/; do - service="$(basename "${service_dir}")" - package="aws/${service}" - config_file="${package}/release-please-config.json" - manifest_file="${package}/release-please-manifest.json" - - if ! targets="$(bash "${script_dir}/release-targets.sh" "${service}" "${config_path}" 2>/dev/null)"; then - if [ -f "${config_file}" ]; then - report "${config_file} exists but ${service} has no release environment" - fi - continue - fi - - incomplete="$(jq -r ' - .[] | . as $target - | ("aws_region", "iam_role_plan", "iam_role_apply") as $field - | select(($target[$field] // "") == "") - | "::error::release target \($target.service)/\($target.environment) has no \($field)" - ' <<<"${targets}")" - if [ -n "${incomplete}" ]; then - echo "${incomplete}" >&2 - failed=1 - fi - - if [ ! -f "${config_file}" ]; then - report "${config_file} is missing but ${service} has a release environment" - continue - fi - - component="$(jq -r --arg package "${package}" '.packages[$package].component // ""' "${config_file}")" - if [ "${component}" != "${service}" ]; then - report "${package}: component must be ${service} (got '${component}')" - fi - - expected_exclude_paths="$(jq -c --arg package "${package}" 'map("\($package)/\(.)")' <<<"${merge_environments}")" - actual_exclude_paths="$(jq -c --arg package "${package}" '.packages[$package]["exclude-paths"]' "${config_file}")" - if ! jq -ne --argjson expected "${expected_exclude_paths}" --argjson actual "${actual_exclude_paths}" ' - ($actual | type) == "array" and ($actual | sort) == ($expected | sort) - ' >/dev/null; then - report "${package}: exclude-paths must be ${expected_exclude_paths} (got ${actual_exclude_paths})" - fi - - if [ ! -f "${manifest_file}" ] || ! jq -e --arg package "${package}" 'has($package)' "${manifest_file}" >/dev/null; then - report "${manifest_file} must have the key ${package}" - fi -done - -exit "${failed}" diff --git a/.github/scripts/terragrunt-release/release-service.sh b/.github/scripts/terragrunt-release/release-service.sh deleted file mode 100755 index 27ebbb99..00000000 --- a/.github/scripts/terragrunt-release/release-service.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -mode="${1:-}" -value="${2:-}" - -case "${mode}" in - --tag) - pattern='^([a-z0-9-]+)-v[0-9]+\.[0-9]+\.[0-9]+$' - expected='-vX.Y.Z' - ;; - --branch) - pattern='^release-please--branches--main--components--([a-z0-9-]+)$' - expected='release-please--branches--main--components--' - ;; - *) - echo "::error::usage: release-service.sh --tag | --branch " >&2 - exit 1 - ;; -esac - -if [[ ! "${value}" =~ ${pattern} ]]; then - shown="${value//$'\n'/ }" - shown="${shown//$'\r'/ }" - echo "::error::'${shown}' does not match ${expected}" >&2 - exit 1 -fi - -echo "${BASH_REMATCH[1]}" diff --git a/.github/scripts/terragrunt-release/release-targets.sh b/.github/scripts/terragrunt-release/release-targets.sh deleted file mode 100755 index 8cc1aa50..00000000 --- a/.github/scripts/terragrunt-release/release-targets.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -service="${1:?usage: release-targets.sh [config_path]}" -config_path="${2:-workflow-config.yaml}" - -candidates="$(yq -o=json '.' "${config_path}" | jq -c --arg service "${service}" ' - .stacks[] - | select(.name == "terragrunt") - | (.exclude // []) as $exclude - | .environments | to_entries[] - | select(.value.apply_trigger == "release") - | {service: $service, environment: .key} as $values - | { - service: $service, - environment: .key, - working_directory: "aws/\($service)/\(.key)", - aws_region: .value.aws_region, - iam_role_plan: .value.iam_role_plan, - iam_role_apply: .value.iam_role_apply, - excluded: any($exclude[]; to_entries | all(.[]; . as $pair | $values | has($pair.key) and .[$pair.key] == $pair.value)) - } -')" - -targets="$( - while IFS= read -r candidate; do - [ -n "${candidate}" ] || continue - if [ -d "$(jq -r '.working_directory' <<<"${candidate}")" ]; then - echo "${candidate}" - fi - done <<<"${candidates}" | jq -c -s '.' -)" - -if [ "$(jq 'length' <<<"${targets}")" -eq 0 ]; then - echo "::error::no release targets for ${service}" >&2 - exit 1 -fi - -jq -c 'map(select(.excluded | not) | del(.excluded))' <<<"${targets}" diff --git a/.github/scripts/terragrunt-release/test.sh b/.github/scripts/terragrunt-release/test.sh deleted file mode 100755 index 59bb7f4e..00000000 --- a/.github/scripts/terragrunt-release/test.sh +++ /dev/null @@ -1,374 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -repo_root="$(git -C "${script_dir}" rev-parse --show-toplevel)" -work_root="$(mktemp -d)" -trap 'rm -rf "${work_root}"' EXIT - -last_stderr="" - -assert_eq() { - local expected="$1" actual="$2" - if [ "${expected}" != "${actual}" ]; then - echo " expected: ${expected}" >&2 - echo " actual: ${actual}" >&2 - exit 1 - fi -} - -assert_fails() { - local stderr_file="${work_root}/stderr" - if "$@" 2>"${stderr_file}"; then - echo " expected a non-zero exit: $*" >&2 - exit 1 - fi - last_stderr="$(cat "${stderr_file}")" -} - -assert_stderr_contains() { - local needle="$1" - if [[ "${last_stderr}" != *"${needle}"* ]]; then - echo " stderr does not contain: ${needle}" >&2 - echo " stderr: ${last_stderr}" >&2 - exit 1 - fi -} - -test_validate_accepts_merge_and_release() { - cat > workflow-config.yaml <<'YAML' -stacks: - - name: terragrunt - environments: - master: - apply_trigger: merge - production: - apply_trigger: release -YAML - bash "${script_dir}/validate-apply-trigger.sh" -} - -test_validate_rejects_missing_trigger() { - cat > workflow-config.yaml <<'YAML' -stacks: - - name: terragrunt - environments: - master: - apply_trigger: merge - production: - aws_region: ap-northeast-1 -YAML - assert_fails bash "${script_dir}/validate-apply-trigger.sh" - assert_stderr_contains "environments.production.apply_trigger" -} - -test_validate_rejects_unknown_value() { - cat > workflow-config.yaml <<'YAML' -stacks: - - name: terragrunt - environments: - production: - apply_trigger: relase -YAML - assert_fails bash "${script_dir}/validate-apply-trigger.sh" - assert_stderr_contains "(got 'relase')" -} - -test_validate_ignores_non_terragrunt_stacks() { - cat > workflow-config.yaml <<'YAML' -stacks: - - name: terragrunt - environments: - master: - apply_trigger: merge - - name: kubernetes - paths: - - "kubernetes/components/{service}/{environment}" -YAML - bash "${script_dir}/validate-apply-trigger.sh" -} - -test_repository_config_is_valid() { - bash "${script_dir}/validate-apply-trigger.sh" "${repo_root}/workflow-config.yaml" -} - -test_repository_config_never_merges_production() { - local trigger - trigger="$(yq '.stacks[] | select(.name == "terragrunt") | .environments.production.apply_trigger' "${repo_root}/workflow-config.yaml")" - assert_eq "release" "${trigger}" -} - -test_release_service_parses_tag() { - assert_eq "eks-holmesgpt" "$(bash "${script_dir}/release-service.sh" --tag eks-holmesgpt-v1.2.3)" -} - -test_release_service_rejects_root_tag() { - assert_fails bash "${script_dir}/release-service.sh" --tag v0.1.0 - assert_stderr_contains "::error::" -} - -test_release_service_rejects_flux_tag() { - assert_fails bash "${script_dir}/release-service.sh" --tag kubernetes-production - assert_stderr_contains "::error::" -} - -test_release_service_parses_branch() { - assert_eq "vpc" "$(bash "${script_dir}/release-service.sh" --branch release-please--branches--main--components--vpc)" -} - -test_release_service_rejects_root_branch() { - assert_fails bash "${script_dir}/release-service.sh" --branch release-please--branches--main - assert_stderr_contains "::error::" -} - -test_release_service_error_is_single_line() { - assert_fails bash "${script_dir}/release-service.sh" --tag $'vpc-v1.2.3\n::warning::x' - assert_stderr_contains "::error::" - assert_eq "1" "$(printf '%s\n' "${last_stderr}" | wc -l | tr -d ' ')" -} - -write_release_config() { - local exclude="${1:-}" - cat > workflow-config.yaml <<'YAML' -stacks: - - name: terragrunt-shared - attributes: {} - - name: terragrunt - environments: - master: - aws_region: ap-northeast-1 - iam_role_plan: arn:aws:iam::111111111111:role/master-plan - iam_role_apply: arn:aws:iam::111111111111:role/master-apply - apply_trigger: merge - production: - aws_region: ap-northeast-1 - iam_role_plan: arn:aws:iam::222222222222:role/production-plan - iam_role_apply: arn:aws:iam::222222222222:role/production-apply - apply_trigger: release - staging: - aws_region: us-east-1 - iam_role_plan: arn:aws:iam::333333333333:role/staging-plan - iam_role_apply: arn:aws:iam::333333333333:role/staging-apply - apply_trigger: release - - name: kubernetes - paths: - - "kubernetes/components/{service}/{environment}" -YAML - if [ -n "${exclude}" ]; then - EXCLUDE="${exclude}" yq -i '(.stacks[] | select(.name == "terragrunt") | .exclude) = env(EXCLUDE)' workflow-config.yaml - fi -} - -test_release_targets_lists_release_envs() { - write_release_config - mkdir -p aws/vpc/master aws/vpc/production - local expected='[{"service":"vpc","environment":"production","working_directory":"aws/vpc/production","aws_region":"ap-northeast-1","iam_role_plan":"arn:aws:iam::222222222222:role/production-plan","iam_role_apply":"arn:aws:iam::222222222222:role/production-apply"}]' - assert_eq "${expected}" "$(bash "${script_dir}/release-targets.sh" vpc)" -} - -test_release_targets_skips_missing_dirs() { - write_release_config - mkdir -p aws/vpc/production - local targets - targets="$(bash "${script_dir}/release-targets.sh" vpc)" - assert_eq "1" "$(jq 'length' <<<"${targets}")" - assert_eq "production" "$(jq -r '.[0].environment' <<<"${targets}")" -} - -test_release_targets_fails_without_targets() { - write_release_config - mkdir -p aws/route53/master - assert_fails bash "${script_dir}/release-targets.sh" route53 - assert_stderr_contains "no release targets for route53" -} - -test_release_targets_skips_excluded_envs() { - write_release_config '[{environment: production}]' - mkdir -p aws/vpc/production aws/vpc/staging - local targets - targets="$(bash "${script_dir}/release-targets.sh" vpc)" - assert_eq "1" "$(jq 'length' <<<"${targets}")" - assert_eq "staging" "$(jq -r '.[0].environment' <<<"${targets}")" -} - -test_release_targets_returns_empty_when_all_excluded() { - write_release_config '[{environment: production}, {environment: staging}]' - mkdir -p aws/vpc/production - assert_eq "[]" "$(bash "${script_dir}/release-targets.sh" vpc)" -} - -test_release_targets_honors_service_scoped_exclude() { - write_release_config '[{service: vpc, environment: production}]' - mkdir -p aws/vpc/production aws/eks/production - assert_eq "[]" "$(bash "${script_dir}/release-targets.sh" vpc)" - local targets - targets="$(bash "${script_dir}/release-targets.sh" eks)" - assert_eq "1" "$(jq 'length' <<<"${targets}")" - assert_eq "production" "$(jq -r '.[0].environment' <<<"${targets}")" -} - -test_release_targets_fails_without_dirs_even_with_exclude() { - write_release_config '[{environment: production}]' - mkdir -p aws/route53/master - assert_fails bash "${script_dir}/release-targets.sh" route53 - assert_stderr_contains "no release targets for route53" -} - -write_service_release_config() { - local service="$1" component="${2:-$1}" exclude_paths="${3:-[\"aws/$1/master\"]}" - mkdir -p "aws/${service}" - cat > "aws/${service}/release-please-config.json" < "aws/${service}/release-please-manifest.json" -} - -test_check_configs_accepts_matching_set() { - write_release_config - mkdir -p aws/vpc/production aws/route53/master - write_service_release_config vpc - assert_eq "" "$(bash "${script_dir}/check-release-configs.sh" 2>&1)" -} - -test_check_configs_rejects_missing_config() { - write_release_config - mkdir -p aws/eks/production - assert_fails bash "${script_dir}/check-release-configs.sh" - assert_stderr_contains "aws/eks/release-please-config.json" -} - -test_check_configs_requires_config_for_excluded_env() { - write_release_config '[{environment: production}]' - mkdir -p aws/eks/production - assert_fails bash "${script_dir}/check-release-configs.sh" - assert_stderr_contains "aws/eks/release-please-config.json" - write_service_release_config eks - assert_eq "" "$(bash "${script_dir}/check-release-configs.sh" 2>&1)" -} - -test_check_configs_rejects_orphan_config() { - write_release_config - mkdir -p aws/route53/master - write_service_release_config route53 - assert_fails bash "${script_dir}/check-release-configs.sh" - assert_stderr_contains "aws/route53/release-please-config.json" -} - -test_check_configs_rejects_wrong_component() { - write_release_config - mkdir -p aws/vpc/production - write_service_release_config vpc eks - assert_fails bash "${script_dir}/check-release-configs.sh" - assert_stderr_contains "aws/vpc: component must be vpc (got 'eks')" -} - -test_check_configs_rejects_manifest_without_package() { - write_release_config - mkdir -p aws/vpc/production - write_service_release_config vpc - echo '{}' > aws/vpc/release-please-manifest.json - assert_fails bash "${script_dir}/check-release-configs.sh" - assert_stderr_contains "aws/vpc/release-please-manifest.json" - rm aws/vpc/release-please-manifest.json - assert_fails bash "${script_dir}/check-release-configs.sh" - assert_stderr_contains "aws/vpc/release-please-manifest.json" -} - -test_check_configs_rejects_incomplete_release_env() { - cat > workflow-config.yaml <<'YAML' -stacks: - - name: terragrunt - environments: - production: - apply_trigger: release -YAML - mkdir -p aws/vpc/production - write_service_release_config vpc - assert_fails bash "${script_dir}/check-release-configs.sh" - assert_stderr_contains "vpc/production" - assert_stderr_contains "aws_region" - assert_stderr_contains "iam_role_plan" - assert_stderr_contains "iam_role_apply" -} - -test_check_configs_rejects_missing_exclude_paths() { - write_release_config - mkdir -p aws/vpc/production - write_service_release_config vpc - jq -c 'del(.packages["aws/vpc"]["exclude-paths"])' aws/vpc/release-please-config.json > config.tmp - mv config.tmp aws/vpc/release-please-config.json - assert_fails bash "${script_dir}/check-release-configs.sh" - assert_stderr_contains 'aws/vpc: exclude-paths must be ["aws/vpc/master"] (got null)' -} - -test_check_configs_rejects_relative_exclude_paths() { - write_release_config - mkdir -p aws/vpc/production - write_service_release_config vpc vpc '["master"]' - assert_fails bash "${script_dir}/check-release-configs.sh" - assert_stderr_contains 'aws/vpc: exclude-paths must be ["aws/vpc/master"]' -} - -test_check_configs_accepts_exclude_paths_in_any_order() { - cat > workflow-config.yaml <<'YAML' -stacks: - - name: terragrunt - environments: - master: - apply_trigger: merge - develop: - apply_trigger: merge - production: - aws_region: ap-northeast-1 - iam_role_plan: arn:aws:iam::222222222222:role/production-plan - iam_role_apply: arn:aws:iam::222222222222:role/production-apply - apply_trigger: release -YAML - mkdir -p aws/vpc/production - write_service_release_config vpc vpc '["aws/vpc/develop","aws/vpc/master"]' - assert_eq "" "$(bash "${script_dir}/check-release-configs.sh" 2>&1)" -} - -test_deploy_trigger_applies_only_merge_targets() { - local expected="\${{ matrix.target.stack == 'terragrunt' && (github.event_name == 'pull_request' && 'plan' || (matrix.target.apply_trigger == 'merge' && 'apply' || '')) || '' }}" - local actual - actual="$(yq '.jobs.deploy-terragrunt.with.action-type' "${repo_root}/.github/workflows/label-base-deploy--resolver.yaml")" - assert_eq "${expected}" "${actual}" -} - -test_deploy_trigger_excludes_shared_targets() { - local job stack - for job in deploy-terragrunt deploy-kubernetes; do - stack="$(yq ".jobs.${job}.strategy.matrix.exclude[] | select(.target.stack == \"terragrunt-shared\") | .target.stack" "${repo_root}/.github/workflows/label-base-deploy--resolver.yaml")" - assert_eq "terragrunt-shared" "${stack}" - done -} - -test_release_workflows_skip_empty_targets() { - local expected="needs.resolve.outputs.targets != '[]'" - assert_eq "${expected}" "$(yq '.jobs.plan.if' "${repo_root}/.github/workflows/release--plan.yaml")" - assert_eq "${expected}" "$(yq '.jobs.apply.if' "${repo_root}/.github/workflows/release--deploy.yaml")" -} - -test_repository_config_excludes_production() { - local excluded - excluded="$(yq '.stacks[] | select(.name == "terragrunt") | .exclude[] | select(.environment == "production") | .environment' "${repo_root}/workflow-config.yaml")" - assert_eq "production" "${excluded}" -} - -failed=0 -for test_name in $(compgen -A function test_); do - fixture="$(mktemp -d "${work_root}/fixture.XXXXXX")" - set +e - (set -e; cd "${fixture}"; "${test_name}") - status=$? - set -e - if [ "${status}" -eq 0 ]; then - echo "PASS: ${test_name}" - else - echo "FAIL: ${test_name}" - failed=1 - fi -done - -exit "${failed}" diff --git a/.github/scripts/terragrunt-release/validate-apply-trigger.sh b/.github/scripts/terragrunt-release/validate-apply-trigger.sh deleted file mode 100755 index dacd5a44..00000000 --- a/.github/scripts/terragrunt-release/validate-apply-trigger.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -config_path="${1:-workflow-config.yaml}" - -errors="$(yq -o=json '.' "${config_path}" | jq -r --arg q "'" ' - .stacks | to_entries[] - | select(.value.name == "terragrunt") - | .key as $index - | .value.environments | to_entries[] - | select(.value.apply_trigger | IN("merge", "release") | not) - | "::error::stacks[\($index)].environments.\(.key).apply_trigger must be merge or release (got \($q)\(.value.apply_trigger)\($q))" -')" - -if [ -n "${errors}" ]; then - echo "${errors}" >&2 - exit 1 -fi diff --git a/.github/workflows/ci-gatekeeper.yaml b/.github/workflows/ci-gatekeeper.yaml index a68a8daa..3295dff1 100644 --- a/.github/workflows/ci-gatekeeper.yaml +++ b/.github/workflows/ci-gatekeeper.yaml @@ -7,19 +7,11 @@ on: branches: - '**' -permissions: - actions: read - jobs: ci-gatekeeper: - name: CI Gatekeeper - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - name: Wait for other workflows - uses: int128/wait-for-workflows-action@b320164b37276db89a12829914d6eb6ef4973d2b # v1.108.0 - with: - max-timeout-seconds: 1800 # 30 minutes - # The AI review is advisory; a Bedrock outage must not block merges through this required check. - exclude-workflow-names: | - Renovate Major Review + permissions: + actions: read + uses: panicboat/.github/.github/workflows/reusable--ci-gatekeeper.yaml@d54532665675f1843914da4b324dc2a58dd37239 # v1.0.0 + with: + # The AI review is advisory; a Bedrock outage must not block merges through this required check. + exclude-workflow-names: Renovate Major Review diff --git a/.github/workflows/label-base-deploy--dispatcher.yaml b/.github/workflows/label-base-deploy--dispatcher.yaml index 6e9f35c2..14d75a72 100644 --- a/.github/workflows/label-base-deploy--dispatcher.yaml +++ b/.github/workflows/label-base-deploy--dispatcher.yaml @@ -7,37 +7,14 @@ on: branches: - '**' -permissions: - contents: read - pull-requests: write - issues: write - jobs: dispatch-labels: - name: 'Dispatch Labels' - if: ${{ !startsWith(github.head_ref, 'release-please--') }} - runs-on: ubuntu-latest - steps: - - name: Generate GitHub App token - id: app-token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - owner: ${{ github.repository_owner }} - - - name: Get PR information - id: pr-info - uses: jwalton/gh-find-current-pr@f3d61b485d2801773f7a07b2aaa3306bd8f8e653 # v1.3.5 - with: - github-token: ${{ steps.app-token.outputs.token }} - state: all - continue-on-error: true - - - name: Dispatch Labels - uses: panicboat/deploy-actions/label-dispatcher@1ab520e5ef33b8d744982762ffc4e08009a34744 # v2.0.1 - with: - pr-number: ${{ steps.pr-info.outputs.number }} - repository: ${{ github.repository }} - github-token: ${{ steps.app-token.outputs.token }} - config-path: 'workflow-config.yaml' + permissions: + contents: read + pull-requests: write + issues: write + uses: panicboat/.github/.github/workflows/reusable--label-base-deploy--dispatcher.yaml@d54532665675f1843914da4b324dc2a58dd37239 # v1.0.0 + with: + app-id: ${{ vars.APP_ID }} + secrets: + private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/label-base-deploy--resolver.yaml b/.github/workflows/label-base-deploy--resolver.yaml index 3bd1aae0..0a6415ae 100644 --- a/.github/workflows/label-base-deploy--resolver.yaml +++ b/.github/workflows/label-base-deploy--resolver.yaml @@ -10,154 +10,18 @@ on: branches: - main -permissions: - id-token: write - contents: write # kubernetes-executor pushes hydrated manifests - pull-requests: write - concurrency: group: label-base-deploy-resolver-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: - resolve: - name: 'Resolve Targets' - runs-on: ubuntu-latest - outputs: - targets: ${{ steps.resolver.outputs.targets }} - has-targets: ${{ steps.resolver.outputs.has-targets }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Validate apply_trigger - run: bash .github/scripts/terragrunt-release/validate-apply-trigger.sh - - - name: Generate GitHub App token - id: app-token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - owner: ${{ github.repository_owner }} - - - name: Get PR information - id: pr-info - uses: jwalton/gh-find-current-pr@f3d61b485d2801773f7a07b2aaa3306bd8f8e653 # v1.3.5 - with: - github-token: ${{ steps.app-token.outputs.token }} - state: all - continue-on-error: true - - - name: Label Resolver - id: resolver - uses: panicboat/deploy-actions/label-resolver@1ab520e5ef33b8d744982762ffc4e08009a34744 # v2.0.1 - with: - repository: ${{ github.repository }} - pr-number: ${{ steps.pr-info.outputs.number }} - github-token: ${{ steps.app-token.outputs.token }} - config-path: 'workflow-config.yaml' - - kubernetes-targets-group: - name: 'Group Kubernetes Targets by Environment' - needs: resolve - if: | - needs.resolve.outputs.has-targets == 'true' && - contains(needs.resolve.outputs.targets, '"stack":"kubernetes"') - runs-on: ubuntu-latest - outputs: - environments: ${{ steps.group.outputs.environments }} - steps: - - name: Group by environment - id: group - env: - TARGETS: ${{ needs.resolve.outputs.targets }} - run: | - set -euo pipefail - grouped=$(echo "$TARGETS" | jq -c ' - [.[] | select(.stack == "kubernetes")] - | group_by(.environment) - | map({environment: .[0].environment, services: [.[].service]}) - ') - echo "environments=$grouped" >> "$GITHUB_OUTPUT" - - deploy-kubernetes-hydrate: - name: 'Hydrate Kubernetes (${{ matrix.env.environment }})' - needs: kubernetes-targets-group - strategy: - matrix: - env: ${{ fromJson(needs.kubernetes-targets-group.outputs.environments) }} - fail-fast: false - uses: ./.github/workflows/reusable--kubernetes-hydrator.yaml - with: - environment: ${{ matrix.env.environment }} - services: ${{ toJson(matrix.env.services) }} - app-id: ${{ vars.APP_ID }} - secrets: - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - deploy-terragrunt: - name: 'Deploy Terragrunt (${{ matrix.target.service }}:${{ matrix.target.environment }})' - needs: resolve - if: | - needs.resolve.outputs.has-targets == 'true' && - contains(needs.resolve.outputs.targets, '"stack":"terragrunt"') - strategy: - matrix: - target: ${{ fromJson(needs.resolve.outputs.targets) }} - exclude: - - target: - stack: terragrunt-shared - fail-fast: false - uses: ./.github/workflows/reusable--terragrunt-runner.yaml + resolver: + permissions: + id-token: write + contents: write # the helmfile hydrator pushes hydrated manifests + pull-requests: write + uses: panicboat/.github/.github/workflows/reusable--label-base-deploy--resolver.yaml@d54532665675f1843914da4b324dc2a58dd37239 # v1.0.0 with: - service-name: ${{ matrix.target.service }} - environment: ${{ matrix.target.environment }} - action-type: ${{ matrix.target.stack == 'terragrunt' && (github.event_name == 'pull_request' && 'plan' || (matrix.target.apply_trigger == 'merge' && 'apply' || '')) || '' }} - iam-role: ${{ github.event_name == 'pull_request' && matrix.target.iam_role_plan || matrix.target.iam_role_apply }} - aws-region: ${{ matrix.target.aws_region }} - working-directory: ${{ matrix.target.working_directory }} app-id: ${{ vars.APP_ID }} secrets: private-key: ${{ secrets.APP_PRIVATE_KEY }} - - deploy-kubernetes: - name: 'Deploy Kubernetes (${{ matrix.target.service }}:${{ matrix.target.environment }})' - needs: [resolve, deploy-kubernetes-hydrate] - if: | - needs.resolve.outputs.has-targets == 'true' && - contains(needs.resolve.outputs.targets, '"stack":"kubernetes"') - strategy: - matrix: - target: ${{ fromJson(needs.resolve.outputs.targets) }} - exclude: - - target: - stack: terragrunt - - target: - stack: terragrunt-shared - fail-fast: false - uses: ./.github/workflows/reusable--kubernetes-builder.yaml - with: - service-name: ${{ matrix.target.service }} - environment: ${{ matrix.target.environment }} - app-id: ${{ vars.APP_ID }} - secrets: - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - deployment-summary: - name: 'Deployment Summary' - needs: [resolve, deploy-terragrunt, deploy-kubernetes-hydrate, deploy-kubernetes] - if: always() && needs.resolve.outputs.has-targets == 'true' - runs-on: ubuntu-latest - steps: - - name: Summary - run: | - echo "📊 Deployment Summary" - echo "Event: ${{ github.event_name }}" - echo "Branch: ${{ github.ref_name }}" - echo "Environment: ${{ needs.resolve.outputs.target-environment }}" - echo "Safety Status: ${{ needs.resolve.outputs.safety-status }}" - echo "Targets: ${{ needs.resolve.outputs.targets }}" - echo "Terragrunt Job Status: ${{ needs.deploy-terragrunt.result }}" - echo "Kubernetes Job Status: ${{ needs.deploy-kubernetes.result }}" - echo "Kubernetes Hydrate Job Status: ${{ needs.deploy-kubernetes-hydrate.result }}" diff --git a/.github/workflows/lint-actions.yml b/.github/workflows/lint-actions.yml index 9d7bb5ad..a05997e6 100644 --- a/.github/workflows/lint-actions.yml +++ b/.github/workflows/lint-actions.yml @@ -6,13 +6,8 @@ on: branches: [main] pull_request: -permissions: - contents: read - jobs: ensure-sha-pinned: - name: Ensure actions are pinned to SHAs - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: zgosalvez/github-actions-ensure-sha-pinned-actions@c4e71056006d29f90204b2d063be337109507d62 # v5.0.10 + permissions: + contents: read + uses: panicboat/.github/.github/workflows/reusable--lint-actions.yaml@d54532665675f1843914da4b324dc2a58dd37239 # v1.0.0 diff --git a/.github/workflows/release--deploy.yaml b/.github/workflows/release--deploy.yaml index eb1463b2..c5283509 100644 --- a/.github/workflows/release--deploy.yaml +++ b/.github/workflows/release--deploy.yaml @@ -11,62 +11,18 @@ on: required: true type: string -permissions: - id-token: write - contents: read - pull-requests: write - concurrency: group: release-deploy-${{ github.event.release.tag_name || inputs.tag }} cancel-in-progress: false jobs: - resolve: - name: 'Resolve Release Targets' - runs-on: ubuntu-latest + release-deploy: permissions: + id-token: write contents: read - env: - TAG: ${{ github.event.release.tag_name || inputs.tag }} - outputs: - targets: ${{ steps.resolve.outputs.targets }} - tag: ${{ steps.resolve.outputs.tag }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ env.TAG }} - - - name: Resolve release targets - id: resolve - run: | - set -euo pipefail - service=$(bash .github/scripts/terragrunt-release/release-service.sh --tag "$TAG") - targets=$(bash .github/scripts/terragrunt-release/release-targets.sh "$service") - echo "targets=$targets" >> "$GITHUB_OUTPUT" - echo "tag=$TAG" >> "$GITHUB_OUTPUT" - - apply: - name: 'Apply Release (${{ matrix.target.service }}:${{ matrix.target.environment }})' - needs: resolve - if: needs.resolve.outputs.targets != '[]' - concurrency: - group: terragrunt-apply-${{ matrix.target.working_directory }} - cancel-in-progress: false - strategy: - matrix: - target: ${{ fromJson(needs.resolve.outputs.targets) }} - fail-fast: false - uses: ./.github/workflows/reusable--terragrunt-runner.yaml + pull-requests: write + uses: panicboat/.github/.github/workflows/reusable--release--deploy.yaml@d54532665675f1843914da4b324dc2a58dd37239 # v1.0.0 with: - service-name: ${{ matrix.target.service }} - environment: ${{ matrix.target.environment }} - action-type: apply - iam-role: ${{ matrix.target.iam_role_apply }} - aws-region: ${{ matrix.target.aws_region }} - working-directory: ${{ matrix.target.working_directory }} app-id: ${{ vars.APP_ID }} - ref: ${{ needs.resolve.outputs.tag }} - github-environment: ${{ matrix.target.environment }} secrets: private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/release--plan.yaml b/.github/workflows/release--plan.yaml index d2caabaa..223486c5 100644 --- a/.github/workflows/release--plan.yaml +++ b/.github/workflows/release--plan.yaml @@ -5,54 +5,18 @@ on: pull_request: types: [opened, synchronize, reopened] -permissions: - id-token: write - contents: read - pull-requests: write - concurrency: group: release-plan-${{ github.head_ref }} cancel-in-progress: true jobs: - resolve: - name: 'Resolve Release Targets' - if: startsWith(github.head_ref, 'release-please--branches--main--components--') - runs-on: ubuntu-latest + release-plan: permissions: + id-token: write contents: read - outputs: - targets: ${{ steps.resolve.outputs.targets }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Resolve release targets - id: resolve - env: - HEAD_REF: ${{ github.head_ref }} - run: | - set -euo pipefail - service=$(bash .github/scripts/terragrunt-release/release-service.sh --branch "$HEAD_REF") - targets=$(bash .github/scripts/terragrunt-release/release-targets.sh "$service") - echo "targets=$targets" >> "$GITHUB_OUTPUT" - - plan: - name: 'Plan Release (${{ matrix.target.service }}:${{ matrix.target.environment }})' - needs: resolve - if: needs.resolve.outputs.targets != '[]' - strategy: - matrix: - target: ${{ fromJson(needs.resolve.outputs.targets) }} - fail-fast: false - uses: ./.github/workflows/reusable--terragrunt-runner.yaml + pull-requests: write + uses: panicboat/.github/.github/workflows/reusable--release--plan.yaml@d54532665675f1843914da4b324dc2a58dd37239 # v1.0.0 with: - service-name: ${{ matrix.target.service }} - environment: ${{ matrix.target.environment }} - action-type: plan - iam-role: ${{ matrix.target.iam_role_plan }} - aws-region: ${{ matrix.target.aws_region }} - working-directory: ${{ matrix.target.working_directory }} app-id: ${{ vars.APP_ID }} secrets: private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/release--please.yaml b/.github/workflows/release--please.yaml index abd973bb..5f0e5301 100644 --- a/.github/workflows/release--please.yaml +++ b/.github/workflows/release--please.yaml @@ -6,46 +6,16 @@ on: branches: [main] workflow_dispatch: {} -permissions: - contents: read - concurrency: group: release-please cancel-in-progress: false jobs: - discover: - runs-on: ubuntu-latest - outputs: - paths: ${{ steps.find.outputs.paths }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Find release-please configs - id: find - run: | - set -euo pipefail - paths=$(git ls-files '*/release-please-config.json' | jq -R 'rtrimstr("/release-please-config.json")' | jq -sc .) - echo "paths=$paths" >> "$GITHUB_OUTPUT" - release-please: - needs: discover - if: needs.discover.outputs.paths != '[]' - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - path: ${{ fromJson(needs.discover.outputs.paths) }} - steps: - - name: Generate GitHub App token - id: app-token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5 - with: - token: ${{ steps.app-token.outputs.token }} - config-file: ${{ matrix.path }}/release-please-config.json - manifest-file: ${{ matrix.path }}/release-please-manifest.json + permissions: + contents: read + uses: panicboat/.github/.github/workflows/reusable--release--please.yaml@d54532665675f1843914da4b324dc2a58dd37239 # v1.0.0 + with: + app-id: ${{ vars.APP_ID }} + secrets: + private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/renovate-major-review.yaml b/.github/workflows/renovate-major-review.yaml index a1d24a84..557e7e40 100644 --- a/.github/workflows/renovate-major-review.yaml +++ b/.github/workflows/renovate-major-review.yaml @@ -13,105 +13,11 @@ concurrency: cancel-in-progress: true jobs: - render: - name: 'Render' - if: github.event.label.name == '📈 major-update' && github.event.pull_request.user.login == 'renovate[bot]' - runs-on: ubuntu-latest - timeout-minutes: 15 - # helmfile templates can exec commands, so PR content is rendered in a job without id-token or the review environment. - permissions: - contents: read - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Setup aqua - uses: aquaproj/aqua-installer@82d0e83878a8657c4a6f2ff1755d3bfbfc67f329 # v4.1.0 - with: - aqua_version: v2.64.0 - - - name: Render manifest diff - # HEAD is the PR merge commit, so its first parent is the base it merges into. - run: bash .github/scripts/kubernetes-hydrate/render-diff.sh HEAD^1 "${RUNNER_TEMP}/render-diff" - - - name: Upload manifest diff - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - with: - name: render-diff - path: ${{ runner.temp }}/render-diff - retention-days: 1 - review: - name: 'Review' - needs: render - runs-on: ubuntu-latest - timeout-minutes: 30 - # Environment-scoped OIDC sub keeps a prompt-injected run from assuming the plan roles, which trust the pull_request sub. - environment: renovate-major-review permissions: contents: read - pull-requests: read - id-token: write - outputs: - body: ${{ steps.claude.outputs.structured_output && fromJSON(steps.claude.outputs.structured_output).body || '' }} - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Download manifest diff - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 - with: - name: render-diff - path: .render-diff - - - name: Setup aqua - uses: aquaproj/aqua-installer@82d0e83878a8657c4a6f2ff1755d3bfbfc67f329 # v4.1.0 - with: - aqua_version: v2.64.0 - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0 - with: - role-to-assume: arn:aws:iam::559744160976:role/github-oidc-auth-master-github-actions-bedrock-role - aws-region: us-east-1 - - - name: Review with Claude - id: claude - uses: anthropics/claude-code-action@16f9f71ab9c490faf367f94dd294897edc25be33 # v1.0.261 - env: - # The Bedrock role only allows Sonnet 4.6, so background tasks must not fall back to Haiku. - ANTHROPIC_DEFAULT_HAIKU_MODEL: global.anthropic.claude-sonnet-4-6 - with: - use_bedrock: 'true' - # Read-only token; without it the action exchanges OIDC for the Claude App's write token. - github_token: ${{ github.token }} - allowed_bots: renovate - prompt: | - Read `.github/prompts/renovate-major-review.md` and follow it. - Pull request number: ${{ github.event.pull_request.number }} - claude_args: | - --model global.anthropic.claude-sonnet-4-6 - --json-schema '{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":60000}},"required":["body"]}' - --allowedTools "Read,Glob,Grep,WebFetch,Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh api:*),Bash(git diff:*),Bash(git log:*),Bash(git show:*),Bash(helm repo add:*),Bash(helm repo update:*),Bash(helm pull:*),Bash(helm show:*)" - - post: - name: 'Post Review' - needs: review - if: needs.review.result == 'success' && needs.review.outputs.body != '' - runs-on: ubuntu-latest - permissions: pull-requests: write - steps: - - name: Upsert review comment - uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1 - with: - message: ${{ needs.review.outputs.body }} - comment-tag: renovate-major-review - mode: upsert - pr-number: ${{ github.event.pull_request.number }} + id-token: write + uses: panicboat/.github/.github/workflows/reusable--renovate-major-review.yaml@d54532665675f1843914da4b324dc2a58dd37239 # v1.0.0 + with: + prompt-path: .github/prompts/renovate-major-review.md diff --git a/.github/workflows/reusable--kubernetes-builder.yaml b/.github/workflows/reusable--kubernetes-builder.yaml deleted file mode 100644 index 816e6168..00000000 --- a/.github/workflows/reusable--kubernetes-builder.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# Posts the kustomize diff of one hydrated component as a pull request comment. -name: 'Reusable - Kubernetes Builder' - -on: - workflow_call: - inputs: - service-name: - required: true - type: string - description: 'Service name for identification' - environment: - required: true - type: string - description: 'Target environment (e.g., local)' - app-id: - required: true - type: string - description: 'GitHub App ID for authentication' - secrets: - private-key: - required: true - description: 'GitHub App private key for authentication' - -jobs: - kustomize-diff: - name: 'Kustomize Diff' - if: github.event_name == 'pull_request' - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - steps: - - name: Generate GitHub App token - id: app-token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 - with: - app-id: ${{ inputs.app-id }} - private-key: ${{ secrets.private-key }} - owner: ${{ github.repository_owner }} - - - name: Get PR information - id: pr-info - uses: jwalton/gh-find-current-pr@f3d61b485d2801773f7a07b2aaa3306bd8f8e653 # v1.3.5 - with: - github-token: ${{ steps.app-token.outputs.token }} - state: all - continue-on-error: true - - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - token: ${{ steps.app-token.outputs.token }} - ref: ${{ github.head_ref }} - fetch-depth: 0 - - - name: Checkout base ref - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.base.sha }} - path: base - token: ${{ steps.app-token.outputs.token }} - - - name: Build head manifests - id: kustomize-head - uses: int128/kustomize-action@4fbeca93d7072507f0c6d4529025d17a5d209551 # v1.195.0 - with: - kustomization: kubernetes/manifests/${{ inputs.environment }}/${{ inputs.service-name }}/kustomization.yaml - write-individual-files: true - - - name: Build base manifests - id: kustomize-base - uses: int128/kustomize-action@4fbeca93d7072507f0c6d4529025d17a5d209551 # v1.195.0 - with: - base-directory: base - kustomization: kubernetes/manifests/${{ inputs.environment }}/${{ inputs.service-name }}/kustomization.yaml - write-individual-files: true - - - name: Diff manifests - id: diff - uses: int128/diff-action@274034d712aef611adcbd41e5a647f43e4edd5a5 # v2.41.0 - with: - base: ${{ steps.kustomize-base.outputs.directory }} - head: ${{ steps.kustomize-head.outputs.directory }} - - - name: Comment PR - if: steps.pr-info.outputs.number != '' - uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1 - with: - message: | - ## Kustomize Diff - - **Service**: `${{ inputs.service-name }}` - **Environment**: `${{ inputs.environment }}` - - ${{ steps.diff.outputs.comment-body || 'No changes' }} - comment-tag: "kubernetes-${{ inputs.service-name }}-${{ inputs.environment }}" - mode: upsert - pr-number: ${{ steps.pr-info.outputs.number }} - GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} - reactions: ${{ steps.diff.outputs.has-diff == 'true' && 'rocket' || '' }} - continue-on-error: true diff --git a/.github/workflows/reusable--kubernetes-hydrator.yaml b/.github/workflows/reusable--kubernetes-hydrator.yaml deleted file mode 100644 index 3f6d2b70..00000000 --- a/.github/workflows/reusable--kubernetes-hydrator.yaml +++ /dev/null @@ -1,125 +0,0 @@ -# Renders the given components into kubernetes/manifests and commits the result to the pull request branch. -name: 'Reusable - Kubernetes Hydrator' - -on: - workflow_call: - inputs: - environment: - required: true - type: string - description: 'Target environment for hydration (e.g., local)' - services: - required: true - type: string - description: 'JSON array of service names to hydrate (e.g. ["coredns","cilium"])' - app-id: - required: true - type: string - description: 'GitHub App ID for authentication' - secrets: - private-key: - required: true - description: 'GitHub App private key for authentication' - -concurrency: - group: kubernetes-hydrate-${{ github.event.pull_request.number || github.ref }}-${{ inputs.environment }} - cancel-in-progress: false - -jobs: - hydrate: - name: 'Hydrate' - if: github.event_name == 'pull_request' - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - steps: - - name: Generate GitHub App token - id: app-token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 - with: - app-id: ${{ inputs.app-id }} - private-key: ${{ secrets.private-key }} - owner: ${{ github.repository_owner }} - - - name: Get PR information - id: pr-info - uses: jwalton/gh-find-current-pr@f3d61b485d2801773f7a07b2aaa3306bd8f8e653 # v1.3.5 - with: - github-token: ${{ steps.app-token.outputs.token }} - state: all - continue-on-error: true - - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - token: ${{ steps.app-token.outputs.token }} - ref: ${{ github.head_ref }} - fetch-depth: 0 - - - name: Setup aqua - uses: aquaproj/aqua-installer@82d0e83878a8657c4a6f2ff1755d3bfbfc67f329 # v4.1.0 - with: - aqua_version: v2.64.0 - - - name: Hydrate changed components - env: - SERVICES_JSON: ${{ inputs.services }} - run: | - set -euo pipefail - for svc in $(echo "$SERVICES_JSON" | jq -r '.[]'); do - bash .github/scripts/kubernetes-hydrate/hydrate-component.sh "$svc" "${{ inputs.environment }}" - done - - - name: Hydrate index - run: bash .github/scripts/kubernetes-hydrate/hydrate-index.sh "${{ inputs.environment }}" - - - name: Commit and push hydrated manifests - id: auto-commit - uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0 - with: - commit_message: 'chore(kubernetes/manifests/${{ inputs.environment }}): hydrate manifests' - commit_options: '--signoff' - file_pattern: 'kubernetes/manifests/${{ inputs.environment }}/' - commit_user_name: 'github-actions[bot]' - commit_user_email: 'github-actions[bot]@users.noreply.github.com' - - - name: Compute index diff - id: index-diff - if: steps.pr-info.outputs.number != '' - env: - BASE_SHA: ${{ github.event.pull_request.base.sha }} - ENV: ${{ inputs.environment }} - run: | - set -euo pipefail - diff=$(git diff "$BASE_SHA" HEAD -- \ - "kubernetes/manifests/$ENV/kustomization.yaml" \ - "kubernetes/manifests/$ENV/00-namespaces/" || true) - { - echo 'diff<> "$GITHUB_OUTPUT" - if [ -n "$diff" ]; then - echo "has-diff=true" >> "$GITHUB_OUTPUT" - else - echo "has-diff=false" >> "$GITHUB_OUTPUT" - fi - - - name: Comment index diff - if: steps.index-diff.outputs.has-diff == 'true' && steps.pr-info.outputs.number != '' - uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1 - with: - message: | - ## Kubernetes Index Diff - - **Environment**: `${{ inputs.environment }}` - - ```diff - ${{ steps.index-diff.outputs.diff }} - ``` - comment-tag: 'kubernetes-index-${{ inputs.environment }}' - mode: upsert - pr-number: ${{ steps.pr-info.outputs.number }} - GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} - continue-on-error: true diff --git a/.github/workflows/reusable--terragrunt-runner.yaml b/.github/workflows/reusable--terragrunt-runner.yaml deleted file mode 100644 index 35342ff3..00000000 --- a/.github/workflows/reusable--terragrunt-runner.yaml +++ /dev/null @@ -1,95 +0,0 @@ -# Runs terragrunt plan or apply in one working directory and reports the result with tfcmt. -name: 'Reusable - Terragrunt Runner' - -on: - workflow_call: - inputs: - service-name: - required: true - type: string - description: 'Service name for terragrunt execution' - environment: - required: true - type: string - description: 'Environment name (develop, staging, production, etc.)' - action-type: - required: true - type: string - description: 'Action type: plan or apply' - iam-role: - required: true - type: string - description: 'IAM role for plan/apply operations' - aws-region: - required: true - type: string - description: 'AWS region' - working-directory: - required: true - type: string - description: 'Working directory for terragrunt execution' - app-id: - required: true - type: string - description: 'GitHub App ID for authentication' - ref: - required: false - type: string - default: '' - description: 'Git ref to check out (defaults to the triggering ref)' - github-environment: - required: false - type: string - default: '' - description: 'GitHub environment the job runs in (none when empty)' - secrets: - private-key: - required: true - description: 'GitHub App private key for authentication' - -jobs: - run-terragrunt: - name: 'Run Terragrunt' - if: inputs.action-type != '' - runs-on: ubuntu-latest - environment: ${{ inputs.github-environment }} - steps: - - name: Generate GitHub App token - id: app-token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 - with: - app-id: ${{ inputs.app-id }} - private-key: ${{ secrets.private-key }} - owner: ${{ github.repository_owner }} - - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ inputs.ref }} - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0 - with: - role-to-assume: ${{ inputs.iam-role }} - aws-region: ${{ inputs.aws-region }} - role-session-name: GitHubActions-Terragrunt-${{ inputs.action-type }}-${{ inputs.environment }} - audience: sts.amazonaws.com - - - name: Setup aqua - uses: aquaproj/aqua-installer@82d0e83878a8657c4a6f2ff1755d3bfbfc67f329 # v4.1.0 - with: - aqua_version: v2.64.0 - - - name: Run Terragrunt - working-directory: ${{ inputs.working-directory }} - env: - GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} - TF_INPUT: 'false' - # tfcmt cannot parse the output while terragrunt prefixes each line with its log metadata. - TG_LOG_DISABLE: 'true' - TFCMT_PLAN_PATCH: 'true' - TFCMT_DISABLE_LABEL: 'true' - SERVICE_NAME: ${{ inputs.service-name }} - ENVIRONMENT: ${{ inputs.environment }} - ACTION_TYPE: ${{ inputs.action-type }} - run: tfcmt -var "target:$SERVICE_NAME/$ENVIRONMENT" "$ACTION_TYPE" -- terragrunt "$ACTION_TYPE" -no-color ${{ inputs.action-type == 'apply' && '-auto-approve' || '' }} diff --git a/.github/workflows/semantic-pull-request.yml b/.github/workflows/semantic-pull-request.yml index a9393ed5..a2e5238e 100644 --- a/.github/workflows/semantic-pull-request.yml +++ b/.github/workflows/semantic-pull-request.yml @@ -5,21 +5,12 @@ on: pull_request_target: types: [opened, edited, synchronize, reopened] -permissions: - contents: read - jobs: validate: - name: Validate PR title - runs-on: ubuntu-latest - steps: - - name: Generate GitHub App token - id: app-token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 - with: - app-id: ${{ vars.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 - env: - GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} + permissions: + contents: read + uses: panicboat/.github/.github/workflows/reusable--semantic-pull-request.yaml@d54532665675f1843914da4b324dc2a58dd37239 # v1.0.0 + with: + app-id: ${{ vars.APP_ID }} + secrets: + private-key: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/.github/workflows/test-terragrunt-release.yaml b/.github/workflows/test-terragrunt-release.yaml index 414f8aea..204128b5 100644 --- a/.github/workflows/test-terragrunt-release.yaml +++ b/.github/workflows/test-terragrunt-release.yaml @@ -1,4 +1,4 @@ -# Tests the terragrunt release scripts and validates workflow-config.yaml and the release-please configs. +# Validates workflow-config.yaml apply_trigger values and the release-please configs. name: Test Terragrunt Release on: @@ -6,15 +6,8 @@ on: branches: [main] pull_request: -permissions: - contents: read - jobs: - test: - name: Test terragrunt release scripts - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - run: bash .github/scripts/terragrunt-release/test.sh - - run: bash .github/scripts/terragrunt-release/validate-apply-trigger.sh - - run: bash .github/scripts/terragrunt-release/check-release-configs.sh + validate: + permissions: + contents: read + uses: panicboat/.github/.github/workflows/reusable--test-terragrunt-release.yaml@d54532665675f1843914da4b324dc2a58dd37239 # v1.0.0 diff --git a/README-ja.md b/README-ja.md index 9bcf0d7a..08db75a6 100644 --- a/README-ja.md +++ b/README-ja.md @@ -53,7 +53,7 @@ #### Releases - `apply_trigger: release` の environment を持つ `aws/{service}` は、それぞれ release-please の設定(`release-please-config.json` / `release-please-manifest.json`)を持つ。 - - 設定がないと [check-release-configs.sh](.github/scripts/terragrunt-release/check-release-configs.sh) が CI を失敗させる。 + - 設定がないと [check-release-configs.sh](https://github.com/panicboat/.github/blob/main/scripts/terragrunt-release/check-release-configs.sh) が CI を失敗させる。 - `apply_trigger: merge` の environment ディレクトリだけを変える commit は、release を作らない(`exclude-paths`)。 - `apply_trigger: release` の environment がすべて除外されている間も release PR は作られるが、plan も apply もされない。 - plan を出し直すときは、`Release - Plan` の run で「Re-run all jobs」を使う。 @@ -63,9 +63,9 @@ | Stack | Path convention | Tooling | |-------|-----------------|---------| -| AWS infrastructure | `aws/{service}/{environment}` | Terragrunt + OpenTofu ([reusable--terragrunt-runner.yaml](.github/workflows/reusable--terragrunt-runner.yaml)) | -| GitHub configuration | `github/{service}/{environment}` | Terragrunt + OpenTofu ([reusable--terragrunt-runner.yaml](.github/workflows/reusable--terragrunt-runner.yaml)) | -| Kubernetes platform | `kubernetes/components/{service}/{environment}` | Helmfile → Kustomize hydration ([reusable--kubernetes-hydrator.yaml](.github/workflows/reusable--kubernetes-hydrator.yaml) / [reusable--kubernetes-builder.yaml](.github/workflows/reusable--kubernetes-builder.yaml)) → Flux CD | +| AWS infrastructure | `aws/{service}/{environment}` | Terragrunt + OpenTofu ([reusable--terragrunt-runner.yaml](https://github.com/panicboat/.github/blob/main/.github/workflows/reusable--terragrunt-runner.yaml)) | +| GitHub configuration | `github/{service}/{environment}` | Terragrunt + OpenTofu ([reusable--terragrunt-runner.yaml](https://github.com/panicboat/.github/blob/main/.github/workflows/reusable--terragrunt-runner.yaml)) | +| Kubernetes platform | `kubernetes/components/{service}/{environment}` | Helmfile → Kustomize hydration ([reusable--kubernetes-hydrator.yaml](https://github.com/panicboat/.github/blob/main/.github/workflows/reusable--kubernetes-hydrator.yaml) / [reusable--kubernetes-builder.yaml](https://github.com/panicboat/.github/blob/main/.github/workflows/reusable--kubernetes-builder.yaml)) → Flux CD | ### Environments and Authentication @@ -92,7 +92,7 @@ flowchart LR end subgraph KubernetesCI [Kubernetes CI] - Group[kubernetes-targets-group
group by env] + Group[helmfile-targets-group
group by env] Hydrator[reusable--kubernetes-hydrator
matrix: env
concurrency: hydrate-PR-env] Commit[auto-commit
kubernetes/manifests/] Builder[reusable--kubernetes-builder
matrix: service x env
diff only] @@ -124,7 +124,7 @@ flowchart LR TG -->|on push main or release published| Apply Plan --> PRComment Apply --> AWS - Resolver -->|stack: kubernetes| Group + Resolver -->|stack: helmfile| Group Group --> Hydrator Hydrator -->|hydrate-component.sh
+ hydrate-index.sh| Commit Hydrator -->|index diff| IndexComment @@ -139,4 +139,4 @@ flowchart LR - Flux bootstrap は `kubernetes/clusters/{cluster}/flux-system/` に置く。cluster の root Kustomization が `kubernetes/manifests/{cluster}/` 配下のレンダリング済みマニフェストと外部 `GitRepository`(現状はアプリケーション monorepo)を集約する。 - Platform と application の repository は別々に pull され、疎結合に保たれる。同期間隔や source URL は `kubernetes/clusters/{cluster}/` 配下のマニフェストが source of truth。 -- [kubernetes/components/](kubernetes/components/) を変更する PR では CI が [.github/scripts/kubernetes-hydrate/](.github/scripts/kubernetes-hydrate/) を実行し、レンダリング結果を [kubernetes/manifests/](kubernetes/manifests/) にコミット、差分を PR コメントに投稿する。マージ後に Flux が適用する。 +- [kubernetes/components/](kubernetes/components/) を変更する PR では CI が [scripts/kubernetes-hydrate/](https://github.com/panicboat/.github/tree/main/scripts/kubernetes-hydrate) を実行し、レンダリング結果を [kubernetes/manifests/](kubernetes/manifests/) にコミット、差分を PR コメントに投稿する。マージ後に Flux が適用する。 diff --git a/README.md b/README.md index 8f159a8c..9988063e 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ A PR labeled by `panicboat/deploy-actions` is resolved against [workflow-config. #### Releases - Each `aws/{service}` with an `apply_trigger: release` environment has its own release-please config (`release-please-config.json` / `release-please-manifest.json`). - - [check-release-configs.sh](.github/scripts/terragrunt-release/check-release-configs.sh) fails CI when a config is missing. + - [check-release-configs.sh](https://github.com/panicboat/.github/blob/main/scripts/terragrunt-release/check-release-configs.sh) fails CI when a config is missing. - Commits that touch only `apply_trigger: merge` environment directories do not create a release (`exclude-paths`). - While every `apply_trigger: release` environment is excluded, the release PR is still created, but nothing is planned or applied. - To re-plan, use "Re-run all jobs" on the `Release - Plan` run. @@ -63,9 +63,9 @@ A PR labeled by `panicboat/deploy-actions` is resolved against [workflow-config. | Stack | Path convention | Tooling | |-------|-----------------|---------| -| AWS infrastructure | `aws/{service}/{environment}` | Terragrunt + OpenTofu ([reusable--terragrunt-runner.yaml](.github/workflows/reusable--terragrunt-runner.yaml)) | -| GitHub configuration | `github/{service}/{environment}` | Terragrunt + OpenTofu ([reusable--terragrunt-runner.yaml](.github/workflows/reusable--terragrunt-runner.yaml)) | -| Kubernetes platform | `kubernetes/components/{service}/{environment}` | Helmfile → Kustomize hydration ([reusable--kubernetes-hydrator.yaml](.github/workflows/reusable--kubernetes-hydrator.yaml) / [reusable--kubernetes-builder.yaml](.github/workflows/reusable--kubernetes-builder.yaml)) → Flux CD | +| AWS infrastructure | `aws/{service}/{environment}` | Terragrunt + OpenTofu ([reusable--terragrunt-runner.yaml](https://github.com/panicboat/.github/blob/main/.github/workflows/reusable--terragrunt-runner.yaml)) | +| GitHub configuration | `github/{service}/{environment}` | Terragrunt + OpenTofu ([reusable--terragrunt-runner.yaml](https://github.com/panicboat/.github/blob/main/.github/workflows/reusable--terragrunt-runner.yaml)) | +| Kubernetes platform | `kubernetes/components/{service}/{environment}` | Helmfile → Kustomize hydration ([reusable--kubernetes-hydrator.yaml](https://github.com/panicboat/.github/blob/main/.github/workflows/reusable--kubernetes-hydrator.yaml) / [reusable--kubernetes-builder.yaml](https://github.com/panicboat/.github/blob/main/.github/workflows/reusable--kubernetes-builder.yaml)) → Flux CD | ### Environments and authentication @@ -92,7 +92,7 @@ flowchart LR end subgraph KubernetesCI [Kubernetes CI] - Group[kubernetes-targets-group
group by env] + Group[helmfile-targets-group
group by env] Hydrator[reusable--kubernetes-hydrator
matrix: env
concurrency: hydrate-PR-env] Commit[auto-commit
kubernetes/manifests/] Builder[reusable--kubernetes-builder
matrix: service x env
diff only] @@ -124,7 +124,7 @@ flowchart LR TG -->|on push main or release published| Apply Plan --> PRComment Apply --> AWS - Resolver -->|stack: kubernetes| Group + Resolver -->|stack: helmfile| Group Group --> Hydrator Hydrator -->|hydrate-component.sh
+ hydrate-index.sh| Commit Hydrator -->|index diff| IndexComment @@ -139,4 +139,4 @@ flowchart LR - Flux bootstrap lives in `kubernetes/clusters/{cluster}/flux-system/`. The cluster's root Kustomization aggregates the rendered manifests under `kubernetes/manifests/{cluster}/` and any external `GitRepository` (currently the application monorepo). - Platform and application repositories are pulled independently and stay loosely coupled. Sync intervals and source URLs are configured in `kubernetes/clusters/{cluster}/` — treat those manifests as the source of truth. -- When [kubernetes/components/](kubernetes/components/) changes, CI runs [.github/scripts/kubernetes-hydrate/](.github/scripts/kubernetes-hydrate/), commits the rendered output to [kubernetes/manifests/](kubernetes/manifests/), and posts the diff as a PR comment. Flux applies the change once merged. +- When [kubernetes/components/](kubernetes/components/) changes, CI runs [scripts/kubernetes-hydrate/](https://github.com/panicboat/.github/tree/main/scripts/kubernetes-hydrate), commits the rendered output to [kubernetes/manifests/](kubernetes/manifests/), and posts the diff as a PR comment. Flux applies the change once merged. diff --git a/docs/runbooks/eks-production-recreate.md b/docs/runbooks/eks-production-recreate.md index 19c2e7b3..b9ebf27e 100644 --- a/docs/runbooks/eks-production-recreate.md +++ b/docs/runbooks/eks-production-recreate.md @@ -247,14 +247,14 @@ Karpenter が NodePool 観測 → Pending pod (= ebs-csi-controller / hubble-rel ```bash # RECREATE marker は Phase 4 で edit 済 (= 再 edit 不要) -# hydrate-component で全 component を新 cluster ID で再生成 +# hydrate-component で全 component を新 cluster ID で再生成 (scripts は platform の隣に clone した panicboat/.github にある) for comp in $(find kubernetes/components -mindepth 1 -maxdepth 1 -type d -exec basename {} \;); do if [ -d "kubernetes/components/${comp}/production" ]; then echo "Hydrating ${comp}..." - bash .github/scripts/kubernetes-hydrate/hydrate-component.sh "$comp" production + bash ../.github/scripts/kubernetes-hydrate/hydrate-component.sh "$comp" production fi done -bash .github/scripts/kubernetes-hydrate/hydrate-index.sh production +bash ../.github/scripts/kubernetes-hydrate/hydrate-index.sh production # commit + push (= main 直接 push は branch protection で blocked のため PR 経由) git checkout -b chore/hydrate-after-recreate-$(date +%Y%m%d) diff --git a/workflow-config.yaml b/workflow-config.yaml index 91f5b917..35f0e3e9 100644 --- a/workflow-config.yaml +++ b/workflow-config.yaml @@ -22,6 +22,6 @@ stacks: exclude: - environment: production - - name: kubernetes + - name: helmfile paths: - "kubernetes/components/{service}/{environment}"