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