Skip to content

ci: harden the build and API-pages workflows#843

Open
SunsetDrifter wants to merge 4 commits into
mainfrom
docs/ci-quick-fixes
Open

ci: harden the build and API-pages workflows#843
SunsetDrifter wants to merge 4 commits into
mainfrom
docs/ci-quick-fixes

Conversation

@SunsetDrifter

@SunsetDrifter SunsetDrifter commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Why

Two gaps in the pipeline around the recently-tracked lockfile and the :main image tag:

  • build_n_push had no concurrency group: two quick merges to main race the image push, and whichever finishes last wins the :main tag regardless of commit order — the server pulls :main, so an older build can silently ship.
  • generate_api_pages ran npm install on an unpinned Node and committed with git add -A + git push --force. Since package-lock.json is now tracked, a divergent macOS-resolved lockfile could be swept into the auto-commit; and a force-push from this workflow would rewrite main, destroying any PR merged during its multi-minute run.

What

build_n_push.yml

  • Per-ref concurrency group — main builds queue (never cancelled mid-push), superseded PR builds are cancelled.
  • permissions: contents: read.
  • PR path filter now also covers .dockerignore and package.json.

generate_api_pages.yml

  • Pin Node 20, npm installnpm ci (this workflow never changes dependencies, so it installs the lockfile exactly and can never rewrite it).
  • Sync the checkout to the branch tip before regenerating: a run queued behind another checks out the commit pinned at dispatch time, and regenerating against that stale base can let a file the newer spec removed silently survive the pre-push rebase.
  • Stage only src/pages/ipa/resources (change-check scoped to match).
  • Rebase onto the branch before pushing, and drop --force: if main moved during the run, the single generated-files commit replays cleanly on top; a genuine conflict fails the run loudly with main untouched. If anyone remembers a deliberate reason the push was --force, please flag it.
  • Concurrency group: several same-day dispatches happen (see run history); overlapping runs regenerate the same files.

scripts/git-dates.mjs

  • Warn (instead of staying silent) when per-page dates are skipped because git is unavailable or the clone is shallow — previously every page silently lost its "Updated" line and the sitemap lost <lastmod>.
  • Document the squash-merge assumption behind the single-pass git log --name-only walk; drop the unused per-file lookup.

CLAUDE.md

  • Note that npm run start warns under output: 'standalone' (safe to ignore locally; prod runs node server.js).

Summary by CodeRabbit

  • Bug Fixes

    • Improved the reliability of automated builds by reducing overlapping runs and limiting unnecessary cancellations.
    • Made generated page updates safer by basing them on the latest branch state and avoiding force-pushes.
    • Tightened change detection so only relevant generated content triggers updates.
  • Documentation

    • Clarified local development guidance for a common startup warning.

… the lockfile

build_n_push: add a per-ref concurrency group so two quick merges to main can't race the :main tag (last push wins regardless of commit order, and the server auto-pulls :main); add permissions: contents: read; validate .dockerignore and package.json changes in the PR path filter.

generate_api_pages: pin Node 20 and switch npm install -> npm ci so the run can never rewrite the now-tracked package-lock.json with a divergent macOS-resolved tree; stage only src/pages/ipa/resources instead of git add -A; drop --force from the push — a force-push from this workflow would silently rewrite main and destroy any PR merged since its checkout.
…ookup

buildGitDateMap now logs a warning when it emits no dates (git missing or shallow clone) instead of silently blanking every page's Updated line and the sitemap lastmod entries; document the squash-merge assumption behind the --name-only walk. Remove the unused getGitLastModified. Note in CLAUDE.md that npm run start warns under output: 'standalone'. Gen output verified byte-identical.
Rebase the single generated-files commit onto the moved branch before pushing, so a PR merged during the multi-minute run no longer rejects the push (the failure --force was presumably papering over). A genuine conflict — a concurrent edit of the generated files themselves — still fails the run loudly with main untouched. Also serialise dispatches with a concurrency group: run history shows several same-day dispatches, and overlapping runs regenerate the same files.

