diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 79c943a..eec371f 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,4 +1,9 @@ name: CI +# Gitea Actions CI/CD +# +# Runs typecheck, tests, and feed sanity checks; builds the site; and publishes +# the container image to Gitea's registry. Scheduled source refreshes are +# handled by .gitea/workflows/refresh.yml. on: push: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e746fe1..a0beb13 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,9 @@ name: CI +# GitHub Actions CI/CD +# +# GitHub only needs to build and serve (deploying to GitHub Pages), not refresh +# data sources. Scheduled fetching and snapshot refresh run exclusively on +# Gitea Actions (.gitea/workflows/refresh.yml). on: push: diff --git a/AGENTS.md b/AGENTS.md index cc67389..4781f38 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,8 +41,11 @@ progress on events that repeat daily, and lets a user mark events completed. twenty games, the full interface, offline support, a static server, a Docker image and CI all exist and are tested. The refresh runner (`bun run refresh`) fetches, caches raw snapshots and rebuilds the feed; `.gitea/workflows/refresh.yml` runs it twice a day and commits only when a page actually -changed. The SQLite layer and the review queue are still specified in `docs/` but not built, so the -feed is a static JSON file built from snapshots, falling back to checked-in fixtures. +changed. GitHub only needs to build and serve (deploying to GitHub Pages via +`.github/workflows/ci.yml`), not refresh data sources; scheduled fetching and container image +publishing run exclusively on Gitea Actions. The SQLite layer and the review queue are still +specified in `docs/` but not built, so the feed is a static JSON file built from snapshots, +falling back to checked-in fixtures. ## Three constraints that shape everything diff --git a/README.md b/README.md index 094b5d3..96554b8 100644 --- a/README.md +++ b/README.md @@ -388,13 +388,12 @@ pipeline always means the code changed rather than a wiki being down. ### Refreshing the data -Gitea Actions only — the GitLab and GitHub pipelines run the gates / builds, but do not fetch wikis. -`.gitea/workflows/refresh.yml` runs `bun run refresh` twice a day (and on demand, with a dry-run -input). It fetches each source at most once per cycle, and **commits only when a page's bytes -actually changed** — a `304`, an identical body, or a fetch that fails to parse all leave the -working tree clean and produce no commit. When something did change it commits the raw snapshots and -dispatches `ci.yml`, which typechecks, tests, rebuilds the feed and republishes the image through the -path that already existed; none of that logic is duplicated. +Gitea Actions only — GitHub Actions only needs to build and serve (deploying to GitHub Pages), +and never refreshes data sources. `.gitea/workflows/refresh.yml` runs `bun run refresh` twice a +day (and on demand, with a dry-run input). It fetches each source at most once per cycle, and +commits the snapshots when a page's bytes actually changed. On every non-dry run, it dispatches +`ci.yml` so that updated cache confirmations or new snapshots trigger a feed rebuild and +container image publication; none of that logic is duplicated. That dispatch is a REST call rather than `gh workflow run`, there being no `gh` on a Gitea runner. It is also, strictly, belt and braces: unlike GitHub, Gitea does **not** suppress workflow triggers diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index bfee232..91960d1 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -224,7 +224,9 @@ that ordering is load-bearing. `Dockerfile` builds and serves this; the image runs typecheck and tests during build, ships no source or toolchain, and runs unprivileged. `.gitea/workflows/ci.yml` and `.gitlab-ci.yml` run the same -gates and publish it, while `.github/workflows/ci.yml` builds and deploys to GitHub Pages. +gates and publish it, while `.github/workflows/ci.yml` builds and deploys to GitHub Pages. GitHub +only needs to build and serve, not refresh data sources; the scheduled refresh and container image +publishing run exclusively on Gitea Actions. ### Hosting under a subpath diff --git a/docs/INGESTION.md b/docs/INGESTION.md index aad04ed..751361b 100644 --- a/docs/INGESTION.md +++ b/docs/INGESTION.md @@ -394,11 +394,12 @@ annotated on the run page, listed in the job summary with its status code, and c conduct for why that ordering is load-bearing. **Built: `scripts/refresh-sources.ts`** (`bun run refresh`), scheduled by -`.gitea/workflows/refresh.yml`. It takes its adapters, store, robots gate, fetch and clock by -injection, so the whole runner is tested offline against a fake fetch. A fetched body is *rejected* -— the previous snapshot survives — when it fails `canParse`, throws, or yields zero events; storing -an empty parse would make the feed build prefer it over the fixture and silently empty a game's -calendar. +`.gitea/workflows/refresh.yml`. Scheduled fetching and data refresh run exclusively on Gitea +Actions; GitHub Actions only builds and serves, and never refreshes data sources. The runner +takes its adapters, store, robots gate, fetch and clock by injection, so the whole runner is +tested offline against a fake fetch. A fetched body is *rejected* — the previous snapshot survives +— when it fails `canParse`, throws, or yields zero events; storing an empty parse would make the feed +build prefer it over the fixture and silently empty a game's calendar. The one exception is a page that states its own emptiness: when a parser's `statesNoEvents` says the document itself reports listing nothing, the empty parse is stored as that source's real answer and diff --git a/test/refresh.test.ts b/test/refresh.test.ts index 0debee9..b93b67e 100644 --- a/test/refresh.test.ts +++ b/test/refresh.test.ts @@ -1130,6 +1130,13 @@ describe("the workflows that drive the refresh", () => { expect(githubCi).toContain("deploy-pages"); expect(githubCi).toContain("pages:"); }); + + test("GitHub only builds and serves and has no refresh workflow", async () => { + const githubRefresh = Bun.file( + new URL("../.github/workflows/refresh.yml", import.meta.url), + ); + expect(await githubRefresh.exists()).toBe(false); + }); }); describe("flags", () => {