Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 2 additions & 25 deletions .github/workflows/ci-frontend-lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,35 +133,12 @@ jobs:
# esbuild ship per-platform binaries as optionalDependencies).
run: bun install --frozen-lockfile --ignore-scripts

# src/v1 is excluded here: its checks run, and report, separately in
# ci-frontend-v1.yaml and ci-frontend-v1-seam.yaml.
- name: Run TypeScript typecheck
working-directory: frontend
run: bun run typecheck

# src/v1 is excluded from the step above and checked under its own
# stricter tsconfig, after scripts/check-v1.mjs checks file types,
# placement, symlinks and the folder taxonomy.
- name: Run v1 typecheck
working-directory: frontend
run: bun run typecheck:v1

# Biome on src/v1, then scripts/check-v1.mjs: the folder import
# contract, v0 reaching v1 only through `@v1`, PropTypes and `ant-`.
- name: Run v1 lint
working-directory: frontend
run: bun run lint:v1

# The guardrail fixtures run under `node --test` (Node 22 APIs).
- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "22"

# v1 unit tests, then the fixtures proving each guard above fails and
# passes when it should.
- name: Run v1 tests
working-directory: frontend
run: bun run test:v1

# ci-test.yaml runs the same suite as the rig's `frontend` group, but its
# tiers skip frontend-only PRs; this job is what gates those.
vitest:
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/ci-frontend-v1-seam.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Frontend v1 seam

# Seam guard (P0-T10, UN-4363): until Phase 9, a PR that is frontend v1 work
# may change v0 only at the files in frontend/scripts/v1-seam-allowlist.json.
# A PR that touches no v1 file is v0 work and passes untouched.
#
# The `v0-change` label lets v1 work that genuinely needs a v0 change through;
# the guard then lists the files instead of failing. Its own workflow, because
# it re-runs on label changes and nothing else needs to.

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
branches: [main]

permissions:
contents: read

jobs:
seam:
name: v1 · Seam
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
# The merge base with the PR's base branch must be reachable.
fetch-depth: 0

- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "22"

# Node built-ins only, so no install step.
- name: Run the seam guard
working-directory: frontend
env:
BASE_REF: ${{ github.base_ref }}
OVERRIDE: ${{ contains(github.event.pull_request.labels.*.name, 'v0-change') && '--override' || '' }}
run: node scripts/check-v1-seam.mjs --base "origin/$BASE_REF" $OVERRIDE
224 changes: 224 additions & 0 deletions .github/workflows/ci-frontend-v1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
name: Frontend v1 checks

# The frontend v1 rules as PR checks (P0-T10, UN-4363), reported apart from
# v0's checks in ci-frontend-lint.yaml. Each guard is its own job so a PR shows
# which rule failed by name. Every guard has fixture cases in
# frontend/test-fixtures/v1-boundary/ proving it fails when it should; the
# "Guard fixtures" job runs them.
#
# The seam guard reads PR labels, so it lives in ci-frontend-v1-seam.yaml:
# re-running these jobs on every label change would cost minutes for nothing.
#
# This workflow runs on a clean checkout of the public repository, with no
# cloud overlay, so a green Build job is the separation guard's "v1 builds
# with no overlay" half.

on:
push:
branches:
- main
paths:
- "frontend/**"
# No `paths` on pull_request: an untriggered workflow reports no check run,
# so a required check would wait forever on non-frontend PRs. Filtering is
# done by the `changes` job instead; a job skipped via `if:` reports
# `skipped`, which satisfies a required check. Same as ci-frontend-lint.yaml.
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches: [main]

permissions:
contents: read

jobs:
# Gating jobs run when `changes` finds frontend files, AND whenever `changes`
# itself did not succeed: a broken filter must fail open (run the checks),
# never skip them. `!cancelled()` lets them run past a failed dependency.
changes:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
permissions:
contents: read
# dorny/paths-filter lists PR files via the API.
pull-requests: read
outputs:
# Push is already path-filtered by its trigger, so force true off-PR.
frontend: ${{ github.event_name != 'pull_request' || steps.filter.outputs.frontend == 'true' }}
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Check for frontend changes
if: github.event_name == 'pull_request'
uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 # v4.0.2
id: filter
with:
filters: |
frontend:
- "frontend/**"

# Biome's recommended rules and the accessibility rules as errors: biome.json
# raises the a11y rules for src/v1, and --error-on-warnings turns every
# remaining warning under src/v1 into a failure.
biome:
name: v1 · Biome
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Biome
uses: biomejs/setup-biome@4c91541eaada48f67d7dbd7833600ce162b68f51 # v2.7.1
with:
version: "2.3.13"