Sandbox-tested against a bare repo: plain push rejected on race; rebase+push lands with both commits intact; true conflict exits 1 leaving the branch tip untouched.
A run queued behind another checks out the commit pinned at its dispatch time; regenerating against that stale base means the pre-push rebase replays a snapshot diff, and a file the newer spec removed can silently survive from the prior run. Fetch + reset to the branch tip before generating so the diff is computed against reality. Also note the latest-dispatched-vs-newest-tag caveat on the concurrency comment.

Sandbox-proven: with the old order a removed-in-newer-spec file survives the rebase replay; with sync-first it is gone.
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2a09f3d2-3a53-4953-9a7c-9c1da0deae85

📥 Commits

Reviewing files that changed from the base of the PR and between 44cab34 and 1800dfd.

📒 Files selected for processing (4)
  • .github/workflows/build_n_push.yml
  • .github/workflows/generate_api_pages.yml
  • CLAUDE.md
  • scripts/git-dates.mjs

📝 Walkthrough

Walkthrough

This PR updates two GitHub Actions workflows to add permissions, concurrency controls, a branch-sync step, deterministic npm ci installs, and a rebase-based commit flow scoped to generated output. It also refactors scripts/git-dates.mjs caching/logging and updates CLAUDE.md documentation.

Changes

CI Workflow Updates

Layer / File(s) Summary
build_n_push trigger and concurrency controls
.github/workflows/build_n_push.yml
Expanded pull_request path filters, added explicit contents: read permissions, and configured concurrency to serialize runs per workflow/ref with PR-only cancellation.
generate_api_pages concurrency, sync, and commit flow
.github/workflows/generate_api_pages.yml
Added concurrency to serialize dispatches, added a sync-to-branch-tip step before generation, switched to actions/setup-node + npm ci, narrowed diff checks to the generated output directory, and replaced force-push with a rebase-based commit/push scoped to generated pages.

Git Dates Script and Docs Update

Layer / File(s) Summary
git-dates caching and warning behavior
scripts/git-dates.mjs
Removed exported getGitLastModified, added module-level _dateMapCache, updated docs on merge-commit handling and shallow-repo behavior, and added a console warning on git-history read failure.
CLAUDE.md start command note
CLAUDE.md
Clarified that the output: 'standalone' warning from npm run start is safe to ignore locally.

Estimated code review effort: 2 (Simple) | ~12 minutes

Suggested reviewers: jnfrati

Poem

A rabbit hopped through YAML fields,
Adding locks where concurrency yields 🔒
Synced the branch, then ran npm ci,
Rebased and pushed, tidy as can be.
Cached the dates, warned when things broke —
Hop, hop, hooray, no more silent joke! 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main workflow hardening changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/ci-quick-fixes

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

scripts/git-dates.mjs

Oops! Something went wrong! :(

ESLint: 9.39.2

TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'configs' -> object with constructor 'Object'
| property 'flat' -> object with constructor 'Object'
| ...
| property 'plugins' -> object with constructor 'Object'
--- property 'react' closes the circle
Referenced from:
at JSON.stringify ()
at file:///node_modules/@eslint/eslintrc/lib/shared/config-validator.js:308:45
at Array.map ()
at ConfigValidator.formatErrors (file:///node_modules/@eslint/eslintrc/lib/shared/config-validator.js:299:23)
at ConfigValidator.validateConfigSchema (file:///node_modules/@eslint/eslintrc/lib/shared/config-validator.js:330:84)
at ConfigArrayFactory._normalizeConfigData (file:///node_modules/@eslint/eslintrc/lib/config-array-factory.js:676:19)
at ConfigArrayFactory._loadConfigData (file:///node_modules/@eslint/eslintrc/lib/config-array-factory.js:641:21)
at ConfigArrayFactory._loadExtendedShareableConfig (file:///node_modules/@eslint/eslintrc/lib/config-array-factory.js:946:21)
at ConfigArrayFactory._loadExtends (file:///node_modules/@eslint/eslintrc/lib/config-array-factory.js:814:25)
at ConfigArrayFactory._normalizeObjectConfigDataBody (file:///node_modules/@eslint/eslintrc/lib/config-array-factory.js:752:25)


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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