CI runs on merges to develop (and on fork pull requests); the release workflow builds the draft from a push to main. AGENTS.md, CONTRIBUTING.md and docs/releasing.md follow. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
6.2 KiB
Releasing FieldCraft
Releases are deliberate. Development lands on develop, the trunk; main holds released code
only. Fast-forwarding main to the chosen, verified develop commit builds every package and
creates a draft GitHub Release; a maintainer verifies the draft and publishes it. Pushes to
develop and tags never start a release, and nothing bumps the version automatically. The workflow is .github/workflows/release.yml; the packaging scripts
are in packaging/ and run the same way on a developer machine.
What a release contains
| Platform | Files | Script |
|---|---|---|
| macOS 11+, universal (arm64 + x86_64) | fieldcraft-<v>-macos-universal.dmg (FieldCraft.app on a drag-to-Applications image), fieldcraft-cli-<v>-macos-universal.zip |
packaging/macos/package.sh |
| Linux x86_64, glibc 2.35+ | fieldcraft-<v>-linux-x86_64.tar.gz (bin/, share/), fieldcraft-<v>-linux-x86_64.AppImage |
packaging/linux/package.sh |
| Windows x64 | fieldcraft-<v>-windows-x64.zip (fieldcraft.exe, fieldcraft-cli.exe) |
packaging/windows/package.ps1 |
Plus SHA256SUMS.txt and the notes from .github/release-notes.md followed by GitHub's
generated list of changes. Every package carries README.md, LICENSE-MIT, LICENSE-APACHE,
NOTICE and THIRD-PARTY-LICENSES.txt (on macOS in FieldCraft.app/Contents/Resources/Licenses).
The application id is io.github.jyviko.fieldcraft: the macOS bundle id, the Linux .desktop
entry and icon name, and the window's Wayland app_id / X11 class. The icons come from
assets/app-icon: icon.icns and Assets.car (macOS 26 and later) in the app bundle,
icon.ico embedded in fieldcraft.exe (apps/fieldcraft/build.rs), the iconset PNGs as the
Linux hicolor icons.
Signing
macOS. When the repository has the secrets below, the app, the dmg and the CLI are signed
with a Developer ID (hardened runtime, packaging/macos/entitlements.plist) and notarized, and
the tickets are stapled. Without them the build is ad-hoc signed, which runs on Apple silicon
but which Gatekeeper blocks on first launch until the user right-clicks › Open; a run warns
about it, and the release notes say which of the two the draft contains.
| Secret | What it is |
|---|---|
APPLE_CERTIFICATE |
The "Developer ID Application" certificate with its private key, exported as .p12 and base64-encoded (base64 -i cert.p12 | pbcopy) |
APPLE_CERTIFICATE_PASSWORD |
The .p12's password |
KEYCHAIN_PASSWORD |
Optional: the temporary CI keychain's password (random when unset) |
APPLE_ID |
The Apple ID used for notarization |
APPLE_PASSWORD |
An app-specific password for that Apple ID (appleid.apple.com › Sign-In and Security) |
APPLE_TEAM_ID |
The 10-character team id of the Developer ID |
Add them with gh secret set <NAME> -R jyviko/fieldcraft. With the certificate but without the
three notarization secrets the app is signed and not notarized. A dmg made locally with
packaging/macos/package.sh is ad-hoc signed unless MACOS_SIGN_IDENTITY names an identity
in the keychain.
Linux and Windows builds are not signed; the checksums are the integrity check. On Windows SmartScreen warns about an unsigned download (More info › Run anyway) until a code-signing certificate is added.
Choose and prepare the version
- Look at the previous published release (
gh release list -R jyviko/fieldcraft) and the changes since it, and choose one version for the batch: a patch for compatible fixes; a minor for new capabilities, and while on0.xalso for breaking changes (say what breaks in the notes);-rc.Nfor a release candidate.1.0is the owner's decision. - Set
[workspace.package] versionin the rootCargo.tomland runcargo update --workspace --offline, which changes only the workspace crates' versions inCargo.lock. Land it ondevelopthrough a pull request like any change, and let CI ondeveloppass. Note the commit to release.
Build the draft
git fetch origin
git push origin <commit>:main # fast-forward main to the verified develop commit
main holds released code only: it moves only by fast-forwarding to a verified develop
commit (a maintainer push; the branch is protected), never by merges, rewrites or force-pushes. The run builds the three platforms; when
all succeed, the last job checks that every file is there, writes SHA256SUMS.txt and the notes,
and creates the draft FieldCraft v<version> targeting the pushed commit. Pushing
main again with the same version rebuilds and replaces the draft's files (its notes are
kept). The job refuses a version whose tag exists or whose release is already published: bump
the version instead.
Verify and publish
Publishing is a maintainer's call; an agent preparing a release stops at the draft.
- Check the run succeeded for the intended commit and the draft targets it
(
gh release view v<version> -R jyviko/fieldcraft). - Download the assets into an empty folder (
gh release download v<version> -R jyviko/fieldcraft), runshasum -a 256 -c SHA256SUMS.txt, and check every platform's files are there. - Smoke-test what you can run: open the dmg, drag the app to Applications, launch it with
--sample cantilever; runfieldcraft-cli --versionfrom the zip or tar.gz; on Linux run the AppImage; on Windows unzip and startfieldcraft.exe. Look at the run's logs for the platforms you could not try (each job checks its own package). - Edit the notes: what is new, fixes, breaking changes, known limitations. Keep the install and signing paragraphs; never claim signing the notes don't state.
- Publish:
gh release edit v<version> -R jyviko/fieldcraft --draft=false --latest(a release candidate:--draft=false --prerelease --latest=false). Publishing creates the tag at the draft's commit; never push release tags by hand.
Dry runs
gh workflow run release.yml -R jyviko/fieldcraft --ref <branch> builds every package and
uploads them with the notes as the release-assets artifact of the run, without creating a
release. -f draft=true creates or updates the draft, and is accepted on main only.
Locally, packaging/macos/package.sh --arch aarch64 (or x86_64, universal) and
packaging/linux/package.sh write to dist/release/.