name: Release
on:
push:
tags:
- 'v*'
env:
CARGO_TERM_COLOR: always
jobs:
verify-tag-on-main:
name: Verify Tag is on Main
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Verify tag points to main branch
run: |
if ! git branch -r --contains "${{ github.ref_name }}" | grep -q 'origin/master'; then
echo "::error::Tag ${{ github.ref_name }} is not on the 'main' branch."
echo "::error::Releases must be created from main. Merge develop → main first."
echo "::error::See RELEASE.md for the release process."
exit 1
fi
echo "Tag ${{ github.ref_name }} is on main branch"
build-binaries:
name: Build Binary (${{ matrix.target }})
runs-on: ${{ matrix.os }}
needs: [verify-tag-on-main]
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact_name: netspeed-cli
asset_name: netspeed-cli-x86_64-linux-gnu
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
artifact_name: netspeed-cli
asset_name: netspeed-cli-aarch64-linux-gnu
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
artifact_name: netspeed-cli
asset_name: netspeed-cli-x86_64-linux-musl
- os: ubuntu-latest
target: aarch64-unknown-linux-musl
artifact_name: netspeed-cli
asset_name: netspeed-cli-aarch64-linux-musl
- os: macos-latest
target: x86_64-apple-darwin
artifact_name: netspeed-cli
asset_name: netspeed-cli-x86_64-macos
- os: macos-latest
target: aarch64-apple-darwin
artifact_name: netspeed-cli
asset_name: netspeed-cli-aarch64-macos
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact_name: netspeed-cli.exe
asset_name: netspeed-cli-x86_64-windows.exe
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache dependencies
uses: Swatinem/rust-cache@v2
- name: Install cross-compilation tools (aarch64 Linux GNU)
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Configure aarch64 linker
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
mkdir -p .cargo
cat > .cargo/config.toml << 'EOF'
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
EOF
- name: Install musl tools (x86_64)
if: matrix.target == 'x86_64-unknown-linux-musl'
run: |
sudo apt-get update
sudo apt-get install -y musl-tools
- name: Install cross (aarch64 musl)
if: matrix.target == 'aarch64-unknown-linux-musl'
run: cargo install cross --locked
- name: Build release (cross)
if: matrix.target == 'aarch64-unknown-linux-musl'
run: cross build --release --target ${{ matrix.target }}
- name: Build release (native)
if: matrix.target != 'aarch64-unknown-linux-musl'
run: cargo build --release --target ${{ matrix.target }}
- name: Prepare artifact
shell: bash
run: |
mkdir -p dist
cp "target/${{ matrix.target }}/release/${{ matrix.artifact_name }}" dist/
- name: Upload artifact
uses: actions/upload-artifact@v6
with:
name: ${{ matrix.asset_name }}
path: dist/${{ matrix.artifact_name }}
publish-github-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [build-binaries]
permissions:
contents: write
steps:
- uses: actions/checkout@v6
- uses: actions/download-artifact@v7
with:
path: release-assets
merge-multiple: true
- name: Generate SHA256 checksums
run: |
cd release-assets
sha256sum * > SHA256SUMS.txt
cat SHA256SUMS.txt
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
path: .
artifact-name: sbom.spdx.json
output-file: release-assets/sbom.spdx.json
format: spdx-json
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release delete "${{ github.ref_name }}" --yes --repo "${{ github.repository }}" 2>/dev/null || true
gh release create "${{ github.ref_name }}" \
--title "${{ github.ref_name }}" \
--generate-notes \
--repo "${{ github.repository }}"
- name: Upload assets to release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload "${{ github.ref_name }}" \
release-assets/* \
--repo "${{ github.repository }}" \
--clobber
- name: Update Homebrew formula
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ github.ref_name }}"
VERSION_NO_V="${VERSION#v}"
SHA256=$(curl -sL "https://github.com/${{ github.repository }}/archive/refs/tags/${VERSION}.tar.gz" | shasum -a 256 | awk '{print $1}')
# Update formula file
sed -i "s/version \".*\"/version \"${VERSION_NO_V}\"/" netspeed-cli.rb
sed -i "s|url \".*\"|url \"https://github.com/${{ github.repository }}/releases/download/${VERSION}/netspeed-cli-${VERSION_NO_V}.tar.gz\"|" netspeed-cli.rb
sed -i "s/sha256 \".*\"/sha256 \"${SHA256}\"/" netspeed-cli.rb
# Commit and push to master branch
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add netspeed-cli.rb
git commit -m "chore: update formula to ${VERSION}"
git push origin HEAD:master
publish-crates-io:
name: Publish to crates.io
runs-on: ubuntu-latest
needs: [publish-github-release]
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- name: Cache dependencies
uses: Swatinem/rust-cache@v2
- name: Verify tests pass
run: cargo test --verbose
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish --allow-dirty