From 135af7bdc24de9d4b43b8b93ec328be572363cfd Mon Sep 17 00:00:00 2001 From: Grantfox Agent <160465301+emirykl@users.noreply.github.com> Date: Thu, 22 Oct 2026 16:01:42 +0300 Subject: [PATCH] ci: add blocking web test typecheck and build job --- .github/workflows/web.yml | 44 +++++++++++++++++++++++++++++++++++++++ docs/CI.md | 13 ++++++++++-- scripts/web-ci.test.mjs | 26 +++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/web.yml create mode 100644 scripts/web-ci.test.mjs diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml new file mode 100644 index 00000000..2f6e7520 --- /dev/null +++ b/.github/workflows/web.yml @@ -0,0 +1,44 @@ +name: Web checks + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + web: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + with: + version: 10.13.1 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + cache: pnpm + + - name: Check web CI configuration + run: node --test scripts/web-ci.test.mjs + + - name: Install JS dependencies + run: pnpm install --frozen-lockfile --ignore-scripts + + - name: Test web + run: pnpm web:test + + - name: Typecheck web + run: pnpm web:typecheck + + - name: Build web + run: pnpm web:build diff --git a/docs/CI.md b/docs/CI.md index 84cc72ae..3cb819d3 100644 --- a/docs/CI.md +++ b/docs/CI.md @@ -1,7 +1,16 @@ # CI and quality gates -This document describes automated checks that protect the TypeScript workspace -(`packages/*` and `services/*`). +This document describes automated checks for the web app and TypeScript +workspaces (`apps/*`, `packages/*`, and `services/*`). + +## Web checks + +The `Web checks` workflow (`.github/workflows/web.yml`) runs on pushes to +`main` and on pull requests. Its single blocking job installs locked JS +dependencies without lifecycle scripts, then runs `pnpm web:test`, +`pnpm web:typecheck`, and `pnpm web:build` in order. Run the same three commands +locally to check `apps/web`; `node --test scripts/web-ci.test.mjs` verifies the +CI job configuration. ## Test coverage gate diff --git a/scripts/web-ci.test.mjs b/scripts/web-ci.test.mjs new file mode 100644 index 00000000..069e5715 --- /dev/null +++ b/scripts/web-ci.test.mjs @@ -0,0 +1,26 @@ +// Copyright (c) 2026 Sub Rosa contributors +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { test } from "node:test"; + +const workflow = readFileSync(new URL("../.github/workflows/web.yml", import.meta.url), "utf8"); +const scripts = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).scripts; + +test("web CI runs all three root checks as blocking steps in one job", () => { + assert.match(workflow, /^ push:\n branches: \[main\]$/m); + assert.match(workflow, /^ pull_request:$/m); + + const job = workflow.match(/^ web:\n([\s\S]*)$/m)?.[1]; + assert.ok(job, "web job must exist"); + assert.doesNotMatch(job, /^ [a-z][\w-]*:/m, "checks must stay in the web job"); + assert.doesNotMatch(job, /\bcontinue-on-error\s*:/, "checks must block on failure"); + assert.match(job, /^ run: pnpm install --frozen-lockfile --ignore-scripts$/m); + + let previousStep = -1; + for (const script of ["web:test", "web:typecheck", "web:build"]) { + assert.ok(scripts[script], `root script ${script} must exist`); + const step = job.indexOf(` run: pnpm ${script}\n`); + assert.ok(step > previousStep, `${script} must run after the preceding check`); + previousStep = step; + } +});