# Releasing Releases are automated by [release-plz](https://release-plz.dev). 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](https://www.conventionalcommits.org) (`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.` 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: ```bash 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](https://crates.io/settings/tokens) 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 ```bash cargo install soulseek-rs ``` Or download an archive from the [releases page](https://github.com/michel/soulseek-rs/releases), verify it against the adjacent `.sha256`, and extract the binary. ## Using the library ```bash cargo add soulseek-rs-lib ```