Files
lightcraft/docs/releasing.md
T
Andrew FrahnandClaude Opus 5.5 6cbc0eb5a9 Phase 0: configurable brand, MIT licence, plan/ and Immich tracker
- brand.toml is the only place the product name lives; every crate and app
  reads it through dac-brand (env vars with legacy fallback, settings folder
  with copy-only migration, default library, preset extensions, i18n {app})
- cargo xtask brand check|test, run|install|package, docs, rename-crates,
  deny and immich; packaging files are templates rendered from brand.toml
- icons regenerated from brand/icon.svg; upstream branding removed
- MIT licence (segment and fetch stay Apache-2.0); cargo deny licence policy
- clean-room rules in AGENTS.md/CLAUDE.md; docs/upstream-merge.md
- plan/ rebuilt and committed; parity tracker reopens Classic rows, adds
  PLAN.md section 2 rows and the IMM Immich section; plan/immich.md and a
  pinned Immich test server

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 10:30:06 +11:00

5.3 KiB

Releasing the app

Names in angle brackets (<app>, <binary>, <cli>, <PREFIX>, <settings_dir>, …) are the values set in brand.toml; see the README.

The release pipeline is .github/workflows/release.yml. It runs on every push to the release branch. A maintainer can also dispatch it manually, with an optional version override such as 1.2.0-rc.1; the release environment's branch restrictions still apply.

Prepare and start a release

  1. Merge the release-ready changes into release.
  2. Set the workspace version in Cargo.toml (for example, with cargo xtask version set 1.2.0). For a manual workflow run, the version input can override the workspace version for that run. Use a semantic version such as 1.2.0 or 1.2.0-rc.1; versions containing a hyphen are marked as prereleases.
  3. Push to release, or dispatch the workflow on release (a dispatch on another branch is a dry run; see below).
  4. Check the workflow run and its artifacts. On success, the workflow creates or updates a draft GitHub Release named <app> v<version>, targeted at the commit that triggered the run. Review the draft and its SHA256SUMS.txt, then publish it in GitHub Releases when ready.

The workflow replaces assets when it updates an existing draft. It stops rather than overwriting a release that has already been published, so bump the version before producing another release.

Builds and artifacts

Release jobs build macOS universal, Windows x86/x64/ARM64, Linux x86_64/aarch64, FreeBSD x86_64, and the WASM web app. The platform scripts in packaging/ write their outputs to dist/release/ (the full list of files is the README's Downloads section):

  • macOS: app DMG and CLI ZIP.
  • Windows: MSI installer and portable ZIP for each architecture.
  • Linux: AppImage (with its .AppImage.zsync), .deb, .rpm, and .tar.gz for each architecture (packaging/linux/package.sh). Each AppImage embeds gh-releases-zsync|<owner>|<repo>|latest|<binary>-*-linux-<arch>.AppImage.zsync, so AppImageUpdate fetches only the changed blocks from the latest published (non-pre-) release.
  • Flatpak: a single-file .flatpak bundle for each architecture, repackaged from that architecture's Linux tarball (packaging/linux/flatpak-bundle.sh with packaging/linux/flatpak/<app_id>.bundle.yml; no Rust build). The from-source manifest <app_id>.yml is for Flathub; packaging-lint keeps their runtime and finish-args identical.
  • FreeBSD: <binary>-<version>-freebsd-x86_64.tar.gz, a /usr/local-style tree built in a FreeBSD 14.3 VM (packaging/freebsd/package.sh, the same packages as freebsd.yml). Install with tar -xzf <file> --strip-components 1 -C /usr/local.
  • Web: <binary>-web-<version>.zip.

Only the macOS, Windows and draft-release jobs use the release environment. The others sign nothing, so dispatching the workflow on a branch (gh workflow run release.yml --ref <branch>) dry-runs them: the signing jobs are refused by the environment's branch rule, and the release job, which needs them, is skipped.

The Linux builds run on Ubuntu 22.04 and target glibc 2.35 or newer. AppImages and binaries may also require system libraries for the windowing stack; the .deb and .rpm packages declare their runtime dependencies.

Release builds fetch the pinned storytold/craft-fonts revision and require it (CRAFT_FONTS_REQUIRED=1). Keep that pin deliberate when updating the workflow, and bump it (in release.yml, five jobs, and freebsd.yml) whenever craft-fonts adds a face a shipped language needs: a stale pin still builds, it just ships tofu (issue #319: v0.4.0 pinned a revision from before Noto Sans CJK SC, so Simplified Chinese had no glyphs). Before a release, check the pin against craft-fonts' fonts/manifest.txt and run CRAFT_FONTS_DIR=../craft-fonts cargo test -p dac-ui-egui i18n, whose glyph-coverage test checks the characters in available faces. CRAFT_FONTS_REQUIRED=1 now also makes the native build fail if the pinned manifest lacks Noto Sans CJK SC Regular (Hans) or BIZ UDPGothic Regular; the web build requires BIZ UDPGothic Regular and packages Noto Sans CJK SC as a separate asset.

Signing credentials

All credentials are stored as secrets in the GitHub release environment. Signing is optional: without platform signing credentials, packaging continues with unsigned artifacts and warnings. macOS notarization is a separate optional step; when its credentials are absent, a build with a signing identity is signed but not notarized. Configure only the platform credentials you need:

  • macOS signing: APPLE_CERTIFICATE, APPLE_CERTIFICATE_PASSWORD, and KEYCHAIN_PASSWORD. Notarization additionally needs all of APPLE_ID, APPLE_PASSWORD (an app-specific password), and APPLE_TEAM_ID.
  • Windows signing: either WINDOWS_CERTIFICATE and WINDOWS_CERTIFICATE_PASSWORD, or Azure Trusted Signing credentials: AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_SIGNING_ENDPOINT, AZURE_SIGNING_ACCOUNT, and AZURE_CERT_PROFILE.

Linux and web artifacts are not code-signed by this workflow. The release job computes SHA-256 checksums for the complete artifact set and attaches the checksum file to the draft release.