Skip to content

ci: move GitHub Actions to their Node 24 majors - #143

Merged
mmcky merged 1 commit into
mainfrom
maint/node24-actions
Sep 18, 2026
Merged

mmcky merged 1 commit into
mainfrom
maint/node24-actions

Conversation

@mmcky

@mmcky mmcky commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Moves every action pin in this repository's four workflows onto its Node 24 major, rewrites the refresh-snapshots notifier so it survives the download-artifact v5+ layout change, and adds a grouped weekly Dependabot config for GitHub Actions. Node 20 reached end-of-life on 2026-04-30; this is data-lectures' part of the fleet-wide Node 24 upgrade approved on 2026-09-18.

Pins

Action From To Runtime (from -> to) Where
actions/checkout v4 v7 node20 -> node24 all four workflows (6 uses)
actions/setup-python v5 v7 node20 -> node24 all four workflows (6 uses)
actions/upload-artifact v4 v7 node20 -> node24 refresh-snapshots, canary
actions/download-artifact v4 v8 node20 -> node24 refresh-snapshots, notify
actions/upload-pages-artifact v3 v5 composite wrapping node20 upload-artifact -> composite wrapping upload-artifact v7.0.0 (node24) audit-dashboard, build
actions/configure-pages v5 v6 node20 -> node24 audit-dashboard, deploy
actions/deploy-pages v4 v5 node20 -> node24 audit-dashboard, deploy

Each target's action.yml was read at its ref and declares runs.using: node24; upload-pages-artifact v5 is a composite whose only inner uses: is upload-artifact v7.0.0, also node24. Nothing is held back here: the fleet's one kept-back action (rossjrw/pr-preview-action, kept until its upstream node24 release, review date 2026-10-31) is not used in this repository, and no workflow here sets a job-level node-version.

The notifier break, and the change

