Repository navigation
fix: port promotion script fixes from infra-central - #163
Conversation
infra-central's port of the change-list format (fil-forge/infra-central PR 245) improved on it in places that matter here too: - Page the compare API. Unpaged, it stops at 250 commits without saying so. The pages are read as one array with jq, so the notes about an identical, behind or diverged pin are written once, not per page. - Run under bash 3.2, so --dry-run works with macOS's /bin/bash: VERSIONS is a plain string set for the service being described. - Name the ghcr.io package after the repository it publishes from. - Drop a stale remote-tracking ref when bot/promote-staging is gone from origin, so the force-with-lease matches the real branch. - Treat a head the bot authored but did not commit as hand-pushed: an amended bot commit keeps the bot as author. - Check for a hand-pushed head before closing, so a held-back branch is not deleted once staging catches up with dev. - Build a dry run on a scratch branch and switch back afterwards, so the local bot/promote-staging is never touched. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Miroslav Bajtoš <oss@bajtos.net>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bbaa2a4c13
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
🔵 Needs a closer look
The script performs force-pushes, remote branch deletions, and PR open/close operations with subtle git ref/lease semantics that warrant human verification before approval.
1 open finding
What changed in this PR
This PR ports a set of fixes to scripts/ci/promote-staging.sh (which keeps the "Promote dev's images to staging" pull request) from the equivalent script in infra-central. The changes harden the script's compare-API handling, git-ref bookkeeping, and dry-run isolation, and follow up #136's change-list formatting work. It fits into the automated promotion pipeline run by promote-staging.yml on every push to main.
Changes:
- Page the compare API with
gh api --paginate --slurpand process all pages as one array in a standalonejq, so the identical/behind/diverged/cut-short notes are written once and the list is not silently capped at 250 commits. - Make the script bash 3.2 compatible (
VERSIONSas a plain string instead of an associative array) and derive the ghcr.io org/package from each service's repository;digest_linknow takes only the digest. - Fix git-ref handling: delete stale remote-tracking refs for a branch gone from origin, treat an app-authored-but-not-committed head as hand-pushed (and check this before the close path), build dry runs on a scratch branch, and push via
HEAD:refs/heads/$BRANCH.
| File | Description |
|---|---|
| scripts/ci/promote-staging.sh | Paginated compare API, bash 3.2-safe VERSIONS/digest_link refactor, stale-ref cleanup, author+committer hand-push check moved earlier, dry-run scratch branch, and updated header/usage docs. |
| docs/RUNBOOK.md | Updates the hold-a-service-back guidance to match the new author+committer detection (an amended bot commit counts as a hand-push). |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The dry run committed on dry-run/promote-staging, switched back and deleted that branch. Anything staged went into the commit and was lost with it, and an existing branch of that name was reset to main. - Commit on a detached HEAD, which needs no branch name. - Refuse to run with staged changes or an edit to staging's versions.env, which the promotion commit would take in. - List the jq variables the SC2016 comment covers. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Miroslav Bajtoš <oss@bajtos.net>
Every run now builds the commit in a worktree detached at main and removed on exit, as infra-central's promote.sh does. The worktree's index starts clean, so nothing staged in the checkout the script runs in can reach the commit, and the checkout's branches are never moved. This replaces the detached checkout and the refusal to run with a dirty index, which only guarded the dry run. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Miroslav Bajtoš <oss@bajtos.net>
Set the trap that removes the worktree where the worktree is made, and fall back to deleting its directory, so a failed git worktree add leaves no empty temporary directory behind. This and the comments now match infra-central's promote.sh (fil-forge/infra-central#251). Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Miroslav Bajtoš <oss@bajtos.net>

Written by Claude.
Port the improvements fil-forge/infra-central#245 made while porting #136's change-list format to infra-central's
scripts/promote.sh.gh api --paginate --slurphands jq every page as one array, so the identical, behind, diverged and cut-short notes are written once. jq is now a prerequisite;ubuntu-latestships it.--dry-runworks with macOS's/bin/bash.VERSIONSis a plain string thatload_versionssets for the service being described, anddigest_linktakes only the digest.bot/promote-stagingis gone from origin, soold_headnever names a commit the force-with-lease cannot match.origin/main, removed on exit, so neither a dry run nor a real one touches the calling checkout, its index or its branches.infra-central's
SOURCE/TARGETstages,BASEandSMOKE_RUN_URLstay out.Verification
make check-shellpasses.changesagainst fil-forge/ingot6071feb...7b28323lists all 8 commits ahead; swapped, it prints only the "8 commits behind" note; the same commit twice prints only the "same commit" note. Withper_page=5the API returns two pages (5 + 3) and the output matchesper_page=100exactly.APP_SLUG=fil-forge-bot /bin/bash scripts/ci/promote-staging.sh --dry-run(bash 3.2.57) exits 0, lists ingot's 9 commits with both digests linked to ghcr.io.versions.envand an existingdry-run/promote-staging, lists ingot's 8 commits, commits only the one-line pin change, and leaves HEAD, the index, every probe and the branch as they were, with no worktree left behind.