Files
soulseek-rs-modded/RELEASE.md
T
Michel de Graaf f09d550e4b ci: attach .deb and .rpm packages to releases and nightlies
Built by nfpm from the static musl binaries, with the man page and the
bash, zsh and fish completions. The names carry no version, so
releases/latest/download/soulseek-rs-amd64.deb stays a working link; the
nightly pair replaces itself on the rolling prerelease.
2026-09-21 12:58:09 +02:00

6.4 KiB

Releasing

Releases are automated by release-plz. You do not run cargo publish, edit versions, write changelog entries, or push tags by hand.

How it works

  1. Merge a PR to master using conventional commits (feat:, fix:, perf:, refactor:, docs:, chore:, or a ! / BREAKING CHANGE: footer for a major bump).
  2. .github/workflows/release.yml opens or updates a chore: release vX.Y.Z PR. It contains the semver bump in [workspace.package], the refreshed Cargo.lock, and the generated CHANGELOG.md entry. Review it like any other PR.
  3. Merging that PR releases, but only once CI has passed on the merge commit — a published crates.io version can be yanked but never withdrawn, so the Wait for CI job blocks the publish until the CI run for that exact commit is green:
    • tags vX.Y.Z and creates the GitHub release with the changelog as its notes,

    • publishes soulseek-rs-lib then soulseek-rs to crates.io (dependency order, waiting for the index between them),

    • builds and attaches binaries with .sha256 checksums for six targets:

      Archive Notes
      soulseek-rs-vX.Y.Z-x86_64-unknown-linux-musl.tar.gz static, any glibc
      soulseek-rs-vX.Y.Z-aarch64-unknown-linux-musl.tar.gz static, any glibc
      soulseek-rs-vX.Y.Z-x86_64-apple-darwin.tar.gz Intel Mac
      soulseek-rs-vX.Y.Z-aarch64-apple-darwin.tar.gz Apple Silicon
      soulseek-rs-vX.Y.Z-x86_64-pc-windows-msvc.zip
      soulseek-rs-vX.Y.Z-aarch64-pc-windows-msvc.zip
    • packages the two Linux binaries as soulseek-rs-amd64.deb, soulseek-rs-arm64.deb, soulseek-rs-x86_64.rpm and soulseek-rs-aarch64.rpm, with the man page and the bash, zsh and fish completions. The names carry no version, so releases/latest/download/soulseek-rs-amd64.deb is a link that keeps working,

    • rewrites Formula/soulseek-rs.rb in the michel/homebrew-tap repository so brew install michel/tap/soulseek-rs picks up the new macOS and Linux archives,

    • merges master back into develop, so the branch the work happens on carries the new version and changelog rather than drifting behind them.

Both crates always share one version, one tag, and one changelog — see release-plz.toml.

The version lives in one place, [workspace.package] in the root Cargo.toml, and release-plz owns it. Do not edit it by hand on develop: the back-merge relies on develop never touching that line, and an edit there turns every release into a conflict.

Nightly builds

.github/workflows/nightly.yml builds the tip of develop at 02:17 UTC every day. It resolves the commit once, builds the same six targets as a numbered release, packages the two Linux ones as soulseek-rs-nightly-*.deb and .rpm, verifies all sixteen files as one set, then replaces the mutable nightly prerelease and tag. Every nightly binary reports X.Y.Z+git<commit time, UTC>.<sha> instead of the crate version. The published release is smoke-tested through the curl and wget installer paths, and by installing the .deb and the .rpm.

Never enable GitHub's Immutable Releases on this repository: nightly replaces its assets and moves its tag, and a tag name burnt by that setting cannot be reused.

Use Actions → Nightly → Run workflow to force a build. The workflow always checks out develop, regardless of the ref selected in the dispatch form. The equivalent command is:

gh workflow run nightly.yml --ref develop

Nightly does not publish crates or update Homebrew. If a target fails, the previous nightly release stays available; use a manual run to retry.

One-time repository setup

  • Settings → Actions → General → Workflow permissions: enable Allow GitHub Actions to create and approve pull requests. Without it the release PR is never opened.
  • Settings → Secrets and variables → Actions: add CARGO_REGISTRY_TOKEN, a crates.io token scoped to publish-new and publish-update. Without it the tag and GitHub release still happen, but the crates.io publish fails.
  • Homebrew tap: create a public michel/homebrew-tap repository, then add a HOMEBREW_TAP_TOKEN secret — a fine-grained PAT with Contents: read and write on that repository only. GITHUB_TOKEN cannot reach another repository. The formula itself is generated by the workflow; nothing in the tap needs editing by hand.

Notes

  • A merge with no releasable commits (only docs:/chore:/test:) opens no release PR. That is intended.
  • The release PR does not run CI on its own, because GitHub does not trigger workflows for PRs opened with GITHUB_TOKEN. Pushing any commit to that branch yourself does start it — handy if you want the version bump validated before merging.
  • If one target's build fails, the other five still upload (fail-fast: false). To retry, run the Release workflow manually and set tag to the existing tag (e.g. v6.0.0); it rebuilds and re-uploads every target for that tag. Re-running the failed job from the Actions UI replays the old workflow file, so it is no use when the workflow is the thing that needs fixing.
  • To skip a release for a commit that would otherwise trigger one, use a chore: type.
  • If CI flakes on the release commit the publish is blocked, by design. The e2e suite talks to a real soulfind server over the network and does occasionally time out. To recover: re-run the failed CI job, wait for that run to go green, then re-run the Release workflow. The gate reads the newest CI run for the commit, so it will then pass. Never work around it by publishing by hand.
  • Release binaries are stripped via [profile.release] strip = true in the workspace Cargo.toml, so cargo install benefits too — not just the release archives.

Installing a release

cargo install soulseek-rs

Or download an archive from the releases page, verify it against the adjacent .sha256, and extract the binary.

Using the library

cargo add soulseek-rs-lib