name: Frontend checks on: pull_request: branches: [main, dev, staging] push: branches: [main, dev, staging] workflow_dispatch: {} permissions: contents: read jobs: build-and-test: name: Build and test # Org reusable workflow (Node 24): format check, lint, build, unit tests. uses: Sea-Haven-Industries/.github/.github/workflows/ci-typescript-frontend.yaml@af0f002e14a08cdbfd879c1183bfe7eb2604bce9 # v1.0.8 with: node-version: "24" governance: # Repo-owned guarantee that every frontend quality gate runs from this # repository, independent of (and in addition to) the reusable workflow. # `npm run verify` is the single command that chains: format check, lint # (--max-warnings=0), type-check + build, unit tests, then the governance # checks in scripts/governance-check.mjs (godfile ratchet, changed-file # maintainability gate, Terraform fmt/validate, Terraform import-plan guard # tests, Terraform isolation gate tests, CDK build/test/synth). If the # reusable workflow is later confirmed to run every gate, this job can be # slimmed to `npm run governance`. # # GOVERNANCE_BASE points the changed-file gate at the right diff: # PR -> the PR target branch (origin/) # push-> the previous commit on the branch (github.event.before) # manual -> dev, for exact-head recovery runs runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Resolve governance comparison ref id: governance-ref shell: bash env: EVENT_NAME: ${{ github.event_name }} EVENT_BEFORE: ${{ github.event.before }} PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} run: | set -euo pipefail if [[ "${EVENT_NAME}" == "pull_request" ]]; then base="${PR_BASE_SHA}" elif [[ "${EVENT_NAME}" == "push" && -n "${EVENT_BEFORE}" && ! "${EVENT_BEFORE}" =~ ^0+$ ]]; then base="${EVENT_BEFORE}" else base="origin/dev" fi printf 'base=%s\n' "${base}" >> "${GITHUB_OUTPUT}" - name: Set up Terraform # Same minor as the HCP workspace (1.16.x) so fmt/validate see what # the remote run will see. uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1 with: terraform_version: "1.16.0" terraform_wrapper: false - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "24" cache: npm - run: npm ci - run: npm run verify 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; it is # read when the job runs, so re-run this workflow after labeling. 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 container: mcr.microsoft.com/playwright:v1.61.1-noble steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "24" cache: npm - run: npm ci - run: npm run test:e2e:visual - name: Upload visual diff artifacts if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: visual-regression-diffs path: | test-results/visual playwright-report-visual if-no-files-found: ignore retention-days: 14