name: Release
on:
push:
tags:
- "v*"
permissions:
contents: read
jobs:
build-macos:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10
- name: Setup Rust
uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with:
toolchain: stable
- name: Add targets
run: |
rustup target add aarch64-apple-darwin
rustup target add x86_64-apple-darwin
- name: Build arm64
run: cargo build --release --target aarch64-apple-darwin
- name: Build x86_64
run: cargo build --release --target x86_64-apple-darwin
- name: Create universal binary
run: |
mkdir -p release
lipo -create \
target/aarch64-apple-darwin/release/headroom \
target/x86_64-apple-darwin/release/headroom \
-output release/headroom
- name: Get version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Create tarball
env:
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
cd release
tar -czvf headroom-${VERSION}-macos-universal.tar.gz headroom
- name: Calculate SHA256
id: sha256
env:
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
SHA256=$(shasum -a 256 release/headroom-${VERSION}-macos-universal.tar.gz | awk '{print $1}')
echo "SHA256=$SHA256" >> $GITHUB_OUTPUT
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: macos-universal
path: release/headroom-${{ steps.version.outputs.VERSION }}-macos-universal.tar.gz
- name: Save SHA256
env:
SHA256: ${{ steps.sha256.outputs.SHA256 }}
run: echo "$SHA256" > sha256-macos-universal.txt
- name: Upload SHA256
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: sha256-macos-universal
path: sha256-macos-universal.txt
build-linux-x86_64:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10
- name: Setup Rust
uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with:
toolchain: stable
- name: Build
run: cargo build --release
- name: Get version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Create tarball
env:
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
mkdir -p release
cp target/release/headroom release/
cd release
tar -czvf headroom-${VERSION}-linux-x86_64.tar.gz headroom
- name: Calculate SHA256
id: sha256
env:
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
SHA256=$(sha256sum release/headroom-${VERSION}-linux-x86_64.tar.gz | awk '{print $1}')
echo "SHA256=$SHA256" >> $GITHUB_OUTPUT
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: linux-x86_64
path: release/headroom-${{ steps.version.outputs.VERSION }}-linux-x86_64.tar.gz
- name: Save SHA256
env:
SHA256: ${{ steps.sha256.outputs.SHA256 }}
run: echo "$SHA256" > sha256-linux-x86_64.txt
- name: Upload SHA256
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: sha256-linux-x86_64
path: sha256-linux-x86_64.txt
build-linux-aarch64:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10
- name: Setup Rust
uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with:
toolchain: stable
- name: Install cross
run: cargo install cross --git https://github.com/cross-rs/cross
- name: Build with cross
run: cross build --release --target aarch64-unknown-linux-gnu
- name: Get version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Create tarball
env:
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
mkdir -p release
cp target/aarch64-unknown-linux-gnu/release/headroom release/
cd release
tar -czvf headroom-${VERSION}-linux-aarch64.tar.gz headroom
- name: Calculate SHA256
id: sha256
env:
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
SHA256=$(sha256sum release/headroom-${VERSION}-linux-aarch64.tar.gz | awk '{print $1}')
echo "SHA256=$SHA256" >> $GITHUB_OUTPUT
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: linux-aarch64
path: release/headroom-${{ steps.version.outputs.VERSION }}-linux-aarch64.tar.gz
- name: Save SHA256
env:
SHA256: ${{ steps.sha256.outputs.SHA256 }}
run: echo "$SHA256" > sha256-linux-aarch64.txt
- name: Upload SHA256
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: sha256-linux-aarch64
path: sha256-linux-aarch64.txt
build-windows:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10
- name: Setup Rust
uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with:
toolchain: stable
- name: Build
run: cargo build --release
- name: Get version
id: version
shell: bash
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Create zip
shell: pwsh
env:
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
New-Item -ItemType Directory -Force -Path release
Copy-Item target\release\headroom.exe release\
Compress-Archive -Path release\headroom.exe -DestinationPath release\headroom-${env:VERSION}-windows-x86_64.zip
- name: Calculate SHA256
id: sha256
shell: pwsh
env:
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
$hash = (Get-FileHash release\headroom-${env:VERSION}-windows-x86_64.zip -Algorithm SHA256).Hash.ToLower()
echo "SHA256=$hash" >> $env:GITHUB_OUTPUT
- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: windows-x86_64
path: release/headroom-${{ steps.version.outputs.VERSION }}-windows-x86_64.zip
- name: Save SHA256
shell: bash
env:
SHA256: ${{ steps.sha256.outputs.SHA256 }}
run: echo "$SHA256" > sha256-windows-x86_64.txt
- name: Upload SHA256
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: sha256-windows-x86_64
path: sha256-windows-x86_64.txt
release:
needs: [build-macos, build-linux-x86_64, build-linux-aarch64, build-windows]
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ steps.version.outputs.VERSION }}
version_num: ${{ steps.version.outputs.VERSION_NUM }}
macos_sha256: ${{ steps.macos_sha256.outputs.SHA256 }}
windows_sha256: ${{ steps.windows_sha256.outputs.SHA256 }}
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10
- name: Get version
id: version
run: |
VERSION="${GITHUB_REF#refs/tags/}"
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
echo "VERSION_NUM=${VERSION#v}" >> $GITHUB_OUTPUT
- name: Download all artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with:
path: artifacts
- name: Prepare release files
run: |
mkdir -p release
mv artifacts/macos-universal/*.tar.gz release/
mv artifacts/linux-x86_64/*.tar.gz release/
mv artifacts/linux-aarch64/*.tar.gz release/
mv artifacts/windows-x86_64/*.zip release/
- name: Create checksums file
env:
VERSION: ${{ steps.version.outputs.VERSION }}
run: |
cd release
cat ../artifacts/sha256-macos-universal/sha256-macos-universal.txt | while read hash; do echo "$hash headroom-${VERSION}-macos-universal.tar.gz"; done > checksums.txt
cat ../artifacts/sha256-linux-x86_64/sha256-linux-x86_64.txt | while read hash; do echo "$hash headroom-${VERSION}-linux-x86_64.tar.gz"; done >> checksums.txt
cat ../artifacts/sha256-linux-aarch64/sha256-linux-aarch64.txt | while read hash; do echo "$hash headroom-${VERSION}-linux-aarch64.tar.gz"; done >> checksums.txt
cat ../artifacts/sha256-windows-x86_64/sha256-windows-x86_64.txt | while read hash; do echo "$hash headroom-${VERSION}-windows-x86_64.zip"; done >> checksums.txt
mv checksums.txt headroom-${VERSION}-checksums.txt
- name: Get macOS SHA256
id: macos_sha256
run: |
SHA256=$(cat artifacts/sha256-macos-universal/sha256-macos-universal.txt)
echo "SHA256=$SHA256" >> $GITHUB_OUTPUT
- name: Get Windows SHA256
id: windows_sha256
run: |
SHA256=$(cat artifacts/sha256-windows-x86_64/sha256-windows-x86_64.txt)
echo "SHA256=$SHA256" >> $GITHUB_OUTPUT
- name: Check for release notes
id: release_notes
run: |
if [ -f "RELEASE_NOTES.md" ]; then
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Create Release (with custom notes)
if: steps.release_notes.outputs.exists == 'true'
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda with:
files: |
release/headroom-${{ steps.version.outputs.VERSION }}-macos-universal.tar.gz
release/headroom-${{ steps.version.outputs.VERSION }}-linux-x86_64.tar.gz
release/headroom-${{ steps.version.outputs.VERSION }}-linux-aarch64.tar.gz
release/headroom-${{ steps.version.outputs.VERSION }}-windows-x86_64.zip
release/headroom-${{ steps.version.outputs.VERSION }}-checksums.txt
body_path: RELEASE_NOTES.md
append_body: true
- name: Create Release (auto-generated notes)
if: steps.release_notes.outputs.exists == 'false'
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda with:
files: |
release/headroom-${{ steps.version.outputs.VERSION }}-macos-universal.tar.gz
release/headroom-${{ steps.version.outputs.VERSION }}-linux-x86_64.tar.gz
release/headroom-${{ steps.version.outputs.VERSION }}-linux-aarch64.tar.gz
release/headroom-${{ steps.version.outputs.VERSION }}-windows-x86_64.zip
release/headroom-${{ steps.version.outputs.VERSION }}-checksums.txt
generate_release_notes: true
body: |
## Installation
| Platform | Command |
|----------|---------|
| **macOS (Homebrew)** | `brew install M-Igashi/tap/headroom` |
| **Windows (winget)** | `winget install M-Igashi.headroom` |
| **Cargo** | `cargo install headroom` (ffmpeg must be installed separately) |
Package managers (Homebrew, winget) install ffmpeg automatically. mp3rgain is built-in — no separate installation needed.
## Checksums
See `headroom-${{ steps.version.outputs.VERSION }}-checksums.txt` for SHA256 checksums of all binaries.
publish-cargo:
needs: [release]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10
- name: Setup Rust
uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 with:
toolchain: stable
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish --token $CARGO_REGISTRY_TOKEN
update-homebrew:
needs: [release]
runs-on: ubuntu-latest
steps:
- name: Update Homebrew formula
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
VERSION: ${{ needs.release.outputs.version }}
VERSION_NUM: ${{ needs.release.outputs.version_num }}
SHA256: ${{ needs.release.outputs.macos_sha256 }}
run: |
git clone https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/M-Igashi/homebrew-tap.git
cd homebrew-tap
cat > Formula/headroom.rb << 'FORMULA'
class Headroom < Formula
desc "Audio loudness analyzer and gain adjustment tool for mastering and DJ workflows"
homepage "https://github.com/M-Igashi/headroom"
url "https://github.com/M-Igashi/headroom/releases/download/VERSION_PLACEHOLDER/headroom-VERSION_PLACEHOLDER-macos-universal.tar.gz"
sha256 "SHA256_PLACEHOLDER"
version "VERSION_NUM_PLACEHOLDER"
license "MIT"
depends_on "ffmpeg"
def install
bin.install "headroom"
end
def caveats
<<~EOS
mp3rgain is now built-in as a library dependency.
No separate installation required for lossless MP3 gain adjustment.
EOS
end
test do
assert_match "headroom", shell_output("#{bin}/headroom --version")
end
end
FORMULA
sed -i "s|VERSION_PLACEHOLDER|${VERSION}|g" Formula/headroom.rb
sed -i "s|SHA256_PLACEHOLDER|${SHA256}|g" Formula/headroom.rb
sed -i "s|VERSION_NUM_PLACEHOLDER|${VERSION_NUM}|g" Formula/headroom.rb
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/headroom.rb
git commit -m "headroom ${VERSION_NUM}"
git push