release: rt release app <name> for single-app patch releases - #464
Merged
Merged
Conversation
…RunCompletion Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es helpers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eference Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o remote calls Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-app fix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 57 minutes. View limit detailsLimit details: You’ve used the included review currently available. Your 85 included PR review attempts over the past 7 days set your current allowance at 1 review per hour. Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (17)
Comment |
…ers skip releases/latest Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…val, and review fixes Last tag from origin, not local tags; the gate refuses any deps.lock change beyond a serve-only pin and runs again on the commit being tagged; an unverified newest tag is re-verified before a new release; --yes-notes binds to the notes hash; bundle-apps runs carry a run-name so in-flight runs are matched by title; the bot PR must be the workflow's own and its binary must pass codesign --verify --strict under the release team; workspace packages count toward an app's changes; held pins are listed in the plan and notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…blish exits 1 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… checks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t the verb checks, step 8 ruling Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t, hash-only approval, catalog and name-linked deps, all-state bot PR scan Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r; --yes-notes takes only the hash Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
rt release app <name>, a single served-app patch release as one resumable verb. It runs the whole pin-only fast path (bump, bundle, merge, notes, tag, verify) for one app, so shipping a board fix no longer takes about 25 hand-run commands.What it does
<name>must be an apps-monorepo row whose pin keeps the fast path (board, chat, console, boxscore).git ls-remote --tags --refs origin 'v*'), never from local tags.RELEASE_NOTES.mdandwebsite/. Once deps.lock is in the diff, preflight'scheckGateruns, then a stricter check: every row stays identical except version, url and sha256 on serve-only rows, and schema and arch are unchanged./rt:release, and so is an existing tag for the next app version.apps/<name>/package.jsonand the app's"apps/<name>"workspace version in the apps repo's rootbun.lockto the next patch, in one fast-forward-only commit through the git data API on top of the apps head that qualify read.bun.lockdoesn't record the current pin. That is checked in qualify, so a dry run reports it too.apps/<name>plus every workspace package it depends on, transitively. Any dependency whose name is a workspace package counts, whatever its specifier. So do root catalog entries the app or those packages use (catalog:and named catalogs) that changed between the pin tag and main, and the notes name them.bundle-apps.yml(apps=<name>,dry_run=false), finds its run, and watches it with verify's tolerant poll, nevergh run watch --exit-status.bundle-apps.ymlnow has arun-namecarrying its inputs. A run already building the app is adopted by that title, never a dry run or anallrun.bundle-ci/<run>, not cross-repository, and authored by the release-token account.<name>'s row. That row may differ from its base only in version, url and sha256, plus update-lock.ts's fixed status, archive and extract.codesign --verify --strictand checksIdentifier=com.mattstack.helper.<name>under a Developer ID authority, withTeamIdentifierequal to theDEVELOPMENT_TEAMinrt-tray/project.yml. The binary is never executed.gh pr checkserror is an error after three in a row, never pending.--match-head-commit. The PR search covers every state (filtered to the workflow's PRs for the target version), so a closed bot PR is refused with the reopen command rather than reported missing.RELEASE_NOTES.mdfor last-tag..main gets one section per moved app, built fromgit logof the app and its workspace packages between the old and new app tags. Subjects only; PR numbers becomem4ttstack/apps#Nso they don't link to rt PRs.--json, the run stops with the notes, theirnotesHashand a resume command.--yes-notestakes only that 12-character hash. The tag form is a usage error, and a hash for other or changed notes is refused with the new notes and hash.chore(release): notes for <tag>and they landed after the last pin move.git tag -a vX.Y.(Z+1)goes on exactly that commit and is pushed; a local-only tag is accepted only when it points at that commit.runVerifyruns, the same checks asrt release verify. A releases/latest that is still propagating ends aspendingwithrt release verify <tag>to recheck, notfailed.Every step detects whether it already happened, so rerunning after a failure resumes: bump already on main, run in flight or already published, PR already merged, notes already committed, tag already pushed. Each failure names the step and the resume command.
With no name on a TTY,
rt release appopens the rt-ui picker over the eligible apps with their pinned versions (e.g.board 0.1.7). The picker is gated onisTTY && !json && !RT_BATCH, and the tree declaresomitBehavior: "picker". Off a TTY, or with--jsonorRT_BATCH, it gives the usual usage error.rt release verifyalso changes for everyone: it now looks for the tag-push run for about three minutes before calling it missing, and it takes askipLatestoption.Decisions worth a look
/rt:release.website/, so the tag runs the same pipeline the last tag already ran. The tag run still builds, notarizes and clean-rooms.released,plannedandawaiting-approvalexit 0;pending,declinedandfailedexit 1.BUNDLE_PR_AUTHORis the release-token account (m4ttheweric), the only login the workflow opens PRs as.mattstack-appscheckout.Also:
checkGatetakes an optional ref.keepsFastPathandpollRunCompletionare exported.DepsRowgainssha256.cwdoption.docs/release-and-distribution.mddescribes the verb and therun-namecontract.--yes-notes <hash>resume, the pending and refusal outcomes, and exactly which preflight checks the verb runs. Step 2b's bump now says a direct commit to apps main, no PR.Follow-ups (from the second review, not in this PR)
failed; returnpendingwhile the run itself is pending.m4ttheweric); optionally also require the head commit authorbundle-apps workflowand that the run is a bundle-apps run on main.--jsondoes not stop at the notes when they are already committed (intended resume behavior), but the tree hint and the skill say it always stops.--yes-notesrefusal theresumefield starts with prose, while the skill says to run the newresume.How to use
Verification
lib/release/__tests__/release-app.test.tscovers the pure pieces: qualification, versions, the pin-only lock gate, the bot-PR row rules, codesign team and identity, the notes hash, run-name parsing, held pins, workspace deps and notes rendering.lib/release/__tests__/release-app-run.test.ts(55) drives the verb against a stateful fake of git and GitHub. That covers every review fix (origin tags, the stricter gate, bound approval, re-verifying an unverified tag, pending verify, website-only main, a non-pin merge mid-run, the tag-time gate, stale notes, notes-subject reuse, run-name adoption, the PR author and fork check, strict codesign and team,gh pr checkserrors, a closed PR and ref-update diagnosis) as well as the original flows. Round 3 adds the combined package.json andbun.lockbump commit, a stalebun.lockrefusal, apps main moving under the bump, a catalog-only change, a closed bot PR found by the scan, and the tag form or a stale hash refused. Mutation-checked: removing each of 23 fixes turns its test red, including the notes-time gate, the stale-notes ancestor check and thebun.lockhalf of the bump.skipLatest.commands/__tests__/release-app.test.ts(15) covers the picker path (fake picker seam), usage errors,--yes-notestaking only a 12-hex hash (the tag form is a usage error, and the value is never taken for the app name), and exit codes including pending.e2e/tests/release-app.test.tsrunsrt release app board --dry-run --jsonwith the compiled binary under an isolated HOME. It uses real git against local bare repos and a journalingghshim, with no network. It asserts the plan, the exact read-onlyghcalls, and that both bare remotes' refs are byte-identical before and after.bunx tsc --noEmit,bun run picker:check,bun run docs:check(reference regenerated); CI runs the suites. No real bundle-apps run, tag or release was run.🤖 Generated with Claude Code