DocsWorking on Yarrix
Releasing (maintainers)
Releases are built, signed and published from a maintainer's own machine. No GitHub runner builds or signs anything. One command does it:
MINISIGN_SECRET_KEY=/path/outside/the/repo/yarrix.key scripts/release/cut.sh 0.1.0
<version> is semver without the v (the tag is v0.1.0); a version with a - (0.1.0-rc.1) is a prerelease.
One-time setup#
- The signing key. The public half is
minisign.pubin the repo. Keep the secret key file outside the repository (cut.shrefuses a key inside it) and pointMINISIGN_SECRET_KEYat it. If it has a password, setMINISIGN_PASSWORDor let minisign prompt. Never commit a key. gh.gh auth loginas someone who can create releases on the repository. A dry run needs nogh.- The repository.
cut.shusesorigin'sowner/name. Override with--repo owner/nameorYARRIX_GH_REPO. Images go toghcr.io/<owner lowercased>/yarrixand.../yarrix-agent(YARRIX_IMAGE_NAMESPACEoverrides); for them rundocker login ghcr.iofirst. - Tools on the build machine: bun 1.4.4, Rust through rustup with the targets
aarch64-apple-darwin,x86_64-apple-darwin,x86_64-pc-windows-gnu(and mingw-w64), Docker with buildx, zip, makensis, minisign, jq, python3, cargo-deny, gitleaks. See the header ofscripts/release/dry-run.sh. - makensis builds the Windows
setup.exe(brew install makensis; 3.13 on macOS 27 is tested). It must run under a UTF-8 locale: under the C locale the Homebrew build aborts withstd::bad_alloc(exit 134) on a Unicode installer.package.shpicks a UTF-8 locale the machine has (C.UTF-8oren_US.UTF-8) and fails unless makensis reports writing a Unicode installer.YARRIX_NSIS_ANSI=1builds the ANSI installer for a local check only;cut.shrefuses to publish it, so unset it before a release.
What cut.sh does, in order#
- Refuses unless the working tree is clean and you are on
mainat the same commit asorigin/main, and the tag does not exist yet. - Runs
scripts/ci/local.sh --strict, which includesscripts/gen-third-party-notices.ts --check, so a staleTHIRD_PARTY_NOTICES.mdstops the release. A skipped stage fails it.--allow-skipsruns it without--strictand prints every SKIP it accepted, so you can see what was not checked. - Builds every artifact with
scripts/release/dry-run.sh v<version>(hub binaries, agents, Windows zip and setup.exe, checksums, SBOM), stamped with the version and trusting the public key. - Checks that
LICENSE,NOTICEandTHIRD_PARTY_NOTICES.mdare in the release files and inside the Windows zip. (Both Docker images carry them in/licenses.) - Writes release notes from
changes/unreleased/*.json(scripts/release/changelog-release.py, run on a scratch copy, so the working tree stays clean). - Signs
MANIFEST.jsonandSHA256SUMSwithscripts/release/sign-release.sh --local, which first re-checks every file against both, then verifies the signatures against the public key. - Tags
v<version>, pushes the tag, and runsgh release create --draftwith every file. The release stays a draft. - With
--push-images, builds and pushes the two multi-arch images. Without it nothing is pushed to a registry (binaries only).
--dry-run stops before step 7: no tag, no gh, no push (with --push-images the images are built and not pushed). A git state a real run would refuse is printed as WOULD REFUSE instead of stopping. --skip-checks (dry run only) skips step 2. Artifacts land in dist/release/v<version>/, the files to upload in dist/release/v<version>.upload/, and the notes in dist/release/v<version>.notes.md.
After cut.sh#
- Open the draft on GitHub, read the notes, and check the files. Verify a download as in verify-release.md.
- Publish the draft by hand.
- Consume the change entries so the next release does not repeat them:
python3 scripts/release/changelog-release.py <version>, then commitchangelog.jsonand the removedchanges/unreleased/*.jsontomain.
If something fails#
Nothing before step 7 changes the repository or the hosting side, so rerun cut.sh after fixing the cause. If step 7 fails after the tag was pushed, delete the tag (git push origin :refs/tags/v<version>, git tag -d v<version>) and any partial draft before retrying.