rafa pages
- rafa
- rafa release
rafa release
Read the release state, settle waiting fragments into a version, tag it, publish it, and write the release ladder's workflows.
rafa release turns the release fragments that merged branches carry into versions. The release flow explains fragments, settle and the ladder; this page is the reference for each action.
Spends: nothing; no action starts a session. Changes: settle commits the version and changelog on the base (pushed, or through one release pull request); tag writes tags; publish runs the publish command; fragment and workflows --write write files. status and list read only. Needs: push access to the base for settle under release.settle: push, and a registry account or a trusted publisher for publish; see Prerequisites.
Things to know before you use it:
settleworks in a scratch worktree oforigin/<pr.base>, so your checkout is never touched, and a run that finds another machine already released the same fragments ends as settled.settlereadspr.base. During a stretch it points at the stretch branch, so settle afterrafa stretch endputs it back.publishskips a version the registry already holds, so a rerun after a half-finished publish only publishes what is missing.
In the target layout this code lives in the private package rafa-release, bundled into @open-tomato/rafa (Repository layout). In 0.47.0 it is already a package, @open-tomato/rafa-release in packages/rafa-release, but only as a facade: it re-exports this code from the root package's src/, where the files still live until their move. You install and type the same either way. [verify: the release the move lands in]
Actions
| Action | Does |
|---|---|
status | show the version, the latest tag, the untagged releases, the pending notes, the waiting fragments and the open stale-docs lines |
settle | fold the fragments waiting on the base branch into one version and changelog section |
tag | tag the commit that set the version both release files agree on |
publish | publish each release unit whose tag points at HEAD, skipping a version the registry holds |
workflows | list the release ladder's workflow files and whether the configured level needs each; write the missing ones |
fragment | write one change fragment for a branch with no wrap-up, such as a bot's pull request |
list | list the root and each publishable workspace package with its version, waiting fragments and newest tag |
rafa release status
Show the version, the latest tag, the untagged releases, the pending notes, the waiting fragments and the open stale-docs lines.
rafa release status [--plan=<string>]
Reads eight things about the release state of the project and writes nothing: the version release.versionFile declares, the latest release tag of the repository by semantic version precedence, the versions release.changelog calls released that carry no tag, the change notes the current plan's sessions have stored for its next release, and the change fragments waiting on origin/<pr.base> as last fetched, with the release rafa release settle would fold them into, the workspace packages that are not private, each with the version its manifest declares, the fragments waiting for it and its newest <name>@<version> tag, and an audit of the changelog's released history: a version two headings name, a gap between versions, dates out of order, and a heading newer than the releases made before settle with no tag, and how many lines the open stale-docs issues of the tracker the chain lands on hold unticked, none when they hold none. That count is the one reading that can reach the network, and it never changes the exit code. The current plan is the one --plan=<stub> names, and otherwise the one the checked-out branch's <type>/<stub> names, resolved against the plans in plan.dir. A reading that could not be made leaves its cell as ? and says why on a line under the block rather than refusing the others. With --output=json the eight readings and the rendered block are the data of the terminal result event.
| Flag | Type and default | What it does |
|---|---|---|
--plan | string | the plan stub the pending change notes are read for, instead of the branch's |
Examples:
rafa release status: Shows the version, the latest tag, the untagged releases and the notes pending for this branch's plan.rafa release status --plan=rafa-21-changelog-and-release: Reads the pending change notes for that plan rather than the one the branch names.
Output formats: text, json.
rafa release settle
Fold the fragments waiting on the base branch into one version and changelog section.
rafa release settle [--dry-run]
Fetches origin/<pr.base> (or origin/main) and works in a scratch worktree of it, so the checkout it runs from is never touched. It lists the fragments under release.fragments in the order the base received them, folds them through release.strategy into the next version and one changelog section, writes both (creating release.changelog under # Changelog when the base lacks it), deletes the folded fragments and commits chore: release <version>. With release.moveLock: true the same commit writes rafa.lock at the root to the new version, creating it when the base holds none, and the settle is refused, writing nothing, when the lock does not read or the version file names a package other than rafa. With release.settle: push (the default) the commit is pushed to the base, never forced; a refused push fetches again and ends as settled when another run released the same fragments, or rebuilds and pushes once more. With release.settle: pr it goes to rafa/release and one pending release pull request is opened or updated. release.tag: settle tags a pushed release. It prints the strategy, the base version, the fragments in order and the new version, and exits 0 when the release is delivered or nothing waits, 1 otherwise. With --dry-run it prints the same reading and writes nothing. With --output=json a run exiting 0 gives the reading and what was delivered as the data of the terminal result event. Starts no session.
| Flag | Type and default | What it does |
|---|---|---|
--dry-run | boolean | Print the fragments, their order, the strategy and the version, and write nothing: no commit, no push, no tag. |
Examples:
rafa release settle: Folds the waiting fragments into a release commit and delivers it byrelease.settle.rafa release settle --dry-run: Prints what a settle would fold and the version it would write, writing nothing.rafa release settle --output=json: Settles and gives the reading and the delivery as a result event.
Output formats: text, json.
rafa release tag
Tag the commit that set the version both release files agree on.
rafa release tag [--push]
Writes v<version> on the release branch — pr.base, or main — when the version release.versionFile declares is the one the newest section of release.changelog names, and <name>@<version> for each workspace package that is not private when the version <dir>/package.json declares is the one the newest section of <dir>/CHANGELOG.md names. Each tag goes on the commit that set its version: HEAD, or, where later commits landed on the branch, the earlier commit, with a warning naming how many commits HEAD is past it. A unit whose version a tag already names is skipped. Every unit is decided before the first tag is written, and the run writes nothing when another branch is checked out, when every unit is skipped, or when any unit's two files disagree, its version's changelog section carries no <!-- rafa:fragments --> receipt and is above the newest version released before settle, no commit holds its version yet, or its version file, the tag list or the history could not be read. After the tags it prints what to run next: per tag, the push that puts it on the remote and the publish line for the registry its manifest configures, with the command release.publishCommand names (npm publish by default), run in the package's folder for a package and spelled to publish from the tag when HEAD is past it, which it does not run. Under release.publish: ci a unit's publish line is replaced by one sentence saying the pushed tag publishes through .github/workflows/release-publish.yml, and json carries publish: "ci" on that unit. With --push it pushes each tag itself to the remote the release branch tracks (origin when it tracks none) and drops its push line; a push that fails exits 1 with what git said and keeps the local tags. With --output=json the readings, the decisions, the follow-ups and the pushes of every unit are the data of the terminal result event.
| Flag | Type and default | What it does |
|---|---|---|
--push | boolean | Push each tag to the remote the release branch tracks once every tag is written; a push that fails exits 1 and keeps the local tags. |
Examples:
rafa release tag: Tags the merged release of every unit and prints the push and publish lines to run next.rafa release tag --push: Tags the merged release of every unit, pushes the tags, and prints the publish lines to run next.rafa release tag --output=json: Writes the same tags and gives every unit's readings, decision and follow-ups as a result event.
Output formats: text, json.
rafa release publish
Publish each release unit whose tag points at HEAD, skipping a version the registry holds.
rafa release publish [--tag=<string>] [--dry-run]
Runs release.publishCommand (npm publish by default) through the shell for each release tag pointing at HEAD — v<version> for the root, published from the project root, and <name>@<version> for a publishable workspace package, published from its folder — or for the one tag --tag names, which is refused when it is no release tag or does not point at HEAD. Every unit is read before anything runs, and the run refuses with exit 1 when no release tag points at HEAD, when a tag names no publishable package, or when the manifest declares a version other than the tag's. Before each publish it asks npm view <name>@<version> version --registry=<registry>, the registry being publishConfig.registry or npm's, and skips the unit with one line when the registry holds that version already, so a retry publishes only what is missing; a private manifest is skipped too. The publish runs with the terminal's streams, and the first that fails stops the run with its exit code, naming the tags published before it. --dry-run prints each unit's line and runs nothing. With --output=json the units, the skipped, the published and the exit are the data of the terminal result event.
| Flag | Type and default | What it does |
|---|---|---|
--tag | string | The one release tag to publish, which has to point at HEAD. |
--dry-run | boolean | Print the line of each unit and run nothing, not even the registry check. |
Examples:
rafa release publish: Publishes every release unit tagged at HEAD that the registry does not hold yet.rafa release publish --tag=@scope/plugin@0.2.0: Publishes that one package, when its tag points at HEAD.rafa release publish --dry-run: Prints what each unit would run, and runs nothing.
Output formats: text, json.
rafa release workflows
List the release ladder's workflow files and whether the configured level needs each; write the missing ones.
rafa release workflows [--write]
Writes one row per workflow file of the release ladder under .github/workflows/: its path, the levels it serves, whether the level release.settle, release.tag and release.publish read as needs it, and present when it holds the shipped template's bytes, differs when it holds others, or missing, a path holding no regular file counting as missing. With --write each needed missing workflow is written from the shipped template, a present or differing file is left as it is and named, and a directory at the path is refused and named; a workflow the level does not need is never written. The command exits 0 in every case. With --output=json the level, the rows and the writes are the data of the terminal result event.
| Flag | Type and default | What it does |
|---|---|---|
--write | boolean | Write each workflow the level needs and the project lacks, from the shipped template. |
Examples:
rafa release workflows: Lists the ladder's workflow files, which the configured level needs, and their state.rafa release workflows --write: Writes each needed workflow that is missing, and leaves every existing file as it is.
Output formats: text, json.
rafa release fragment
Write one change fragment for a branch with no wrap-up, such as a bot's pull request.
rafa release fragment [--plan=<string>] [--level=<string>] [--title=<string>]
[--note=<string>] [--package=<string>]
Writes one change fragment under release.fragments and prints the path written. The fragment carries --plan, --title (one line), --level (patch, minor, major or none), --package when given and one - <area>: <summary> line per --note; a level other than none given no note carries its title as the one note. The file is named <plan>.md, or -2, -3 and on when that name waits on origin/<pr.base>, read after a fetch. Exits 1, writing nothing, for a plan id that cannot name a fragment, an unknown level, an empty title, a note that is not <area>: <summary>, a package the workspace lacks or holds as private, a base that cannot be read, and a fragment of that name already on the branch. With --output=json the path, the fragment and any warnings are the data of the terminal result event.
| Flag | Type and default | What it does |
|---|---|---|
--plan | string | The plan id the fragment carries and is named by. |
--level | string | The bump the fragment asks for: patch, minor, major or none. |
--title | string | The fragment's title, one line. |
--note | string | One note as <area>: <summary>; give the flag once per note. |
--package | string | The publishable workspace package the fragment releases; the root when left out. |
Examples:
rafa release fragment --plan=dependabot-7 --level=patch --title='Bump zod from 3.22 to 3.23': Writes a patch fragment for pull request 7, its title as the one note.rafa release fragment --plan=rafa-12 --level=minor --title='Plugin hooks' --note='hooks: run before each task' --package=@scope/plugin: Writes a minor fragment for a workspace package with one note.
Output formats: text, json.
rafa release list
List the root and each publishable workspace package with its version, waiting fragments and newest tag.
rafa release list
Writes one row per unit that releases on its own and writes nothing else: the root first, named by the name of release.versionFile, then each workspace package that is not private. Each row holds the version its file declares, how many change fragments waiting on origin/<pr.base> as last fetched name it, and its newest release tag: v<version> for the root, <name>@<version> for a package, or untagged. A column that could not be read is ?, with the reason on a line under the rows, and the command still exits 0. With --output=json the rows and the rendered lines are the data of the terminal result event.
Examples:
rafa release list: Lists the root and each publishable package with its version, waiting fragments and newest tag.
Output formats: text, json.