|
9 | 9 | type: string |
10 | 10 |
|
11 | 11 | permissions: |
12 | | - contents: write |
| 12 | + contents: write # Required for `gh release create` after a successful promotion. |
13 | 13 |
|
14 | 14 | env: |
15 | 15 | # Override these by editing this file or by setting the matching repository variable. |
16 | 16 | # Worst-case wall time per attempt is HEALTH_CHECK_INTERVAL plus the curl --max-time below |
17 | 17 | # (10s), so the defaults give a ~10 minute window (24 × (15 + 10) = 600s) — enough for |
18 | 18 | # most Rails cold boots (asset precompile + db:migrate + workload readiness). |
19 | | - HEALTH_CHECK_RETRIES: 24 |
20 | | - HEALTH_CHECK_INTERVAL: 15 |
| 19 | + HEALTH_CHECK_RETRIES: ${{ vars.HEALTH_CHECK_RETRIES || 24 }} |
| 20 | + HEALTH_CHECK_INTERVAL: ${{ vars.HEALTH_CHECK_INTERVAL || 15 }} |
21 | 21 | # Space-separated list of HTTP statuses considered healthy. The default accepts 301/302 |
22 | 22 | # because `curl` is invoked without `-L`, so a root `/` that redirects to a login page |
23 | 23 | # (common for Rails apps that auth-gate `/`) would otherwise be reported as unhealthy |
|
26 | 26 | # (e.g. "200" for a plain /health, or "200 401 403" for apps that auth-gate / without |
27 | 27 | # redirecting). |
28 | 28 | HEALTH_CHECK_ACCEPTED_STATUSES: ${{ vars.HEALTH_CHECK_ACCEPTED_STATUSES || '200 301 302' }} |
29 | | - ROLLBACK_READINESS_RETRIES: 24 |
30 | | - ROLLBACK_READINESS_INTERVAL: 15 |
| 29 | + ROLLBACK_READINESS_RETRIES: ${{ vars.ROLLBACK_READINESS_RETRIES || 24 }} |
| 30 | + ROLLBACK_READINESS_INTERVAL: ${{ vars.ROLLBACK_READINESS_INTERVAL || 15 }} |
31 | 31 | PRIMARY_WORKLOAD: ${{ vars.PRIMARY_WORKLOAD }} |
32 | 32 |
|
33 | 33 | concurrency: |
@@ -128,19 +128,27 @@ jobs: |
128 | 128 | staging_vars="$(CPLN_TOKEN="${CPLN_TOKEN_STAGING}" cpln gvc get "${STAGING_APP_NAME}" --org "${CPLN_ORG_STAGING}" -o json | jq -r '.spec.env // [] | .[].name' | sort)" |
129 | 129 | production_vars="$(CPLN_TOKEN="${CPLN_TOKEN_PRODUCTION}" cpln gvc get "${PRODUCTION_APP_NAME}" --org "${CPLN_ORG_PRODUCTION}" -o json | jq -r '.spec.env // [] | .[].name' | sort)" |
130 | 130 |
|
| 131 | + # This compares GVC-level env var names only. Workload-level env entries |
| 132 | + # and secret references are outside this pre-flight check's scope. |
131 | 133 | if [[ -z "${staging_vars}" ]]; then |
132 | 134 | echo "Staging GVC exposes no environment variables; skipping parity check." |
133 | 135 | exit 0 |
134 | 136 | fi |
135 | 137 |
|
136 | 138 | missing_vars="$(comm -23 <(printf '%s\n' "${staging_vars}") <(printf '%s\n' "${production_vars}"))" |
| 139 | + extra_vars="$(comm -13 <(printf '%s\n' "${staging_vars}") <(printf '%s\n' "${production_vars}"))" |
137 | 140 |
|
138 | 141 | if [[ -n "${missing_vars}" ]]; then |
139 | 142 | echo "::error::Production is missing environment variables that exist in staging" |
140 | 143 | echo "${missing_vars}" |
141 | 144 | exit 1 |
142 | 145 | fi |
143 | 146 |
|
| 147 | + if [[ -n "${extra_vars}" ]]; then |
| 148 | + echo "::warning::Production has GVC environment variables that do not exist in staging; verify they are intentional:" |
| 149 | + echo "${extra_vars}" |
| 150 | + fi |
| 151 | +
|
144 | 152 | - name: Capture current production image |
145 | 153 | id: capture-current |
146 | 154 | env: |
@@ -258,6 +266,8 @@ jobs: |
258 | 266 | rollback_args=() |
259 | 267 |
|
260 | 268 | while IFS=$'\t' read -r index image; do |
| 269 | + # cpln parses --set as key=value; current image URI formats do not |
| 270 | + # contain "=", but re-check this if digest-pinned refs ever add one. |
261 | 271 | rollback_args+=(--set "spec.containers[${index}].image=${image}") |
262 | 272 | done < <(echo "${previous_images}" | jq -r 'to_entries[] | "\(.key)\t\(.value)"') |
263 | 273 |
|
|
0 commit comments