diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b77321ec..03da78dd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,9 +21,13 @@ jobs: # React-shipping packages via eslint-plugin-react-hooks. The backlog has been # cleared, so this is a required gate: any new finding fails the check. steps: - - uses: actions/checkout@v5 - with: - persist-credentials: false + # Every step in this file carries a distinct `name:`. Four jobs check out + # with byte-identical `uses:` blocks, so unnamed steps give reviewers (and + # tools applying line-anchored review suggestions) no way to tell them + # apart — that ambiguity is how a duplicate `with:` key landed in this job + # in #92 and broke the whole workflow. + - name: Check out repository (react-lint) + uses: actions/checkout@v5 with: persist-credentials: false @@ -32,7 +36,8 @@ jobs: with: run_install: false - - uses: actions/setup-node@v5 + - name: Setup Node + uses: actions/setup-node@v5 with: node-version: '24.14.1' cache: 'pnpm' @@ -53,7 +58,8 @@ jobs: # tests are intentionally out of scope (still carry findings), so this gate is # narrower than `pnpm lint` (biome check .). steps: - - uses: actions/checkout@v5 + - name: Check out repository (biome-lint) + uses: actions/checkout@v5 with: persist-credentials: false @@ -62,7 +68,8 @@ jobs: with: run_install: false - - uses: actions/setup-node@v5 + - name: Setup Node + uses: actions/setup-node@v5 with: node-version: '24.14.1' cache: 'pnpm' @@ -76,19 +83,22 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - name: Check out repository (test) + uses: actions/checkout@v5 - name: Setup pnpm uses: pnpm/action-setup@v5 with: run_install: false - - uses: actions/setup-node@v5 + - name: Setup Node + uses: actions/setup-node@v5 with: node-version: '24.14.1' cache: 'pnpm' - - uses: astral-sh/setup-uv@v7 + - name: Setup uv + uses: astral-sh/setup-uv@v7 with: version: "latest" @@ -141,7 +151,7 @@ jobs: # Wait for server to be ready (up to ~30s) # Check both root and a fixture path to ensure server is fully ready - for i in {1..30}; do + for _ in {1..30}; do if curl -sSf http://localhost:38473/ >/dev/null && \ curl -sSf http://localhost:38473/v0.5.0/blobs.zarr/zmetadata >/dev/null; then echo "Test server is up and serving fixtures" @@ -165,7 +175,8 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v5 + - name: Check out repository (production-browser) + uses: actions/checkout@v5 with: persist-credentials: false @@ -174,12 +185,14 @@ jobs: with: run_install: false - - uses: actions/setup-node@v5 + - name: Setup Node + uses: actions/setup-node@v5 with: node-version: '24.14.1' cache: 'pnpm' - - uses: astral-sh/setup-uv@v7 + - name: Setup uv + uses: astral-sh/setup-uv@v7 with: version: "latest" @@ -195,7 +208,10 @@ jobs: - name: Generate test fixtures (Python spatialdata 0.7.2) if: steps.cache-production-browser-fixtures.outputs.cache-hit != 'true' - run: pnpm test:fixtures:generate:0.7.2 -- --output-dir test-fixtures-production-browser + # No `--` before the flags: pnpm forwards the separator through to the + # script verbatim, and argparse treats everything after a bare `--` as + # positional, so `-- --output-dir X` fails with "unrecognized arguments". + run: pnpm test:fixtures:generate:0.7.2 --output-dir test-fixtures-production-browser - name: Expose production browser fixtures run: ln -s test-fixtures-production-browser test-fixtures diff --git a/.github/workflows/workflow-lint.yml b/.github/workflows/workflow-lint.yml new file mode 100644 index 00000000..c914db6c --- /dev/null +++ b/.github/workflows/workflow-lint.yml @@ -0,0 +1,44 @@ +name: Workflow Lint + +# Deliberately a SEPARATE workflow file, and it must stay that way. +# +# A workflow cannot validate itself. Once a file stops parsing, GitHub can no +# longer evaluate its `on:` triggers, so none of its own jobs run — the failure +# surfaces only as a 0-second run with no jobs and no logs, which reads like +# infra flake rather than a broken file. That is exactly how a duplicate `with:` +# key reached main in #92: the PR's last green check predated the bad edit, and +# nothing re-ran to contradict it. +# +# This file parses independently of the others, so it still runs when they are +# broken and reports a real annotation with a file:line. + +on: + push: + branches: + - main + pull_request: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + actionlint: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Check out repository (workflow-lint) + uses: actions/checkout@v5 + with: + persist-credentials: false + + # actionlint covers both halves of the problem: a strict YAML syntax check + # (duplicate keys, bad indentation — the things GitHub silently rejects) + # and semantic checks on top (unknown `uses:` refs, invalid expressions, + # shellcheck over `run:` blocks). Pinned to an exact version: this gate is + # meant to fail on our mistakes, not on a linter release. + - name: Lint workflow files (actionlint) + uses: docker://rhysd/actionlint:1.7.12