name: Release
on:
push:
tags: ['v*.*.*']
workflow_dispatch:
permissions:
contents: write
jobs:
build:
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: ubuntu-latest, target: x86_64-unknown-linux-gnu, suffix: linux-x86_64, ext: '' }
- { os: ubuntu-latest, target: aarch64-unknown-linux-gnu, suffix: linux-aarch64, ext: '', cross: true }
- { os: macos-latest, target: x86_64-apple-darwin, suffix: macos-x86_64, ext: '' }
- { os: macos-latest, target: aarch64-apple-darwin, suffix: macos-aarch64, ext: '' }
- { os: windows-latest, target: x86_64-pc-windows-msvc, suffix: windows-x86_64, ext: '.exe' }
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
- name: Install cross-compile toolchain (linux/aarch64)
if: matrix.cross
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
mkdir -p .cargo
cat >> .cargo/config.toml <<EOF
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
EOF
- name: Build release
run: cargo build --release --locked --target ${{ matrix.target }}
- name: Package (unix)
if: runner.os != 'Windows'
shell: bash
run: |
name="agtop-${{ matrix.suffix }}"
mkdir -p "dist/$name"
cp "target/${{ matrix.target }}/release/agtop${{ matrix.ext }}" "dist/$name/"
cp README.md LICENSE "dist/$name/"
cd dist
tar -czf "${name}.tar.gz" "$name"
- name: Package (windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$name = "agtop-${{ matrix.suffix }}"
New-Item -ItemType Directory -Force -Path "dist/$name" | Out-Null
Copy-Item "target/${{ matrix.target }}/release/agtop${{ matrix.ext }}" "dist/$name/"
Copy-Item "README.md","LICENSE" "dist/$name/"
Compress-Archive -Path "dist/$name" -DestinationPath "dist/$name.zip" -Force
- uses: softprops/action-gh-release@v3
with:
files: |
dist/agtop-${{ matrix.suffix }}.tar.gz
dist/agtop-${{ matrix.suffix }}.zip
fail_on_unmatched_files: false
generate_release_notes: true
publish-crates:
name: Publish to crates.io
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- name: cargo publish
env:
CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
run: |
if [ -z "$CRATES_IO_TOKEN" ]; then
echo "::error::CRATES_IO_TOKEN secret not set"
exit 1
fi
# Skip cleanly if the version is already on crates.io (e.g. the
# tag was re-pushed for a docs-only re-roll). Hard-fail on any
# other publish error so silent breakage can't ship.
version=$(awk -F'"' '/^version[[:space:]]*=/{print $2; exit}' Cargo.toml)
if cargo search "agtop" --limit 1 | grep -qE "^agtop = \"$version\""; then
echo "agtop $version already on crates.io — skipping"
exit 0
fi
cargo publish --token "$CRATES_IO_TOKEN"
publish-npm:
name: Publish to npm (@mbrassey/agtop)
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v4
with:
node-version: "20"
registry-url: "https://registry.npmjs.org"
- name: Build npm tarball
run: bash packages/npm/build.sh
- name: Publish (skip if version already on npm)
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
if [ -z "$NODE_AUTH_TOKEN" ]; then
echo "::error::NPM_TOKEN secret not set"
exit 1
fi
cd packages/npm/build
version=$(node -p "require('./package.json').version")
name=$(node -p "require('./package.json').name")
published=$(npm view "$name@$version" version 2>/dev/null || true)
if [ -n "$published" ]; then
echo "$name@$version already on npm — skipping"
exit 0
fi
npm publish --access public