QuantEcon / QuantEcon/actions

testing: publish/preview/cache action logic has no automated tests

Open
#100 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

infrastructure
Dominant language
Shell
Stars
0
Forks
1
Avg merge
32m
Merged PRs (30d)
3

Description

Surfaced by the v0.8.0 validation study.

Problem

Containers are covered end-to-end (build-containers.ymltest-container.yml / test-containers-lectures.yml), and since v0.10.0 so are the cache and environment actions, on the PR's own code. Untested: the publish and preview layer, plus the @v0 sibling-pin chain only a released ref can reach.

Coverage — harness (.github/workflows/test-actions.yml, via uses: ./; bare :N are its lines) / canary (QuantEcon/test-actions-lecture-intro, pinned @v0):

  • restore-jupyter-cache ✅ both cache types × both modes, fail-on-miss firing and staying quiet (:195, :234, :268, :301, :332, :362, :394) / ✅ ci.yml:23
  • setup-environment ✅ standard-mode conda cache, two-run miss→hit chain (:431, :461) / ✅ via build-jupyter-cache
  • build-lectures ✅ real executed HTML build, both directions (:461, :508) / ✅ six call sites in ci.yml, publish.yml
  • build-jupyter-cache ⚠️ runs (:591, :638, :698, :784, :818) but its internal calls execute @v0, not the PR / ✅ cache.yml:27
  • preview-netlify ❌ needs a real deploy target / ⚠️ ci.yml:54, fires only on a PR opened there — no successful deploy between 2026-02-10 and 2026-08-05
  • preview-cloudflare ❌ / ❌ called nowhere — no harness job, no canary call site
  • publish-gh-pages ❌ would publish this repo's own Pages / ⚠️ publish.yml:56, fires only on a publish* tag pushed there — last run 2026-02-10, so v0.7.0–v0.11.1 never went through it

Behind the ❌s: uses: takes no expressions and build-jupyter-cache pins siblings hardcoded (setup-environment@v0 at build-jupyter-cache/action.yml:149; build-lectures@v0 at :164, :174, :184), so that chain is untestable pre-release; the previews and publish-gh-pages need real deploy targets end to end, hence TESTING.md:37 assigns them to the canary — but see stage 1.5 below, which that framing has been writing off. The relevance gate is blind too — the IGNORED list at test-actions.yml:112 misses preview-*/action.yml, so a preview-only PR runs all 15 substantive jobs and reports the required check Action harness: all checks green without running a line of preview code. Publish/preview confidence rests on code review plus production publishes in the lecture repos, which is where this issue started.

Why it matters

A publish or cache regression surfaces only when a real build fails — the layer whose gaps hid #28 (see #83). preview-cloudflare, uncovered everywhere, shipped PR comments linking the per-deployment hash rather than the stable pr-N alias, and a deploy-url returning the alias on one wrangler release and the hash on another; both caught by reading, fixed in v0.11.1 (#131). #105 (preview deploy errors swallowed) is the same shape, still open. Canaries also decay untended: the weekly cache.yml build ran every Sunday to 2026-04-12, missed 16 consecutive Sundays, resumed 2026-08-09 — the first Sunday after activity returned 2026-08-05, the signature of GitHub disabling a schedule after 60 days of repository inactivity. v0.7.0, v0.8.0 and v0.9.0 all shipped in that window, unnoticed.

