From 224afa9afb5a66f131963141a6b334e91eb750ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sun, 13 Sep 2026 20:23:46 +0000 Subject: [PATCH] :construction_worker: Publish tag coverage to the pages server The build job bind-mounts the shared pages tree (the runner whitelists it via container.valid_volumes) and, on tag pushes, wipes /data/gitea-pages////coverage before copying the c8 report into it. Only this tag's coverage/ is touched; older tags and sibling docs/landing trees are left for manual pruning. Add a `tags: ["*"]` push trigger: a `branches` filter alone matches no tag ref, so the tag-gated publish job (and this coverage step) could never run. Track per-branch coverage as a backlog task. --- .gitea/workflows/ci.yml | 28 ++++++++++++++++++++++++++++ CONTRIBUTING.md | 24 ++++++++++++------------ backlog.tasks | 7 ++++--- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 86048d0..a656110 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -3,6 +3,10 @@ name: CI on: push: branches: [main] + # Releases are tag pushes (`scripts/release.sh` tags bare `x.y.z`). A + # `branches` filter alone matches no tag ref, so without this both the + # tag-gated `publish` job and the coverage publish step never fire. + tags: ["*"] pull_request: branches: [main] workflow_dispatch: {} @@ -10,6 +14,13 @@ on: jobs: build: runs-on: ubuntu-latest + # Bind-mount the shared pages tree so the coverage step below can write + # into it. The runner whitelists this path via `container.valid_volumes` + # (docker-space `setup/gitea.sh`); `image` is omitted on purpose so the + # runner keeps using its default job image. + container: + volumes: + - /data/gitea-pages:/data/gitea-pages steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -20,6 +31,23 @@ jobs: - run: npm run build - run: npm run check - run: npm run test:ci + # Publish this tag's coverage to the self-hosted pages server, + # served read-only at + # https://pages.e1nsnull.de////coverage/. Wipe only + # this tag's `coverage/`, so sibling docs/landing trees and older + # tags survive; pruning stale tags is a manual chore. + - name: Publish coverage to the pages server + if: startsWith(gitea.ref, 'refs/tags/') + env: + REPO: ${{ github.repository }} + REF: ${{ gitea.ref }} + run: | + TAG="${REF#refs/tags/}" + DEST="/data/gitea-pages/${REPO}/${TAG}/coverage" + rm -rf "${DEST}" + mkdir -p "${DEST}" + cp -R coverage/. "${DEST}/" + echo "Coverage: https://pages.e1nsnull.de/${REPO}/${TAG}/coverage/" # Fast, offline packaging gate. `attw` stays in `publish` (it needs # a pack + full resolution matrix); `publint` packs too but is cheap # enough to run on every push so a packaging break fails here, not diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9d76e9e..0501959 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,18 +44,18 @@ Separately, some top-level scripts are **bare** (no prefix): the entry points th The tools are organized into a feedback ladder. Each tier catches different things at different costs; the rule of thumb is "earlier tiers fire more often, faster tiers catch less, slower tiers are more thorough": -| Tier | When | What it runs | Time | -| -------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------- | ----- | -| `npm run watch` | manual | `watch:test` — re-runs tests on file save | ~0.1s | -| Pre-commit (auto) | on stage | tsc + oxlint + oxfmt + cspell (staged files only) | ~1.3s | -| Pre-push (auto) | on push | `npm test` (full tsc + unit tests) | ~3.5s | -| `npm run check` | manual | Correctness gates: tsc + oxlint + oxfmt + cspell (whole project) | ~3s | -| `npm run verify` | manual | Definition of done: `npm run check` + unit tests, one shot | ~6s | -| `npm run fix` | manual | Auto-resolve fixable issues (lint, format) | ~3s | -| `npm run maintain` | manual / CI (advisory) | `maintain:knip` + `maintain:outdated` (whole-project + network scans) | ~10s | -| CI build (auto) | on push to `main` | `build` job (build + correctness + packaging) — see [.gitea/workflows/ci.yml](./.gitea/workflows/ci.yml) | ~30s+ | -| CI maintain (auto, non-blocking) | on push to `main` | `npm run maintain` — reports, never fails the build | ~10s | -| CI publish (auto) | on tag | Gitea release page (body from CHANGELOG) + `publish:publint` + `publish:attw`, then `npm publish` | ~15s | +| Tier | When | What it runs | Time | +| -------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------- | ----- | +| `npm run watch` | manual | `watch:test` — re-runs tests on file save | ~0.1s | +| Pre-commit (auto) | on stage | tsc + oxlint + oxfmt + cspell (staged files only) | ~1.3s | +| Pre-push (auto) | on push | `npm test` (full tsc + unit tests) | ~3.5s | +| `npm run check` | manual | Correctness gates: tsc + oxlint + oxfmt + cspell (whole project) | ~3s | +| `npm run verify` | manual | Definition of done: `npm run check` + unit tests, one shot | ~6s | +| `npm run fix` | manual | Auto-resolve fixable issues (lint, format) | ~3s | +| `npm run maintain` | manual / CI (advisory) | `maintain:knip` + `maintain:outdated` (whole-project + network scans) | ~10s | +| CI build (auto) | on push to `main` / tag | `build` job (build + correctness + packaging) — see [.gitea/workflows/ci.yml](./.gitea/workflows/ci.yml) | ~30s+ | +| CI maintain (auto, non-blocking) | on push to `main` | `npm run maintain` — reports, never fails the build | ~10s | +| CI publish (auto) | on tag | Gitea release page (body from CHANGELOG) + `publish:publint` + `publish:attw`, then `npm publish` | ~15s | ### Why these splits? diff --git a/backlog.tasks b/backlog.tasks index 9c1d968..cbeff09 100644 --- a/backlog.tasks +++ b/backlog.tasks @@ -32,9 +32,10 @@ Documentation: Maintenance: ☐ Serve CI coverage over a tiny self-hosted webserver (replace the zip artifact) @low - ☐ Add a minimal dir-listing webserver to the gitea docker setup (e.g. caddy `file_server browse` reusing the existing reverse proxy, or any single-binary static server, lipanski/docker-static-website) - ☐ CI writes each run's `coverage/` into a shared volume keyed by project + tag (e.g. `/coverage/tiny-pattern-ts//`) - ☐ Browse to `…/coverage///index.html` in the browser; drop the `actions/upload-artifact` coverage step in favour of the shared-dir layout + ✔ Add a minimal dir-listing webserver to the gitea docker setup (e.g. caddy `file_server browse` reusing the existing reverse proxy, or any single-binary static server, lipanski/docker-static-website) @done (9/13/2026, 9:02:37 PM) + ✔ drop the `actions/upload-artifact` coverage step in favour of the shared-dir layout @done (9/13/2026, 10:37:22 PM) + ☐ Explore serving coverage for non-tag pushes (e.g. `main/coverage`, PR previews) @low + ☐ Manually verify the coverage was created on a real tag push (needs main) @low → design: no deploy step in CI; the webserver just exposes the shared directory (decided over Gitea Pages / Codecov — neither confirmed available/ wanted) ☐ serve docs over self hosted server @low ☐ Add a minimal dir-listing webserver to the gitea docker setup for serving docs (reuse existing reverse proxy)