- name: Run Biome on src/v1
working-directory: frontend
run: biome ci --error-on-warnings src/v1/

typecheck:
name: v1 · Typecheck
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Install dependencies
working-directory: frontend
# No dependency lifecycle scripts: nothing here needs them.
run: bun install --frozen-lockfile --ignore-scripts

# scripts/check-v1.mjs --files (TypeScript only, styles only in styles/,
# allowed file types, no symlinks, folder taxonomy), then strict tsc.
- name: Run v1 typecheck
working-directory: frontend
run: bun run typecheck:v1

# No shim, antd, `ant-` class, CSS file, inline style, PropTypes or JS file
# under v1, plus the folder import contract and the styling policy. The JS
# and CSS-file rules run in the Typecheck job (check-v1 --files).
purity:
name: v1 · Purity
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Install dependencies
working-directory: frontend
run: bun install --frozen-lockfile --ignore-scripts

- name: Run the import and purity checks
working-directory: frontend
run: node scripts/check-v1.mjs --code

- name: Run the styling policy
working-directory: frontend
run: node scripts/check-v1-styles.mjs

# The v1 unit tests. P0-T08 (UN-4329) replaces this with the frontend-v1
# unit group.
unit:
name: v1 · Unit tests
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Install dependencies
working-directory: frontend
run: bun install --frozen-lockfile --ignore-scripts

- name: Run v1 unit tests
working-directory: frontend
# The lockfile's vitest, never a fetched one.
run: ./node_modules/.bin/vitest run --dir src/v1 --passWithNoTests

# One production build, then the bundle guard (no v1 chunk loads v0 or
# antd) and the separation guard (no enterprise plugin code in this repo).
build:
name: v1 · Build, bundle and separation
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "22"

- name: Install dependencies
working-directory: frontend
run: bun install --frozen-lockfile --ignore-scripts

- name: Build and run the bundle guard
working-directory: frontend
run: node scripts/check-v1-bundle.mjs

- name: Run the separation guard
working-directory: frontend
run: node scripts/check-v1-separation.mjs

# Proves every guard above fails and passes when it should (node --test,
# Node 22 APIs). Spawns the real tools, two small Vite builds included.
guard-fixtures:
name: v1 · Guard fixtures
needs: changes
if: ${{ !cancelled() && github.event.pull_request.draft != true && (needs.changes.result != 'success' || needs.changes.outputs.frontend == 'true') }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

- name: Setup Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "22"

- name: Install dependencies
working-directory: frontend
run: bun install --frozen-lockfile --ignore-scripts

- name: Run the guard fixtures
working-directory: frontend
run: node --test test-fixtures/v1-boundary/boundary.fixtures.mjs
13 changes: 13 additions & 0 deletions frontend/biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,19 @@
}
}
},
"a11y": {
"noLabelWithoutControl": "error",
"noNoninteractiveElementInteractions": "error",
"noRedundantRoles": "error",
"noStaticElementInteractions": "error",
"useAriaPropsSupportedByRole": "error",
"useButtonType": "error",
"useFocusableInteractive": "error",
"useGenericFontNames": "error",
"useKeyWithClickEvents": "error",
"useSemanticElements": "error",
"useValidAnchor": "error"
},
"suspicious": {
"noExplicitAny": "error"
}
Expand Down
7 changes: 5 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,11 @@
"typecheck": "tsc --noEmit",
"tokens:v1": "bun scripts/build-v1-tokens.mjs",
"typecheck:v1": "node scripts/check-v1.mjs --files && tsc -p src/v1/tsconfig.json",
"lint:v1": "biome lint src/v1/ && node scripts/check-v1.mjs --code && node scripts/check-v1-styles.mjs",
"test:v1": "vitest run --dir src/v1 --passWithNoTests && node --test test-fixtures/v1-boundary/boundary.fixtures.mjs"
"lint:v1": "biome lint --error-on-warnings src/v1/ && node scripts/check-v1.mjs --code && node scripts/check-v1-styles.mjs",
"test:v1": "vitest run --dir src/v1 --passWithNoTests && node --test test-fixtures/v1-boundary/boundary.fixtures.mjs",
"seam:v1": "node scripts/check-v1-seam.mjs --base origin/main",
"separation:v1": "node scripts/check-v1-separation.mjs",
"bundle:v1": "node scripts/check-v1-bundle.mjs"
},
"browserslist": {
"production": [
Expand Down
Loading
Loading