From fa7f99559a35f81ce8ec696c31c2bdc62567357f Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Fri, 18 Sep 2026 09:57:03 +0200 Subject: [PATCH] fix(ci): dispatch ci to publish feed on refresh even when snapshots return 304 When sources return 304, no git commit is created, but the cache holds updated confirmation timestamps. Publish the refreshed feed unconditionally on non-dry runs so CI rebuilds events.v1.json with fresh confirmation dates. --- .gitea/workflows/refresh.yml | 11 ++++++----- test/refresh.test.ts | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/refresh.yml b/.gitea/workflows/refresh.yml index 4366560..3199652 100644 --- a/.gitea/workflows/refresh.yml +++ b/.gitea/workflows/refresh.yml @@ -183,12 +183,13 @@ jobs: # would have made. Note the difference from GitHub that makes this step # look redundant: Gitea does *not* suppress workflow triggers on a push # made with the Actions token, so the commit above will usually have - # started ci.yml already. Dispatching anyway is deliberate — it is the only - # thing that guarantees publication if that behaviour is ever configured - # off, and a duplicate run is harmless because ci.yml's concurrency group - # is per-ref with cancel-in-progress, so the second supersedes the first. + # Dispatching anyway is deliberate — it guarantees publication even when + # every source returned 304 (so no git commit was made, but the cache holds + # updated confirmation timestamps), and protects against push-triggered + # workflow runs ever being disabled. A duplicate run is harmless because + # ci.yml's concurrency group is per-ref with cancel-in-progress. - name: Publish the refreshed feed - if: steps.diff.outputs.changed == 'true' && inputs.dry_run != true + if: inputs.dry_run != true env: TOKEN: ${{ secrets.GITHUB_TOKEN }} API: ${{ github.server_url }}/api/v1 diff --git a/test/refresh.test.ts b/test/refresh.test.ts index 246a792..0debee9 100644 --- a/test/refresh.test.ts +++ b/test/refresh.test.ts @@ -1085,6 +1085,20 @@ describe("the workflows that drive the refresh", () => { expect(refresh.slice(health)).toContain("exit 1"); }); + test("refresh.yml publishes even when no snapshot bytes changed", async () => { + // A 304 updates lastConfirmedAt in the bookkeeping cache without touching + // git-tracked files. If publishing is gated on `changed == 'true'`, a cycle + // where no wiki moved leaves the deployed feed unbuilt — and two days of + // quiet wikis turns the live calendar stale despite green runs. + const refresh = await read("refresh.yml"); + const publish = refresh.slice( + refresh.indexOf("Publish the refreshed feed"), + refresh.indexOf("Report source health"), + ); + expect(publish).not.toContain("steps.diff.outputs.changed"); + expect(publish).toContain("inputs.dry_run != true"); + }); + test("ci.yml fails a source that parsed nothing, not one whose events ended", async () => { // The total-event floor is blind to one source going to zero while nine // others hold the number up, which shows the reader an empty calendar for