name: Release
on:
push:
tags: ["v*"]
permissions:
contents: write
jobs:
create-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Prepare release notes
run: |
set -euo pipefail
version="${GITHUB_REF_NAME#v}"
awk -v version="$version" '
$0 ~ "^## \\[" version "\\]" { in_section = 1; print; next }
in_section && /^## \[/ { exit }
in_section { print }
' CHANGELOG.md > release-notes.md
if [ ! -s release-notes.md ]; then
echo "a3s ${GITHUB_REF_NAME}" > release-notes.md
fi
- name: Create GitHub release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1 \
|| gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" \
--notes-file release-notes.md --verify-tag
binaries:
needs: [create-release, crate]
strategy:
fail-fast: false
matrix:
include:
- { target: aarch64-apple-darwin, os: macos-latest }
- { target: x86_64-apple-darwin, os: macos-latest }
- { target: x86_64-unknown-linux-gnu, os: ubuntu-latest }
- { target: aarch64-unknown-linux-gnu, os: ubuntu-latest }
- { target: x86_64-pc-windows-msvc, os: windows-latest }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Prepare A3S workspace crates
shell: bash
run: bash .github/scripts/checkout-a3s-workspace.sh
- uses: taiki-e/upload-rust-binary-action@v1
with:
bin: a3s
target: ${{ matrix.target }}
archive: a3s-$tag-$target
token: ${{ secrets.GITHUB_TOKEN }}
crate:
needs: create-release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Prepare A3S workspace crates
run: bash .github/scripts/checkout-a3s-workspace.sh
- uses: dtolnay/rust-toolchain@stable
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
if [ -z "${CARGO_REGISTRY_TOKEN:-}" ]; then
echo "::error::CARGO_REGISTRY_TOKEN not set — cannot publish a3s to crates.io"; exit 1
fi
crate_exists() {
curl --retry 5 --retry-all-errors --retry-delay 5 -fsSL \
-A "a3s-release-check/1.0" \
"https://crates.io/api/v1/crates/$1/$2" >/dev/null
}
if ! crate_exists a3s-code-core 4.3.0; then
echo "::error::a3s-code-core 4.3.0 is not on crates.io yet — cannot publish a3s"; exit 1
fi
if ! crate_exists a3s-memory 0.1.2; then
echo "::error::a3s-memory 0.1.2 is not on crates.io yet — cannot publish a3s"; exit 1
fi
if ! crate_exists a3s-tui 0.1.5; then
echo "::error::a3s-tui 0.1.5 is not on crates.io yet — cannot publish a3s"; exit 1
fi
cargo publish
homebrew:
needs: binaries
runs-on: ubuntu-latest
steps:
- name: Update Homebrew tap formula
env:
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
set -euo pipefail
if [ -z "${TAP_TOKEN:-}" ]; then
echo "::error::HOMEBREW_TAP_TOKEN not set — cannot update Homebrew tap"; exit 1
fi
tag="$GITHUB_REF_NAME"; v="${tag#v}"
base="https://github.com/A3S-Lab/CLI/releases/download/${tag}"
sha() { curl -fsSL "$base/a3s-${tag}-$1.tar.gz" | sha256sum | cut -d' ' -f1; }
mac_arm=$(sha aarch64-apple-darwin)
mac_x86=$(sha x86_64-apple-darwin)
lin_arm=$(sha aarch64-unknown-linux-gnu)
lin_x86=$(sha x86_64-unknown-linux-gnu)
git clone "https://x-access-token:${TAP_TOKEN}@github.com/A3S-Lab/homebrew-tap.git" tap
cat > tap/Formula/a3s.rb <<RB
class A3s < Formula
desc "A3S coding agent CLI — a3s code launches the interactive TUI"
homepage "https://github.com/A3S-Lab/CLI"
version "${v}"
license "MIT"
on_macos do
# RemoteUI popup helper (own repo/formula): A3S-Lab/WebView. Pulled
# in automatically so the inline OS popup works out of the box.
depends_on "a3s-lab/tap/a3s-webview"
on_arm do
url "${base}/a3s-${tag}-aarch64-apple-darwin.tar.gz"
sha256 "${mac_arm}"
end
on_intel do
url "${base}/a3s-${tag}-x86_64-apple-darwin.tar.gz"
sha256 "${mac_x86}"
end
end
on_linux do
on_arm do
url "${base}/a3s-${tag}-aarch64-unknown-linux-gnu.tar.gz"
sha256 "${lin_arm}"
end
on_intel do
url "${base}/a3s-${tag}-x86_64-unknown-linux-gnu.tar.gz"
sha256 "${lin_x86}"
end
end
def install
bin.install "a3s"
end
test do
assert_match "a3s", shell_output("#{bin}/a3s --version")
end
end
RB
cd tap
git config user.email "ci@a3s.dev"
git config user.name "A3S CI"
git add Formula/a3s.rb
git diff --cached --quiet || git commit -m "a3s ${v} (automated)"
git push