Skip to content

ci(nightly): run on a cron, not on every push to main#4

Merged
jetblk merged 1 commit into
mainfrom
ci/nightly-cron
Jul 17, 2026
Merged

ci(nightly): run on a cron, not on every push to main#4
jetblk merged 1 commit into
mainfrom
ci/nightly-cron

Conversation

@jetblk

@jetblk jetblk commented Jul 17, 2026

Copy link
Copy Markdown
Owner

The nightly was a nightly in name only: push: branches: [main] built on every merge — 9 permanent releases today for one day of work. A day of merges should land in one build.

What changed

  • schedule: "37 6 * * *" (02:37 EDT / 01:37 EST), push trigger removed. The offset minute is deliberate — crons on the hour queue behind GitHub's peak load and get delayed or dropped.
  • New check_changes gate job. A scheduled run builds only if main gained a non-docs commit since the last nightly, resolved from the rolling release's targetCommitish. Quiet day or docs-only day → no build, no version burned. Costs ~10s (no checkout; uses the compare API).
  • workflow_dispatch bypasses the gate and always builds, so "get my merge onto a node now" needs no force input. The runbook row for it is unchanged.
  • paths-ignore removed — it had to go regardless: path filters only apply to push/pull_request, so under schedule it would have been dead config that silently stopped working. The gate replaces it and is strictly better: it diffs the whole day rather than judging each push alone.
  • No more cancel-in-progress. Publish deletes the nightly release before recreating it; a cancel in that window leaves nodes with no release to pull, and since ExecStartPre is best-effort they would silently keep running a stale build. Run ci(nightly): run on a cron, not on every push to main #4 today was cancelled, so this fires in practice.

Borrowed from upstream release.yml

Upstream has run a real scheduled nightly far longer than we have, and had three things we did not:

  • !failure() && !cancelled() on the build job — this is what lets a skipped gate through while still halting on a broken one. always() would build even when the gate errored. Without this the build job silently never runs.
  • Date from github.run_started_at, not wall-clock date -u: a build starting at 23:59 UTC would otherwise stamp tomorrow.
  • contents: read by default, write only on the job that publishes.

Deliberate divergences: their gate is SHA-equality only (would build on a docs commit) — ours is docs-aware, preserving the paths-ignore intent. Their nightly channel is an npm dist-tag, so they have no rolling-release delete/recreate to protect; ours is fork-local and needs the concurrency fix. Their cron is every 3h — a reminder that nightly upstream means a channel, not a cadence.

Verification

  • Gate logic exercised against the live API on all four paths: HEAD == last nightly → skip; docs-only commit (db3a315d4) → skip; code commit (d106a284d) → build; unreachable SHA → build (fails safe).
  • Dispatched this branch (run 10): check_changesskipped, buildin_progress, confirming the if: expression on a skipped gate. Cancelled before publish, so no release was created.
  • Merging this PR will not itself trigger a build — the pushed commit no longer carries a push trigger. First build under the new regime is tonight's cron, or a dispatch.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ua6eR6J5wHne2wfEd3VF9N

Note

Switch nightly workflow trigger from push to cron schedule

  • Replaces the push-based trigger in nightly-fork.yml with a nightly cron schedule, keeping workflow_dispatch for manual runs.
  • Adds a check_changes job that compares HEAD against the last nightly release and skips the build if only docs changed since the last nightly; manual dispatches always build.
  • Moves contents: write permission from global scope into the build job only, and sets cancel-in-progress: false so in-progress runs are never cancelled.
  • Derives the stamped version date from github.run_started_at instead of the step execution time to avoid day-boundary mismatches.
  • Updates docs/nodes.md to document the cron cadence, the change gate, and that merging no longer triggers an immediate release.
📊 Macroscope summarized 01f5a95. 2 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

The workflow was a nightly in name only: `push: branches: [main]` built on
every merge, publishing 9 permanent releases in one day for one day's work.
A day's merges should land in one build.

Switch to `schedule: 37 6 * * *` (02:37 EDT / 01:37 EST; the offset minute
avoids GitHub's on-the-hour cron backlog) and gate scheduled runs on a
`check_changes` job, so a quiet day or a docs-only day skips entirely.
`paths-ignore` had to go regardless — path filters only apply to
push/pull_request, so it would have become dead config under `schedule`. The
replacement diffs the whole day rather than one push at a time.

workflow_dispatch keeps working and now bypasses the gate, so a manual run is
always a build — no `force` input needed.

Borrowed from upstream's release.yml, which has run a real nightly for far
longer:
  - `!failure() && !cancelled()` on the build job, which is what lets a
    *skipped* gate through while still halting on a broken one; `always()`
    would build even when the gate errored.
  - Date the version from `github.run_started_at`, not wall-clock `date -u`:
    a build starting at 23:59 UTC would otherwise stamp tomorrow.
  - `contents: read` by default, `write` only on the job that publishes.

Also stop cancelling in-progress runs. The publish step deletes the `nightly`
release before recreating it; a cancel in that window leaves nodes with no
release to pull, and since their ExecStartPre is best-effort they would
silently keep running a stale build. Upstream has no concurrency group either.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ua6eR6J5wHne2wfEd3VF9N
@jetblk
jetblk merged commit 94a3380 into main Jul 17, 2026
2 of 3 checks passed
@jetblk
jetblk deleted the ci/nightly-cron branch July 17, 2026 12:52
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.

1 participant