mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-07 16:19:01 +00:00
ci(terraform-isolation): run label retriggers in a dedicated workflow
This commit is contained in:
parent
f366d449c8
commit
46dbe35998
6 changed files with 78 additions and 67 deletions
35
.github/workflows/ci.yaml
vendored
35
.github/workflows/ci.yaml
vendored
|
|
@ -3,16 +3,6 @@ name: Frontend checks
|
|||
on:
|
||||
pull_request:
|
||||
branches: [main, dev, staging]
|
||||
# labeled/unlabeled re-evaluate terraform-isolation when the override
|
||||
# label is added or removed. Every Frontend checks job runs on those
|
||||
# events. Skipping the suite would report required checks as success
|
||||
# and could merge a failing SHA.
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- labeled
|
||||
- unlabeled
|
||||
push:
|
||||
branches: [main, dev, staging]
|
||||
workflow_dispatch: {}
|
||||
|
|
@ -81,31 +71,6 @@ jobs:
|
|||
env:
|
||||
GOVERNANCE_BASE: ${{ steps.governance-ref.outputs.base }}
|
||||
|
||||
terraform-isolation:
|
||||
# Fails a pull request that changes `terraform/**` together with deployable
|
||||
# application code (scripts/check-terraform-isolation.mjs). A merge that
|
||||
# does both queues an HCP VCS run and a content release at the same time,
|
||||
# and the two race for the workspace lock. The
|
||||
# `terraform-isolation-override` label is the reviewed exception. This
|
||||
# job runs on labeled/unlabeled as well as the default PR types so the
|
||||
# check matches the labels currently on the PR.
|
||||
name: Terraform and application changes are isolated
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: "24"
|
||||
- name: Check changed files
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
TERRAFORM_ISOLATION_OVERRIDE: ${{ contains(github.event.pull_request.labels.*.name, 'terraform-isolation-override') }}
|
||||
run: node scripts/check-terraform-isolation.mjs --base "${BASE_SHA}" --head "${HEAD_SHA}"
|
||||
|
||||
visual-regression:
|
||||
name: Visual regression
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
43
.github/workflows/terraform-isolation.yaml
vendored
Normal file
43
.github/workflows/terraform-isolation.yaml
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
name: Terraform isolation
|
||||
|
||||
# Own workflow so labeled/unlabeled re-evaluate this gate without starting a
|
||||
# new Frontend checks run. Skipping jobs inside `ci.yaml` on those events
|
||||
# would report required checks as success and could merge a failing SHA.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, dev, staging]
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
- labeled
|
||||
- unlabeled
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
terraform-isolation:
|
||||
# Fails a pull request that changes Terraform infrastructure together with
|
||||
# deployable application code (scripts/check-terraform-isolation.mjs). A
|
||||
# merge that does both queues an HCP VCS run and a content release at the
|
||||
# same time, and the two race for the workspace lock. The
|
||||
# `terraform-isolation-override` label is the reviewed exception. This
|
||||
# job is unconditional so adding or removing that label always reads the
|
||||
# current label set; a previous green check does not survive removal.
|
||||
name: Terraform and application changes are isolated
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: "24"
|
||||
- name: Check changed files
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
TERRAFORM_ISOLATION_OVERRIDE: ${{ contains(github.event.pull_request.labels.*.name, 'terraform-isolation-override') }}
|
||||
run: node scripts/check-terraform-isolation.mjs --base "${BASE_SHA}" --head "${HEAD_SHA}"
|
||||
|
|
@ -30,7 +30,7 @@ and synthesis. A task is not done until this is green.
|
|||
| Terraform isolation gate contract | `npm run test:terraform-isolation` → `scripts/check-terraform-isolation.test.mjs` | `governance` + CI | Changed-file classifier |
|
||||
| Terraform formatting/validation | `npm run test:terraform` → `scripts/terraform-validate.mjs` | `governance` + CI | `terraform/live/dev` |
|
||||
| CDK build, tests, synthesis | `npm run test:infra` | `governance` + CI | `infra/cdk/**`, both synth modes |
|
||||
| Terraform/app change isolation | `ci.yaml` job `terraform-isolation` → `scripts/check-terraform-isolation.mjs` | CI (PR) | Changed files of the PR |
|
||||
| Terraform/app change isolation | `terraform-isolation.yaml` job `terraform-isolation` → `scripts/check-terraform-isolation.mjs` | CI (PR) | Changed files of the PR |
|
||||
|
||||
## No-false-pass guarantees
|
||||
|
||||
|
|
@ -51,12 +51,11 @@ and synthesis. A task is not done until this is green.
|
|||
(`terraform/README.md`).
|
||||
- **The isolation gate re-evaluates on label changes** — the
|
||||
`terraform-isolation-override` label is the only way to merge a mixed
|
||||
Terraform/application PR. `ci.yaml` runs `terraform-isolation` on
|
||||
`labeled` and `unlabeled` as well as the default pull-request types, so
|
||||
adding or removing the label re-checks the current labels. The other
|
||||
Frontend checks jobs run on those events too; skipping them would report
|
||||
required checks as success. Removing the label fails a mixed PR that had
|
||||
previously passed with the override.
|
||||
Terraform/application PR. `.github/workflows/terraform-isolation.yaml`
|
||||
runs `terraform-isolation` on `labeled` and `unlabeled` as well as the
|
||||
default pull-request types, so adding or removing the label re-checks
|
||||
the current labels without starting a new Frontend checks run. Removing
|
||||
the label fails a mixed PR that had previously passed with the override.
|
||||
|
||||
## Where the gates run
|
||||
|
||||
|
|
@ -67,9 +66,10 @@ and synthesis. A task is not done until this is green.
|
|||
format/lint/build/tests, **and** a repo-owned `governance` job runs
|
||||
`npm run verify` (with Terraform 1.16.0 installed) so the maintainability
|
||||
ratchets and repository gates are guaranteed from this repository regardless
|
||||
of the reusable workflow. On pull requests the same workflow's
|
||||
`terraform-isolation` job fails when `terraform/**` and application code
|
||||
change together.
|
||||
of the reusable workflow.
|
||||
- **Terraform isolation ([`.github/workflows/terraform-isolation.yaml`](.github/workflows/terraform-isolation.yaml)):**
|
||||
on pull requests, fails when Terraform infrastructure and application code
|
||||
change together. Label add/remove re-runs only this workflow.
|
||||
|
||||
## Toolchain pin
|
||||
|
||||
|
|
|
|||
|
|
@ -156,10 +156,10 @@ No stored AWS keys — OIDC only. Infrastructure and content deploy separately:
|
|||
[`AGENTS.md`](AGENTS.md), [`QUALITY_GATES.md`](QUALITY_GATES.md),
|
||||
[`ARCHITECTURE_AND_CODE_QUALITY.md`](ARCHITECTURE_AND_CODE_QUALITY.md), and
|
||||
[`REVIEW_AND_PR_FRAMEWORK.md`](REVIEW_AND_PR_FRAMEWORK.md).
|
||||
- **Terraform isolation** (the `terraform-isolation` job in
|
||||
[`.github/workflows/ci.yaml`](.github/workflows/ci.yaml)) — fails a PR that
|
||||
mixes `terraform/**` with application code, so a Terraform merge never races
|
||||
a content release for the HCP workspace.
|
||||
- **Terraform isolation**
|
||||
([`.github/workflows/terraform-isolation.yaml`](.github/workflows/terraform-isolation.yaml))
|
||||
— fails a PR that mixes `terraform/**` with application code, so a Terraform
|
||||
merge never races a content release for the HCP workspace.
|
||||
- **Dev content** ([`.github/workflows/deploy.yml`](.github/workflows/deploy.yml))
|
||||
— `workflow_dispatch` on `dev` only while the Terraform adoption is in
|
||||
progress. Runs `npm run verify`, assumes `githubdeploy-shoc-frontend-new-dev`,
|
||||
|
|
|
|||
|
|
@ -147,22 +147,25 @@ test("CLI refuses to run without a base ref or --stdin", () => {
|
|||
assert.notEqual(result.status, 0);
|
||||
});
|
||||
|
||||
test("ci.yaml re-evaluates isolation on labeled and unlabeled without skipping other jobs", () => {
|
||||
const yaml = readFileSync(
|
||||
path.join(path.dirname(fileURLToPath(import.meta.url)), "..", ".github/workflows/ci.yaml"),
|
||||
"utf8",
|
||||
test("isolation workflow re-evaluates on labeled and unlabeled without rerunning Frontend checks", () => {
|
||||
const workflows = path.join(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
"..",
|
||||
".github/workflows",
|
||||
);
|
||||
const ciYaml = readFileSync(path.join(workflows, "ci.yaml"), "utf8");
|
||||
const isolationYaml = readFileSync(path.join(workflows, "terraform-isolation.yaml"), "utf8");
|
||||
|
||||
for (const eventType of ["opened", "synchronize", "reopened", "labeled", "unlabeled"]) {
|
||||
assert.match(yaml, new RegExp(`^ - ${eventType}$`, "m"), eventType);
|
||||
assert.match(isolationYaml, new RegExp(`^ - ${eventType}$`, "m"), eventType);
|
||||
}
|
||||
|
||||
assert.match(yaml, /^ terraform-isolation:\n/m);
|
||||
assert.doesNotMatch(
|
||||
yaml,
|
||||
/github\.event\.action != 'labeled'/,
|
||||
"skipping other jobs on label events would report required checks as success",
|
||||
);
|
||||
assert.doesNotMatch(ciYaml, /^ - labeled$/m);
|
||||
assert.doesNotMatch(ciYaml, /^ - unlabeled$/m);
|
||||
assert.doesNotMatch(ciYaml, /^ terraform-isolation:\n/m);
|
||||
assert.doesNotMatch(ciYaml, /github\.event\.action != 'labeled'/);
|
||||
|
||||
const isolation = yaml.split(/^ terraform-isolation:\n/m)[1]?.split(/^ [a-z]/m)[0] ?? "";
|
||||
assert.match(isolation, /if: github\.event_name == 'pull_request'/);
|
||||
assert.match(isolationYaml, /^ terraform-isolation:\n/m);
|
||||
assert.match(isolationYaml, /name: Terraform and application changes are isolated/);
|
||||
assert.doesNotMatch(isolationYaml, /github\.event\.action != 'labeled'/);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -218,14 +218,14 @@ the labels. Push-to-`dev` releases return behind the repository variable
|
|||
|
||||
- **Terraform-only PRs.** A PR that changes `terraform/**` may not change
|
||||
deployable application code. The `terraform-isolation` job in
|
||||
`.github/workflows/ci.yaml` enforces this; documentation and the
|
||||
`.github/workflows/terraform-isolation.yaml` enforces this; documentation and the
|
||||
`scripts/*terraform*` tooling are allowed alongside. A reviewer may add the
|
||||
`terraform-isolation-override` label for the rare change that must introduce
|
||||
Terraform variables together with the workflow that consumes them (PR C).
|
||||
Adding or removing that label re-runs the Frontend checks workflow,
|
||||
including `terraform-isolation`, against the labels currently on the PR.
|
||||
Removing the label fails a mixed PR that had previously passed with the
|
||||
override, so a stale green check cannot merge. Markdown under `terraform/` does not count as a Terraform
|
||||
Adding or removing that label re-runs only that workflow against the labels
|
||||
currently on the PR; Frontend checks does not start a new run. Removing the
|
||||
label fails a mixed PR that had previously passed with the override, so a
|
||||
stale green check cannot merge. Markdown under `terraform/` does not count as a Terraform
|
||||
change for this gate; it does not match the workspace trigger patterns.
|
||||
The label is the approval record. The override is temporary:
|
||||
a follow-up PR after PR C removes the label path from the checker and
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue