Repository navigation
v0.132.0
rlsbl rewritten in Go: one binary, published to npm and PyPI as per-platform packages and wheels and installable with go install, with the release record in the .strictmetadata layout. The Python package is gone.
Context
The stricttools projects are moving to Go; the source checks rlsbl ran moved to strictcode.
Breaking
- rlsbl is rewritten in Go. One
rlsblbinary replaces the Python package. It is distributed as the Go modulegithub.com/stricttools/rlsbl, as npm packages under the existingrlsblname (the binary in one package per platform,rlsbl-linux-x64,rlsbl-linux-arm64,rlsbl-darwin-x64, andrlsbl-darwin-arm64, selected throughoptionalDependencies), and as PyPI wheels under the existingrlsblname. There are no Windows packages, and rlsbl's Python modules can no longer be imported. - rlsbl's records move to
.strictmetadata/. rlsbl reads nothing of the old layout (.rlsbl/,.rlsbl-monorepo/, and each member's.rlsbl/). Runrlsbl migrate recordsonce in every repository, with--dry-runfirst: it converts the declarations, changelogs, release files and archives, batch release files, transition record, scaffold state, hook scripts, and options entries, writes the lifecycle-and-license record (--licensesstates a license the manifests do not), removes the old layout through saferm, and commits.rlsbl monorepo cleanupremoves old-layout residue, in a standalone repository too. - One declarations file.
config.json,workspace.toml, andreleasable.tomlare replaced by.strictmetadata/releasables/releasables.toml, declaring the layout, release branches, releasables, members, targets, pipelines, hooks, and checks; its[timeouts]table (push_seconds,ci_seconds,check_seconds,hook_seconds) replaces thepush_timeout,ci_timeout,check_timeout, andhook_timeoutkeys, and behavior switches are options entries in.strictmetadata/options/, written withrlsbl options set.rlsbl migrate recordswrites both. - The release targets are go, npm, and pypi. The
spectarget is removed, andrlsbl migrate recordsrefuses a configuration naming any target other than go, npm, and pypi, naming the hand edit. - Changelog format version 2. Each releasable's changelog lives in
.strictmetadata/changelog/<releasable>/, every entry carries an id, and an entry naming more commits than the per-entry limit carries its reason throughrlsbl changelog add --batch-reason, which replaces--allow-batchand thebatch_limitsexclusions;rlsbl migrate recordsrestamps existing entries. - The pre-release channel is removed. Versions are
MAJOR.MINOR.PATCH: a release file carryingpreid,blog, orbump = "prerelease"is refused, andrlsbl migrate recordsfolds a pre-release's changelog entries into the stable version it preceded. - Removed subsystems. Member layering (the
[layers]key and the layers-violations check), deploy configuration (a server releasable declares adeploy_commandinstead), subtree mirror publication, the launcher artifact, local asset upload (assetsandcustom_assets; the publish workflow builds and attaches release archives in CI), the Cloudflare Pages pipeline (selfdoc deploys documentation sites), blog-on-release, and therequires-services(with theservicesandtest_envkeys),private-hook-stale, andmixed-tag-schemeschecks are removed. - Removed commands and flags.
rlsbl deploy,rlsbl prs,rlsbl pre-push-check,rlsbl monorepo mirror,rlsbl monorepo snapshot,rlsbl monorepo snapshot-check(rlsbl monorepo graph --jsongives the same inventory on demand),rlsbl transition record,rlsbl release undo --target, andrlsbl changelog amend --idare removed. - Source checks move to strictcode. The lint, format, and type-check tool options, the dependency-declaration checks, and the dead-modules, circular-deps, library-lint, dead-workspace-packages, ruff-lint, and strictspec certificate checks leave rlsbl; the
rlsbl:strictcodeoption (error by default) runsstrictcode analyzeas a release check and refuses a missing strictcode, andrlsbl migrate recordsmoves their settings intostrictcode.toml. - The lifecycle-and-license record. Each repository's
.strictmetadata/lifecycle-and-license/lifecycle-and-license.tomlholds each releasable's dated lifecycle, license, and identities. A release or resume of a releasable on hold or retired is refused; a proprietary releasable requires a private repository and refuses every public output (registry packages, attestations, the Go module proxy, public docs); a Go library target on a private repository is refused; andrlsbl monorepo init,rlsbl monorepo add, andrlsbl monorepo absorbcreating a releasable require--license. - Changed flags.
rlsbl release reconciletakes--mode planor--mode applyinstead of--planand--apply;rlsbl monorepo release initrequires--releasablesor--all, writing no table for every releasable unasked; andrlsbl monorepo graphrequires--format. - Preflight checks always run. A declared
pre_releasehook replaces only a member's built-in tests, never the preflight checks, and customized hook scripts become hooks declared inreleasables.toml, moved byrlsbl migrate recordsto.strictmetadata/release-hooks/. - A release refuses an origin remote whose host is a domain other than github.com; SSH host aliases without a dot are accepted.
- A release file whose
excludenames a target a pipeline publishes is refused, naming the pipeline: every pipeline publishes on every release, so the excluded target was published anyway. Delete the pipeline fromreleasables.tomlto release without publishing that target. - rlsbl is a Go binary. The npm and PyPI packages
rlsblnow install the Go binary, through per-platform packages (rlsbl-linux-x64,rlsbl-linux-arm64,rlsbl-darwin-x64,rlsbl-darwin-arm64on npm, platform wheels on PyPI) for Linux and macOS on x64 and arm64; there is no Windows build.go install github.com/stricttools/rlsbl/cmd/rlsbl@v0and the archives on each GitHub Release install it too. The Python package and itspython -m rlsblentry point are gone.
Features
- New
rlsbl transition public-client --subject <name> --reason <text>declares that a subject of a confidential repository has a public client, taking its registry names and the repository's names out of the confidential-name index;transition showlists the declarations, and the index no longer holds releasable names or identity values, nor matches a name inside a URL or a dotted hostname - New
rlsbl transitioncommands keep the lifecycle-and-license record:transition showprints the record with every rule's verdict,transition lifecycle,transition license,transition identity, andtransition unversioned-tagrecord periods and tags,transition classifymakes a releasable proprietary,transition declassifysquashes the proprietary history and takes a repository public, andtransition init-minimal-recordwrites a minimal record into a repository rlsbl does not manage. - Confidential names stay out of public output. The
confidential-namescheck refuses a tracked file or changelog entry of a public repository carrying a name from the machine-local confidential-name index, every GitHub Release body rlsbl writes is scanned the same way, and every mutating command keeps the index in step with the lifecycle-and-license record. - A release refuses a packed artifact (an npm tarball, a wheel, or a Go module zip) carrying a file from outside the releasable's members, naming each file.
rlsbl monorepo graph --jsonprints the dependency graph as a document: the members in topological order with their versions, targets, releasables, flags, dependencies, and dependents, and the edges in the same order.- npm ships Go binaries. A go binary pipeline publishes to npm as one package per platform, selected through the main package's
optionalDependenciesbyosandcpu, with no postinstall script. rlsbl rewrite project-namerecords each renamed identity in the lifecycle-and-license record as a pending identity, one per registry carrying the name, which takes effect with the next release.rlsbl release deprecateandrlsbl release yankaccept the latest release, which they used to refuse in favor ofrlsbl release undo.rlsbl scaffoldrefuses to write a newVERSIONthat would disagree with a target's version.
Fixes
- Commands that create a
.strictmetadatadirectory'smanifest.tomlwhile writing a record (rlsbl release backfill,rlsbl release abandon) now commit the manifest with the record instead of leaving it uncommitted - A refusing command prints no partial report:
rlsbl statusrefusing a member with several targets and no--targetno longer prints an empty status block before the error transition showholds the confidential-names rule for a confidential repository whose public-client declarations leave it no name to protect, expecting no index entry, instead of calling it public- After a three-way merge conflict is resolved, the next
rlsbl scaffoldcommits the resolved file and its new merge base, which it used to leave uncommitted. - The
npm-token-syncedcheck runs insiderlsbl check,rlsbl failing-checks, and a release's--dry-run; it failed there because listing the npm tokens was not an allowed read. - A go binary pipeline whose main package is not at the module root gets a
.goreleaser.ymland archives named after that package (./cmd/toolbuildstool), not after the module path's last element; andrlsbl scaffoldkeeps theversion.goit wrote into the main package instead of removing it on the next run and writing it again on the one after. rlsbl scaffoldwrites a stubgo.modinto the.strictmetadata/of a Go module below the repository root when that module tracks files there (the strictcli schema dump), so the module zip leaves them out and theupload-private-pathscheck's fix clears it.- The
npm-token-syncedcheck reads npm 10's token listing, where a revoked token carries its revocation time; it reported thatnpm token list --jsonprinted no list of tokens. - A release no longer fails in the release checkout of a repository whose working tree holds an uncommitted
go.work: every program the release starts, the strictcli schema dump's entry-point detection, the preflight checks, and the packed-artifact listing included, gets the release'sGOWORK(the checkout's own committedgo.work, or off), so Go never picks up the working tree'sgo.workfrom the checkout below it. - The PyPI binary wheels a pypi go-binary pipeline publishes carry the project's readme as their description, with its content type, and its keywords and classifiers, so the PyPI project page shows the readme; a readme whose suffix names no content type, or a readme table without one, is refused.
- rlsbl scaffold removes the stored merge base of a file it no longer renders when the file was deleted already, as its refusal of an edited file of that sort says to do; the base was left behind under .strictmetadata/.scaffold-bases/.
- A release no longer builds a pypi target whose only pipelines are go-binary pipelines: its wheels are assembled in CI from the release archives, and the local
uv buildmade a package that never shipped, and failed for a pyproject.toml declaring no build system. rlsbl release run --watchandrelease resume --watchwait up to five minutes and twenty seconds for the npm and PyPI listings to show a version CI published, longer than npm's CDN serves a cached package document; with 50 seconds, a publish that succeeded was reported as never reaching npm.- A commit rlsbl makes leaves out a path whose working tree matches HEAD while its index does not, such as a scaffolded file deleted through saferm (which stages the deletion) and written back unchanged by the next
rlsbl scaffold; safegit refused the whole commit, so the scaffold failed after writing its files. - The
confidential-namescheck and the release scan every commit a push of the branch carries (from origin's branch to the release commit): each commit message and every text file a commit adds or changes, so a name added and removed again before the push is refused, naming the commit, the path, and the term. Before, only the current tree and the published texts were scanned. - A releasable's tags are recognized only as its tag format's prefix, a
MAJOR.MINOR.PATCHversion, then the format's suffix, everywhere: an identity'stag_patternsglob (v*) no longer claimsvideo-proc@v0.1.0or makes that tag's owner ambiguous, and a workspace's publish router judges the published tag by the same rule, its wait-for-ci job naming the matched tag scheme in an output each publish job's condition reads, instead of prefix conditions. Runrlsbl scaffoldto regenerate the publish workflows. rlsbl release scrubno longer refuses changelog commit ids that named no commit before its rewrite either (left by an earlier rewrite): it lists them and goes on, and refuses only an id that named a commit the rewrite replaced and names none after it. Such ids are first remapped through the rewrite's own commit map, then safegit's rewrite journal.rlsbl release scrubandrlsbl transition declassifygive a safegit history rewrite five minutes plus 50ms for each commit of the repository, instead of a fixed ten minutes an entire-history scrub of a long history exceeded, and require safegit 0.31.1, whose rewrites fit that bound.- A
rlsbl release scrubstopped by an out-of-date generated changelog is finished by regenerating it withrlsbl changelog generate --no-auto-commitand running the scrub again, which commits it with the scrub's records; the refusal used to say to commit the regenerated changelog, after which the scrub refused to resume. - A release is no longer refused for a dev overlay of a package no
pyproject.tomlof the releasable declares; the version-skew check asks PyPI only about overlaid packages the release depends on. - A release of a repository that commits a
go.workno longer puts Go commands outside its checkout in that workspace: the tests of a Go project that build throwaway modules failed inside the release, listing no package.