Stage 1 — shipped

  • A PR-time harness in this repo using ./ local paths, so it exercises the code on the PR rather than a released ref — done in v0.10.0 (#114, #118), extended in v0.11.0 (#120, #122, #124, #127).

17 jobs: a relevance gate (:75), 15 substantive jobs, and harness-summary (:854), whose job name Action harness: all checks is the required check on main. Fixtures are salted per run, jobs assert on outputs and filesystem, and negative jobs unit-build-miss-guard (:301), build-fail-guard (:508), bjc-fail-guard (:638), bjc-abort-guard (:698) stop a swallowed failure passing green. TESTING.md:25 documents it as stage 1. #29's env-test half landed with it — env-seed (:431), env-hit-build (:461), the two-run standard-mode conda miss→hit chain, done under PLAN.md backlog item 9; #29's docs half remains.

  • Make the harness's green honest about what it did not run — naming the un-exercised actions in harness-summary's output is enough.

Stage 2 — make the canary consume the shipped templates

The canary — named in PLAN.md's "Consumers in production" table and TESTING.md:47, superseding QuantEcon/test-lectures from the design proposal comment below — is live, pinned @v0 and runs the full chain, but does not consume templates/ verbatim, so what we ship consumers is validated nowhere.

  • Re-sync the canary's cache.yml, ci.yml and publish.yml from templates/, and keep them synced. Drift: templates/publish.yml triggers on push to main plus workflow_dispatch where the canary's uses a publish* tag, so the trigger we hand consumers is never exercised; templates/cache.yml crons 0 0 * * 0 against the canary's 0 3 * * 0. Also keeps #109's template fixes from re-drifting. Coordinate with #135, which changes the canary's publish trigger too.
  • Detect a silent canary, not only a red one — the 16 missed Sundays produced no signal because absence is indistinguishable from success. (#135 covers a red canary reaching a human, and scheduling; neither addresses liveness.)

Stage 3 — coverage needing a real deploy target

  • preview-netlify — a call site on a real deploy target — the canary deploys real Netlify previews at ci.yml:54, with the tokens it needs.
  • publish-gh-pages — a call site on a real Pages target — the canary publishes at publish.yml:56; that it has not run since 2026-02-10 is a trigger problem, and belongs to #135.
  • preview-cloudflare — the only action with zero coverage in either harness. Needs a Cloudflare Pages project and an API token on the canary, plus a call site: a second preview job in its ci.yml, or a dedicated workflow. Also the action most recently found broken by reading, which argues for doing it first.

Scope boundary

  • Stage 4 — canary on release, green before v0 moves — is now #135: all ten of the canary's action references are @v0, the tag a release moves, so it always exercises the previous release, which no trigger change fixes; #135 proposes a v0-next staging tag.
  • #136 goes further — a floating :latest container, build-time network reads and live Dependabot each make a red there ambiguous — and proposes a frozen fixture repo for the gate role, keeping the canary as the sandbox. Stages 2–3 stay here either way; if #136 lands, the gate fixture is its work.
  • Container fixture gaps (containers/quantecon/tests/minimal-jupyter-book/) stay with #108: those exercise the image, these the action logic.
  • Uncovered even then: the pre-release build-jupyter-cache sibling chain, structurally — #135 narrows the ungated surface rather than closing it; real-scale performance and content diversity, so test-containers-lectures.yml against the three real lecture repos stays as-is; the lecture-jax GPU path, while QuantEcon/lecture-jax#284 is open.
  • QuantEcon/workspace-lectures#31 sequences the lecture family's move to floating @v0 behind this gap; QuantEcon/workspace-lectures#33 is the consumer view of the gating decision.

Stage 1.5 — the deploy-action logic that needs no deploy target

"Needs real deploy targets and secrets" is true of the deploy itself and false of most of what these three actions actually do. The following are pure functions of their inputs, testable in this harness today with no Cloudflare project, no Netlify account, no canary and no #136 fixture repo — and they are the parts that have silently shipped wrong before:

  • Extract the duplicated ~87-line PR-comment renderer from preview-netlify and preview-cloudflare into a shared script (PLAN item 6) and assert the rendered URL paths, including the strip-lectures-dir variants
  • Extract publish-gh-pages' release-asset packaging and assert the tarball, its SHA256 checksum, and the JSON manifest fields against a fixture directory
  • Assert CNAME injection and build-directory validation against a fixture
  • Correct the "needs real deploy targets and secrets" line here and at TESTING.md:37, which currently writes off work that needs neither

This matters more now than when this issue was filed: #135/#136 have moved the real-deploy route behind a new fixture repo that does not exist yet, so the pure-logic half is the only preview/publish coverage reachable in the near term. It also removes the duplication PLAN item 6 tracks, so the extraction pays for itself twice.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with .github/workflows/test-actions.yml, TESTING.md, PLAN.md, and the action files for preview-netlify, preview-cloudflare, and publish-gh-pages. Map the unchecked coverage and existing canary workflows before choosing a stage, coordinating with the referenced issues where required. Done means the relevant pure logic or canary paths are covered and the harness reports untested actions honestly.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, shell
Domain
ci-cd, devops, testing-qa
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.