name: Release
on:
push:
tags:
- 'v[0-9]+.*'
workflow_dispatch:
permissions:
contents: write
id-token: write
env:
CARGO_TERM_COLOR: always
jobs:
build:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
archive: tar.gz
- target: x86_64-unknown-linux-musl
os: ubuntu-latest
archive: tar.gz
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
archive: tar.gz
cross: true
- target: x86_64-apple-darwin
os: macos-latest
archive: tar.gz
- target: aarch64-apple-darwin
os: macos-latest
archive: tar.gz
- target: x86_64-pc-windows-msvc
os: windows-latest
archive: zip
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Get version from tag
id: version
shell: bash
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install musl-tools (Linux musl)
if: matrix.target == 'x86_64-unknown-linux-musl'
run: sudo apt-get update && sudo apt-get install -y musl-tools
- name: Install cross-compilation tools (Linux ARM64)
if: matrix.cross == true
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Build release binary
run: cargo build --release --target ${{ matrix.target }}
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
- name: Create archive (Unix)
if: matrix.os != 'windows-latest'
run: |
mkdir -p dist
cp target/${{ matrix.target }}/release/deadbranch dist/
MAN_PAGE=$(find target/${{ matrix.target }}/release/build -name "deadbranch.1" | head -1)
cp "$MAN_PAGE" dist/
cp README.md LICENSE dist/ 2>/dev/null || true
cd dist
tar -czf ../deadbranch-${{ steps.version.outputs.version }}-${{ matrix.target }}.tar.gz *
- name: Create archive (Windows)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path dist
Copy-Item "target/${{ matrix.target }}/release/deadbranch.exe" -Destination "dist/"
Copy-Item "README.md" -Destination "dist/" -ErrorAction SilentlyContinue
Copy-Item "LICENSE" -Destination "dist/" -ErrorAction SilentlyContinue
Compress-Archive -Path "dist/*" -DestinationPath "deadbranch-${{ steps.version.outputs.version }}-${{ matrix.target }}.zip"
- name: Upload release asset
uses: softprops/action-gh-release@v2
with:
files: |
deadbranch-${{ steps.version.outputs.version }}-${{ matrix.target }}.${{ matrix.archive }}
publish-crates:
name: Publish to crates.io
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Publish to crates.io
run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
publish-npm:
name: Publish to npm
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- name: Publish to npm (with provenance)
working-directory: pkg/npm
run: npm publish --access public --provenance
publish-homebrew:
name: Publish to Homebrew tap
needs: build
runs-on: ubuntu-latest
steps:
- name: Get version from tag
id: version
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Download release tarballs and compute SHA256
id: sha256
run: |
BASE="https://github.com/armgabrielyan/deadbranch/releases/download/v${{ steps.version.outputs.version }}"
V="${{ steps.version.outputs.version }}"
download_with_retry() {
local URL="$1"
local OUT="$2"
local MAX_ATTEMPTS=10
local WAIT=15
for attempt in $(seq 1 $MAX_ATTEMPTS); do
HTTP_CODE=$(curl -sL -w "%{http_code}" "$URL" -o "$OUT")
if [ "$HTTP_CODE" = "200" ]; then
echo "Downloaded $URL (attempt $attempt)"
return 0
fi
echo "Attempt $attempt/$MAX_ATTEMPTS: got HTTP $HTTP_CODE for $URL, retrying in ${WAIT}s..."
sleep $WAIT
done
echo "Failed to download $URL after $MAX_ATTEMPTS attempts"
return 1
}
download_with_retry "$BASE/deadbranch-${V}-x86_64-apple-darwin.tar.gz" x86_64-apple-darwin.tar.gz
download_with_retry "$BASE/deadbranch-${V}-aarch64-apple-darwin.tar.gz" aarch64-apple-darwin.tar.gz
download_with_retry "$BASE/deadbranch-${V}-x86_64-unknown-linux-gnu.tar.gz" x86_64-linux-gnu.tar.gz
download_with_retry "$BASE/deadbranch-${V}-aarch64-unknown-linux-gnu.tar.gz" aarch64-linux-gnu.tar.gz
echo "x86_64_darwin=$(sha256sum x86_64-apple-darwin.tar.gz | awk '{print $1}')" >> $GITHUB_OUTPUT
echo "aarch64_darwin=$(sha256sum aarch64-apple-darwin.tar.gz | awk '{print $1}')" >> $GITHUB_OUTPUT
echo "x86_64_linux=$(sha256sum x86_64-linux-gnu.tar.gz | awk '{print $1}')" >> $GITHUB_OUTPUT
echo "aarch64_linux=$(sha256sum aarch64-linux-gnu.tar.gz | awk '{print $1}')" >> $GITHUB_OUTPUT
- name: Checkout deadbranch (main repo)
uses: actions/checkout@v6
with:
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
ref: main
fetch-depth: 0
path: deadbranch
- name: Checkout homebrew-tap
uses: actions/checkout@v6
with:
repository: armgabrielyan/homebrew-tap
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
path: homebrew-tap
- name: Update formula files
run: |
patch_formula() {
local FORMULA="$1"
local V="${{ steps.version.outputs.version }}"
# Preserve any trailing comment (e.g. # x-release-please-version) on the version line
sed -i "s/\(version \"\)[^\"]*\(\"[^#]*\)\(#.*\)\?/\1${V}\2\3/" "$FORMULA"
sed -i "/x86_64-apple-darwin\.tar\.gz\"/{n;s/sha256 \".*\"/sha256 \"${{ steps.sha256.outputs.x86_64_darwin }}\"/}" "$FORMULA"
sed -i "/aarch64-apple-darwin\.tar\.gz\"/{n;s/sha256 \".*\"/sha256 \"${{ steps.sha256.outputs.aarch64_darwin }}\"/}" "$FORMULA"
sed -i "/x86_64-unknown-linux-gnu\.tar\.gz\"/{n;s/sha256 \".*\"/sha256 \"${{ steps.sha256.outputs.x86_64_linux }}\"/}" "$FORMULA"
sed -i "/aarch64-unknown-linux-gnu\.tar\.gz\"/{n;s/sha256 \".*\"/sha256 \"${{ steps.sha256.outputs.aarch64_linux }}\"/}" "$FORMULA"
}
patch_formula "deadbranch/pkg/homebrew/deadbranch.rb"
patch_formula "homebrew-tap/Formula/deadbranch.rb"
- name: Commit and push to homebrew-tap
run: |
cd homebrew-tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/deadbranch.rb
git commit -m "chore: update deadbranch to v${{ steps.version.outputs.version }}"
git push origin main
- name: Commit and push pkg/homebrew to main repo
run: |
cd deadbranch
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add pkg/homebrew/deadbranch.rb
git commit -m "chore: update homebrew formula to v${{ steps.version.outputs.version }}"
git push origin main