Skip to content

Release and packaging runbook ​

State: release preparation authorized (Sep 2, 2026). An earlier v0.3.0 tag attempt triggered nothing (fork Actions quirk) and was deleted; zero releases exist. The working tree is now version 0.4.0 in Cargo.toml. After the release workflow lands on main and its branch smoke run passes, run this top to bottom with that version.

0. Cut, verify, and publish the release ​

bash
git tag v0.4.0 && git push origin v0.4.0

Then verify a run appeared (gh run list --repo kreatzzz/woofer). A tag push runs the complete build and verification matrix but does not publish a GitHub release. The workflow also accepts a manual dispatch: a branch run is an isolated smoke build named 0.4.0-dev.<run-number>, while a dispatch from the release tag can publish only when the publish input is explicitly set to true.

After the tag run is green, start the publish pass from that same tag:

bash
gh workflow run Release --repo kreatzzz/woofer --ref v0.4.0 -f publish=true

The assemble job validates every name, archive path, and checksum before the publish job uploads anything. Each successful build contains:

  • Linux x86_64 and arm64 portable .tar.gz archives plus AppImages, built with pinned, SHA-256-verified AppImage tools;
  • Windows x86_64 and arm64 portable .zip archives plus per-user Inno Setup installers;
  • one universal macOS DMG; and
  • a sorted checksums.txt covering every asset.

Windows Authenticode signing is optional, enabled only when both documented certificate secrets exist. macOS signing and notarization are optional too, but require the complete six-secret Apple contract; otherwise the DMG is ad-hoc/unsigned and needs the usual first-open approval. Tag-push smoke runs never receive signing secrets.

1. Homebrew tap (~10 min, fully scriptable) ​

bash
gh repo create kreatzzz/homebrew-tap --public --clone=false
git clone https://github.com/kreatzzz/homebrew-tap /tmp/tap && cd /tmp/tap
mkdir -p Casks

Casks/woofer.rb:

ruby
cask "woofer" do
  version "0.4.0"
  sha256 "SHA256_OF_THE_DMG"   # from the release's checksums.txt

  url "https://github.com/kreatzzz/woofer/releases/download/v#{version}/woofer-v#{version}-macos-universal.dmg"
  name "Woofer"
  desc "Fast, lightweight, native Spotify client"
  homepage "https://github.com/kreatzzz/woofer"

  livecheck do
    url :url
    strategy :github_latest
  end

  app "Woofer.app"
end

Commit, push. Users: brew install kreatzzz/tap/woofer. Every future release: bump version + sha256 in one tap commit. If the first DMG is unsigned, put the first-open note in the README: right-click → Open, or xattr -cr /Applications/Woofer.app. Add the direct release URL only after the explicit publish pass has created a public asset.

2. AUR (~20 min, needs the user's aur.archlinux.org account + SSH key) ​

Two packages, each pushed to aur@aur.archlinux.org:<pkg>.git:

woofer (release tarball, x86_64):

sh
pkgname=woofer
pkgver=0.4.0
pkgrel=1
pkgdesc="Fast, lightweight, native Spotify client built with Rust and egui"
arch=('x86_64')
url="https://github.com/kreatzzz/woofer"
license=('MIT')
depends=('alsa-lib' 'libpulse' 'wayland' 'libxkbcommon')
conflicts=('woofer-git')
source=("$pkgname-$pkgver.tar.gz::$url/releases/download/v$pkgver/woofer-v$pkgver-x86_64-unknown-linux-gnu.tar.gz")
sha256sums=('FILL_FROM_checksums.txt')
package() {
  cd "$srcdir/$pkgname-v$pkgver-x86_64-unknown-linux-gnu"
  install -Dm755 woofer "$pkgdir/usr/bin/woofer"
  install -Dm644 packaging/applications/woofer.desktop \
    "$pkgdir/usr/share/applications/woofer.desktop"
  install -Dm644 packaging/icons/woofer.svg \
    "$pkgdir/usr/share/icons/hicolor/scalable/apps/woofer.svg"
  install -Dm644 LICENSE "$pkgdir/usr/share/licenses/woofer/LICENSE"
}

Validate with makepkg -f (or namcap), then git init && git add . && git commit && git push aur:woofer.git. Test with yay -S woofer in a clean chroot if possible.

woofer-git: same shape, makedepends=('cargo' 'git'), source=("$pkgname::git+$url.git"), pkgver() from git describe, build with cargo build --release --locked, same package() installs.

3. winget (Windows; the bureaucratic one) ​

  1. Fork microsoft/winget-pkgs under kreatzzz, shallow-clone it.
  2. Add manifests/k/kreatzzz/Woofer/0.4.0/ with three YAML files:
    • kreatzzz.Woofer.yaml — PackageIdentifier: kreatzzz.Woofer, PackageVersion: 0.4.0, PackageLocale, Publisher: kreatzzz, PackageName: Woofer, License: MIT, ShortDescription, Moniker: woofer.
    • kreatzzz.Woofer.installer.yaml — InstallerType: inno, both architectures pointing at the GitHub …-setup.exe URLs, each with its sha256 from checksums.txt, and InstallerSwitches: { Silent: /VERYSILENT /SUPPRESSMSGBOXES /NORESTART, SilentWithProgress: /SILENT }, AppsAndFeaturesEntries with ProductCode if the .iss declares one.
    • kreatzzz.Woofer.locale.en-US.yaml — description, tags, homepage.
  3. Validate locally with winget validate (on Windows) or the winget-pkgs CI, then open the PR with their template. The bot verifies the URLs and hashes; a human reviews (1-3 days). First-time submitters need a seasoned GitHub account — having the tap and AUR package public first helps the review.

Future versions: a new version folder per release.

After the first release ​

  • Bump the tap (version + sha256) — one commit.
  • docs/_guide/download.md records the paused release state and the source install path; add direct package links there when Homebrew/AUR/winget are live.
  • The update checker (src/updates.rs) watches kreatzzz/woofer/releases/latest — it starts working from the first real release.

Woofer is independent software, not affiliated with or endorsed by Spotify AB.