From v5, download-artifact extracts straight into path/ whenever a download matches exactly one artifact. The condition in src/download-artifact.ts at v8 is isSingleArtifactDownload || inputs.mergeMultiple || artifacts.length === 1, so it covers pattern: downloads too, not only artifact-ids. The notify job downloads pattern: canary-failure-* into failures/ and walked failures/*/. When exactly one canary leg fails, which is the usual case (both failing runs behind #115 on 2026-09-01 were the single us_business_cycle_monthly.csv leg), failure.json and builder.log land in failures/ itself, the glob finds no subfolder, and the upstream-break issue is filed with only its boilerplate: no dataset, no classification, no log. Nothing errors, so notify stays green while the alarm loses its content.

No input restores a per-artifact folder for a single artifact in v5+, so the change is on the reading side. The loop now takes its directories from find failures -type f -name failure.json -exec dirname {} \; | sort and reads builder.log beside each failure.json. That does not depend on the layout: one artifact unpacked flat yields failures, several yield one failures/<name> each, and no artifact at all (plan failed, or a leg failed before its builder ran) leaves no failures/ and yields nothing, as the old glob did. sort keeps the old glob's alphabetical order, and the loop body is unchanged.

Local test of the notifier in both layouts

The notify step's run: script was extracted straight from the workflow YAML, both this branch's version and main's, and each was run with bash -e (the runner's default for a step with no shell:), with gh stubbed to log its calls and report no open issue. The fixtures were written exactly as the canary step writes them: the same jq -n call for failure.json, plus a three-line fake builder.log. The test ran on macOS (bash 3.2, BSD find); the runner has bash 5 and GNU find, and the script uses nothing that differs between them (process substitution, while read, find -type f -name -exec dirname). shellcheck reports nothing.

Layout Files main (glob) this branch (find)
one artifact, unpacked flat (v5+, one leg failed) failures/failure.json, failures/builder.log exit 0, 0 failure sections, 0 log excerpts exit 0, 1 section, 1 log excerpt
two artifacts, one subfolder each failures/canary-failure-gdp_growth_annual/{failure.json,builder.log}, failures/canary-failure-us_business_cycle_monthly/{failure.json,builder.log} exit 0, 2 sections, 2 log excerpts exit 0, 2 sections, 2 log excerpts
no artifact no failures/ exit 0, 0 sections exit 0, 0 sections

In every case the stub recorded the same three calls: gh label create upstream-break ..., gh issue list --label upstream-break ... and gh issue create ... --body-file body.md. The generated body.md files follow.

main, one artifact unpacked flat: the break (the issue carries no details)
The weekly sources-alive canary failed. Nothing was written: every consumer keeps reading the last-good snapshot, so no lecture is affected — this is the alarm moving from the lecture repos' CI to here, doing its job.

Run: https://github.com/QuantEcon/data-lectures/actions/runs/0000000000

_Posted automatically. Later failures comment here rather than opening new issues, so close this once the canary is green._
This branch, one artifact unpacked flat
The weekly sources-alive canary failed. Nothing was written: every consumer keeps reading the last-good snapshot, so no lecture is affected — this is the alarm moving from the lecture repos' CI to here, doing its job.

### `us_business_cycle_monthly.csv` — **fetch failed** (exit 1) — the upstream or the network, not the data. Re-run the workflow; if it fails again, the source has moved or gone.

Builder: `builders/business_cycle_fred.py`. Last lines of its log:

```
fetching us_business_cycle_monthly.csv
Traceback (most recent call last):
TimeoutError: The read operation timed out (fake log for us_business_cycle_monthly.csv)
```

Run: https://github.com/QuantEcon/data-lectures/actions/runs/0000000000

_Posted automatically. Later failures comment here rather than opening new issues, so close this once the canary is green._
This branch, two artifacts in subfolders
The weekly sources-alive canary failed. Nothing was written: every consumer keeps reading the last-good snapshot, so no lecture is affected — this is the alarm moving from the lecture repos' CI to here, doing its job.

### `gdp_growth_annual.csv` — **validation failed** (exit 2) — the fetched data broke the published contract. A human decides: absorb the upstream change in the builder's `pre_process` stage so the published schema is unchanged, or, if it cannot honestly be absorbed, plan a new-filename vintage (AGENTS.md, "Refresh, break, or schema change").

Builder: `builders/business_cycle.py`. Last lines of its log:

```
fetching gdp_growth_annual.csv
Traceback (most recent call last):
TimeoutError: The read operation timed out (fake log for gdp_growth_annual.csv)
```

### `us_business_cycle_monthly.csv` — **fetch failed** (exit 1) — the upstream or the network, not the data. Re-run the workflow; if it fails again, the source has moved or gone.

Builder: `builders/business_cycle_fred.py`. Last lines of its log:

```
fetching us_business_cycle_monthly.csv
Traceback (most recent call last):
TimeoutError: The read operation timed out (fake log for us_business_cycle_monthly.csv)
```

Run: https://github.com/QuantEcon/data-lectures/actions/runs/0000000000

_Posted automatically. Later failures comment here rather than opening new issues, so close this once the canary is green._

Other checks

  • upload-pages-artifact v4+ drops dotfiles unless include-hidden-files: true. The last deployed Pages artifact (run 34809670165, 2026-09-14) archived 94 entries under v3 and none is a dotfile, and Pages uses the workflow build type, so no .nojekyll is needed. This PR's build job archived the same 94 entries under v5 (the two tar listings are identical), so nothing is lost.
  • checkout v7. The refresh job pushes with the token checkout persists. From v6 that token lives in a file under $RUNNER_TEMP that git config includes, which git push in the workspace still reads; nothing here reads the extraheader. The v7 fork-PR block applies only to pull_request_target and workflow_run, which no workflow here uses.
  • setup-python v7 removes only pip-install, which nothing here uses; every step sets python-version: "3.12".
  • upload-artifact v7 / download-artifact v8. Artifact names stay unique per leg (canary-failure-<stem>). v8 fails on a digest mismatch, which is right for an artifact from the same run.

Dependabot

Adds .github/dependabot.yml: the github-actions ecosystem, weekly, with two groups (minor and patch together, majors separately) as QuantEcon/actions does, the ⬆️ commit prefix the lecture repositories use, and open-pull-requests-limit: 10. There is no conda stanza because this repository has no environment.yml. This is data-lectures' half of the first rider in QuantEcon/workspace-lectures#59; the lecture-wasm PR carries the other half.

What CI proves

This PR's own CI runs validate-datasets.yml (both pandas legs), consumed-file-check.yml (the required consumed-files check) and the build job of audit-dashboard.yml (its pull_request paths filter includes the workflow itself), which between them exercise checkout v7, setup-python v7 and upload-pages-artifact v5. PR check results, all on 7259977: validate (pandas 2.3.3) pass, validate (pandas 3.0.5) pass, consumed-files pass, build (audit-dashboard) pass; deploy and notify skipped, as they always are on a pull request. The run logs show the runner fetching checkout@v7, setup-python@v7, upload-pages-artifact@v5 and its inner upload-artifact v7.0.0, and no job carries a Node 20 deprecation annotation (the only annotation is GitHub's notice about ubuntu-latest moving to Ubuntu 26).

Dispatched on this branch: refresh-snapshots.yml, run 35319536981, green. plan and both canary legs (gdp_growth_annual.csv, us_business_cycle_monthly.csv) ran on checkout v7 and setup-python v7 with no Node 20 deprecation warning; main's last scheduled run (34815181947) carried three. notify and refresh were skipped, as expected: a green run does not exercise the notifier, and nothing was due, so no refresh PR could be opened from this branch.

Proven only after merge:

  • configure-pages v6 and deploy-pages v5, in the deploy job of audit-dashboard.yml, which runs only on push to main, the weekly schedule or a dispatch. The merge run deploys the dashboard; it was not dispatched from this branch because that would publish a non-main build to the live site.
  • upload-artifact v7 (canary) and download-artifact v8 plus the new loop (notify), which run only when a canary leg fails. The local test above covers the reading logic in both layouts; the first real failure proves the rest.
  • The refresh job (checkout v7 with the persisted token, then git push), which runs only when a dataset is due. The next is us_business_cycle_monthly.csv, at the first scheduled run on or after 2026-10-01.

🤖 Generated with Claude Code

Node 20 reached end-of-life on 2026-04-30, and these pins are all
node20 (upload-pages-artifact v3 wraps node20 upload-artifact):

  actions/checkout               v4 -> v7  (6 uses, 4 files)
  actions/setup-python           v5 -> v7  (6 uses, 4 files)
  actions/upload-artifact        v4 -> v7  (refresh-snapshots)
  actions/download-artifact      v4 -> v8  (refresh-snapshots)
  actions/upload-pages-artifact  v3 -> v5  (audit-dashboard)
  actions/configure-pages        v5 -> v6  (audit-dashboard)
  actions/deploy-pages           v4 -> v5  (audit-dashboard)

refresh-snapshots notify: download-artifact v5+ unpacks a download
that resolves to exactly one artifact straight into path/, with no
<name>/ folder, and that includes pattern: downloads. When one canary
leg fails (the usual case, as on 2026-09-01) failure.json and
builder.log land in failures/ itself, `for dir in failures/*/` finds
nothing, and the upstream-break issue is filed without its details,
with nothing erroring. The loop now finds each failure.json wherever
it landed and reads builder.log beside it, so it no longer depends
on the layout.

upload-pages-artifact v4+ drops dotfiles by default; the last deployed
Pages artifact (94 entries) had none, so nothing is lost.

Also adds a grouped weekly github-actions Dependabot config (the repo
had none), in the form QuantEcon/actions uses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 18, 2026 07:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The workflow pin updates are consistent across the repo’s workflows and the notifier change correctly handles both single- and multi-artifact extraction layouts without introducing YAML or shell-script errors.

Pull request overview

This PR updates the repository’s GitHub Actions workflow pins to the Node 24–based major versions and adjusts the refresh-snapshots notifier logic to handle actions/download-artifact’s v5+ single-artifact extraction layout, plus adds a Dependabot configuration to keep GitHub Actions pins current.

Changes:

  • Bump actions/checkout and actions/setup-python pins across all workflows to their Node 24 majors.
  • Bump artifact/pages actions majors and update the refresh-snapshots notify script to locate failure.json regardless of whether artifacts extract into failures/ or failures/<artifact>/.
  • Add grouped weekly Dependabot updates for the github-actions ecosystem.
File summaries
File Description
.github/workflows/validate-datasets.yml Updates action pins to Node 24 majors for the dataset validation matrix workflow.
.github/workflows/refresh-snapshots.yml Updates action pins and fixes notifier artifact discovery to be robust to download-artifact v5+ layout.
.github/workflows/consumed-file-check.yml Updates action pins to Node 24 majors for integrity and catalog freshness checks.
.github/workflows/audit-dashboard.yml Updates action pins (including Pages actions) to Node 24 majors for dashboard build/deploy.
.github/dependabot.yml Adds grouped weekly Dependabot updates for GitHub Actions pins.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@mmcky
mmcky merged commit ab9d24d into main Sep 18, 2026
12 checks passed
@mmcky
mmcky deleted the maint/node24-actions branch September 18, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants