Build(deps): Bump the minor-and-patch group with 8 updates #283
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| # `ready_for_review` is not one of the default activity types, and naming any type | |
| # replaces the defaults rather than adding to them — so the three defaults have to | |
| # be written out again alongside it. Without it, a PR opened as a draft and later | |
| # marked ready would sit with no CI run at all until its next push. | |
| pull_request: | |
| types: | |
| - opened | |
| - synchronize | |
| - reopened | |
| - ready_for_review | |
| push: | |
| branches: | |
| - main | |
| permissions: | |
| contents: read | |
| jobs: | |
| quality: | |
| # Named for what the job *is*, not for the steps it currently runs. This string is a | |
| # required status check on `main`, so every rename is a branch protection change made | |
| # in the GitHub settings UI — and a name that enumerates its steps earns one of those | |
| # every time a step is added. `Lint, test and build` lasted exactly as long as it took | |
| # to add a test step. Not `CI`, which the workflow is already called and which would | |
| # render the check as `CI / CI`. | |
| name: Quality | |
| runs-on: ubuntu-latest | |
| # Draft PRs skip CI; marking one ready fires `ready_for_review` and runs it then. | |
| # | |
| # This must stay a job-level condition, not a filter in the `on:` block — and not | |
| # only because draft state is not expressible there. A job skipped by `if:` reports | |
| # Success, whereas a whole workflow skipped by filtering leaves its checks pending, | |
| # blocking the merge. Once this check is required on `main` (#18), the first blocks | |
| # nothing and the second would make every draft unmergeable short of an admin | |
| # override or dropping the requirement. | |
| # | |
| # `!= true` rather than `!github.event.pull_request.draft`: on `push` there is no | |
| # `pull_request` object, so both forms pass, but only this one says why. | |
| if: github.event.pull_request.draft != true | |
| steps: | |
| # Actions are pinned to commit SHAs, not tags: a major-version tag can be | |
| # retargeted. Comments record the version each SHA corresponds to; bump both | |
| # together. | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| # The step below diffs against the base branch, and the default | |
| # `fetch-depth: 1` clones no commit to diff against. | |
| fetch-depth: 0 | |
| # A pull request that changes nothing but Markdown cannot break any of the steps at | |
| # the bottom of this job: no `.md` file is an input to `pnpm lint`, `pnpm test` or | |
| # `next build`, so all three would spend several minutes proving it. Skip them for it. | |
| # | |
| # This is a step condition rather than `paths-ignore` on the `pull_request` | |
| # trigger above, for the same reason the draft skip is a job-level `if:` — see the | |
| # comment on it. `paths-ignore` skips the *workflow*, which leaves its checks | |
| # pending rather than green, and once this check is required on `main` (#18) that | |
| # would make every documentation pull request unmergeable. | |
| # | |
| # Two things this has to get right, both of which fail silently: | |
| # | |
| # - The test is "every changed file is documentation", not "some documentation | |
| # changed". A pull request touching `AGENTS.md` *and* `src/` must run. | |
| # - It is an allowlist, so anything the pattern does not recognise falls through | |
| # to a full build — including a diff that could not be computed at all. The | |
| # cost of a needless build is a few minutes; the cost of a wrongly skipped one | |
| # is a broken `main`. | |
| # | |
| # "Documentation" is `**/*.md` and nothing else. Not because Markdown is prose — | |
| # `AGENTS.md` is instructions to agents, and `.claude/skills/` holds working | |
| # skills — but because the question this job asks is narrower than that: whether | |
| # lint, the tests or the build read the file. Nothing here does. The `scripts/*.sh` sitting | |
| # beside a skill's `SKILL.md` is not matched and so is not skipped, which is the | |
| # right way round. | |
| - name: Look for changes outside documentation | |
| id: scope | |
| if: github.event_name == 'pull_request' | |
| env: | |
| BASE_REF: ${{ github.base_ref }} | |
| run: | | |
| set -euo pipefail | |
| # `--no-renames` is load-bearing, not tidiness. Rename detection is on by | |
| # default, and `--name-only` then prints only the *destination* path — so | |
| # `git mv src/thing.ts docs/thing.md` reports one `.md` file and nothing else, | |
| # and a module leaves `src/` classified as documentation. With the flag, both | |
| # paths are listed and the deleted one forces a build. | |
| if ! changed=$(git diff --name-only --no-renames "origin/$BASE_REF...HEAD"); then | |
| echo "Could not diff against origin/$BASE_REF — building rather than guessing." | |
| echo "docs-only=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "Changed files:" | |
| printf '%s\n' "$changed" | sed 's/^/ /' | |
| # A here-string rather than `printf | grep`, and for the same fail-closed | |
| # reason. `grep -q` exits on its first match; with a list bigger than the pipe | |
| # buffer the writer is still going, takes SIGPIPE and exits 141, and | |
| # `pipefail` reports that 141 instead of grep's 0 — which `!` then reads as | |
| # "no non-Markdown file found". A here-string is not a pipeline, so none of | |
| # that applies. | |
| if [ -n "$changed" ] && ! grep -qv '\.md$' <<<"$changed"; then | |
| echo "Documentation only — skipping install, lint and build." | |
| echo "docs-only=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "docs-only=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| # Every step from here down carries the same condition. An unset output — a `push` | |
| # build, where the step above does not run, or a diff that failed — is not `true`, | |
| # so the default in both cases is to build. | |
| # | |
| # pnpm/action-setup must come before setup-node, or the cache step finds no | |
| # lockfile it understands. Omitting `version` makes the action read | |
| # `packageManager` from package.json, so the pin cannot drift from local dev. | |
| - name: Install pnpm | |
| if: steps.scope.outputs.docs-only != 'true' | |
| uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10 | |
| # Read from `.nvmrc` rather than a literal, so this workflow cannot drift from | |
| # local development or from any other workflow. | |
| - name: Install Node | |
| if: steps.scope.outputs.docs-only != 'true' | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: pnpm | |
| - name: Install dependencies | |
| if: steps.scope.outputs.docs-only != 'true' | |
| run: pnpm install --frozen-lockfile | |
| # `next build` no longer runs ESLint, so lint has to be its own CI step. | |
| - name: Lint | |
| if: steps.scope.outputs.docs-only != 'true' | |
| run: pnpm lint | |
| # Vitest's `src` project only — `pnpm test` is `vitest run --project src`. | |
| # | |
| # The `db` project (`tests/db`, run by `pnpm test:db`) is deliberately not here. | |
| # It asserts the schema's invariants against a running Supabase stack — Postgres, | |
| # PostgREST, GoTrue and Kong in containers — and booting those would turn a fast | |
| # required check into a slow one. Note what the reason is not: this runner does | |
| # have Docker, and an earlier version of this comment said otherwise. The cost is | |
| # minutes, not capability. | |
| # | |
| # It runs in `schema.yml` instead, which is a separate workflow for that reason | |
| # and is not a required check. That is the house pattern rather than a new | |
| # exception — the end-to-end suite is a separate workflow too. | |
| # | |
| # Playwright's end-to-end suite is a separate workflow, and one that is currently | |
| # disabled by hand — so nothing runs Playwright on a pull request at all, and this | |
| # step is not the reason why. Keeping e2e out of this job is still right whatever | |
| # that workflow's state: it builds and serves the app, and this job should stay | |
| # fast enough to be a required check. | |
| - name: Test | |
| if: steps.scope.outputs.docs-only != 'true' | |
| run: pnpm test | |
| - name: Build | |
| if: steps.scope.outputs.docs-only != 'true' | |
| run: pnpm build |