name: Release
on:
push:
tags: ['v*']
env:
CARGO_TERM_COLOR: always
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
- run: cargo fmt --check
- run: cargo clippy -- -D warnings
- run: cargo test
build:
name: Build (${{ matrix.target }})
needs: test
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
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:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Install cross
if: matrix.cross
run: cargo install cross --version 0.2.5
- name: Build (cross)
if: matrix.cross
run: cross build --release --target ${{ matrix.target }}
- name: Build (cargo)
if: ${{ !matrix.cross }}
run: cargo build --release --target ${{ matrix.target }}
- name: Package (tar.gz)
if: matrix.archive == 'tar.gz'
run: |
cd target/${{ matrix.target }}/release
tar czf ../../../aigent-${{ github.ref_name }}-${{ matrix.target }}.tar.gz aigent
cd ../../..
- name: Package (zip)
if: matrix.archive == 'zip'
shell: pwsh
run: |
Compress-Archive -Path target/${{ matrix.target }}/release/aigent.exe -DestinationPath aigent-${{ github.ref_name }}-${{ matrix.target }}.zip
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: aigent-${{ matrix.target }}
path: aigent-${{ github.ref_name }}-${{ matrix.target }}.*
release:
name: Release
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: Generate checksums
run: |
cd artifacts
files=$(ls *.tar.gz *.zip 2>/dev/null || true)
if [ -z "$files" ]; then
echo "ERROR: No artifact archives found to generate checksums." >&2
exit 1
fi
sha256sum $files > checksums.txt
if [ ! -s checksums.txt ]; then
echo "ERROR: Failed to generate checksums or checksums.txt is empty." >&2
exit 1
fi
cat checksums.txt
- name: Extract changelog
run: |
VERSION=${GITHUB_REF_NAME#v}
VERSION_ESCAPED=$(echo "$VERSION" | sed 's/\./\\./g')
sed -n "/^## \[${VERSION_ESCAPED}\]/,/^## \[/{/^## \[/d;p;}" CHANGES.md > release-notes.md
if [ ! -s release-notes.md ]; then
echo "ERROR: No changelog entry found for version ${VERSION}" >&2
exit 1
fi
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
body_path: release-notes.md
files: artifacts/*
publish:
name: Publish to crates.io
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable
- run: cargo publish
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
homebrew:
name: Update Homebrew formula
needs: release
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true
- name: Update formula and push
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
if [ -z "${HOMEBREW_TAP_TOKEN}" ]; then
echo "ERROR: HOMEBREW_TAP_TOKEN secret is not set" >&2
exit 1
fi
VERSION=${GITHUB_REF_NAME#v}
if [ -z "${VERSION}" ] || [ "${VERSION}" = "${GITHUB_REF_NAME}" ]; then
echo "ERROR: invalid tag '${GITHUB_REF_NAME}', expected v-prefixed version" >&2
exit 1
fi
# Verify all required artifacts exist
for target in aarch64-apple-darwin x86_64-apple-darwin aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu; do
if [ ! -f "artifacts/aigent-${GITHUB_REF_NAME}-${target}.tar.gz" ]; then
echo "ERROR: missing artifact aigent-${GITHUB_REF_NAME}-${target}.tar.gz" >&2
exit 1
fi
done
# Compute checksums for Homebrew targets
AARCH64_DARWIN=$(sha256sum artifacts/aigent-${GITHUB_REF_NAME}-aarch64-apple-darwin.tar.gz | cut -d' ' -f1)
X86_64_DARWIN=$(sha256sum artifacts/aigent-${GITHUB_REF_NAME}-x86_64-apple-darwin.tar.gz | cut -d' ' -f1)
AARCH64_LINUX=$(sha256sum artifacts/aigent-${GITHUB_REF_NAME}-aarch64-unknown-linux-gnu.tar.gz | cut -d' ' -f1)
X86_64_LINUX=$(sha256sum artifacts/aigent-${GITHUB_REF_NAME}-x86_64-unknown-linux-gnu.tar.gz | cut -d' ' -f1)
# Clone homebrew tap
git clone https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/wkusnierczyk/homebrew-aigent.git tap
cd tap
# Update version
sed "s/version \".*\"/version \"${VERSION}\"/" Formula/aigent.rb > Formula/aigent.rb.tmp
mv Formula/aigent.rb.tmp Formula/aigent.rb
# Update checksums: match each url target, replace the following sha256
awk -v ad="$AARCH64_DARWIN" -v xd="$X86_64_DARWIN" \
-v al="$AARCH64_LINUX" -v xl="$X86_64_LINUX" '
/aarch64-apple-darwin/ { t="ad" }
/x86_64-apple-darwin/ { t="xd" }
/aarch64-unknown-linux-gnu/ { t="al" }
/x86_64-unknown-linux-gnu/ { t="xl" }
/^\s*sha256\s+"[a-f0-9]+"/ && t != "" {
if (t=="ad") sub(/"[a-f0-9]+"/, "\"" ad "\"")
else if (t=="xd") sub(/"[a-f0-9]+"/, "\"" xd "\"")
else if (t=="al") sub(/"[a-f0-9]+"/, "\"" al "\"")
else if (t=="xl") sub(/"[a-f0-9]+"/, "\"" xl "\"")
t=""
}
{ print }
' Formula/aigent.rb > Formula/aigent.rb.tmp
mv Formula/aigent.rb.tmp Formula/aigent.rb
# Commit and push
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/aigent.rb
git diff --cached --quiet && echo "Formula already up to date" && exit 0
git commit -m "Update aigent to ${VERSION}"
git push