Skip to content

Commit 9752fe0

Browse files
authored
feat(release): add prebuilt CLI binary builds and Homebrew formula (#871)
Add cli-binaries.yml workflow that builds prebuilt CLI binaries for macOS (ARM64, x86_64) and Linux (x86_64), uploads tarballs with SHA256 checksums to GitHub Release, and pushes a Homebrew formula to everruns/homebrew-tap. Same pattern as everruns/everruns.
1 parent da760af commit 9752fe0

File tree

5 files changed

+219
-7
lines changed

5 files changed

+219
-7
lines changed

.github/workflows/cli-binaries.yml

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# Prebuilt CLI binaries — dispatched by release.yml after GitHub Release is created.
2+
# GITHUB_TOKEN-created releases don't trigger `release: published` (anti-recursion).
3+
# The Release workflow dispatches this workflow explicitly, same pattern as everruns/everruns.
4+
name: Publish CLI Binaries
5+
6+
on:
7+
workflow_dispatch:
8+
inputs:
9+
tag:
10+
description: 'Release tag (e.g., v0.1.13)'
11+
required: true
12+
type: string
13+
14+
permissions:
15+
contents: write
16+
17+
jobs:
18+
build:
19+
name: Build CLI (${{ matrix.target }})
20+
runs-on: ${{ matrix.runner }}
21+
strategy:
22+
fail-fast: false
23+
matrix:
24+
include:
25+
- target: aarch64-apple-darwin
26+
runner: macos-latest
27+
archive: bashkit-aarch64-apple-darwin.tar.gz
28+
- target: x86_64-apple-darwin
29+
runner: macos-13
30+
archive: bashkit-x86_64-apple-darwin.tar.gz
31+
- target: x86_64-unknown-linux-gnu
32+
runner: ubuntu-latest
33+
archive: bashkit-x86_64-unknown-linux-gnu.tar.gz
34+
35+
steps:
36+
- uses: actions/checkout@v6
37+
with:
38+
ref: ${{ inputs.tag }}
39+
40+
- name: Install Rust toolchain
41+
uses: dtolnay/rust-toolchain@stable
42+
with:
43+
targets: ${{ matrix.target }}
44+
45+
- name: Cache Rust
46+
uses: Swatinem/rust-cache@v2
47+
with:
48+
shared-key: "cli-${{ matrix.target }}"
49+
50+
- name: Build CLI binary
51+
run: cargo build --release --target ${{ matrix.target }} -p bashkit-cli --no-default-features
52+
53+
- name: Package binary
54+
run: |
55+
cd target/${{ matrix.target }}/release
56+
tar czf "$GITHUB_WORKSPACE/${{ matrix.archive }}" bashkit
57+
cd "$GITHUB_WORKSPACE"
58+
shasum -a 256 "${{ matrix.archive }}" > "${{ matrix.archive }}.sha256"
59+
60+
- name: Upload to release
61+
env:
62+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63+
run: |
64+
gh release upload "${{ inputs.tag }}" \
65+
"${{ matrix.archive }}" \
66+
"${{ matrix.archive }}.sha256" \
67+
--clobber
68+
69+
update-homebrew:
70+
name: Update Homebrew formula
71+
needs: build
72+
runs-on: ubuntu-latest
73+
permissions:
74+
contents: read
75+
steps:
76+
- name: Download SHA256 checksums from release
77+
env:
78+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
79+
run: |
80+
TAG="${{ inputs.tag }}"
81+
for target in aarch64-apple-darwin x86_64-apple-darwin x86_64-unknown-linux-gnu; do
82+
gh release download "$TAG" \
83+
--repo "${{ github.repository }}" \
84+
--pattern "bashkit-${target}.tar.gz.sha256"
85+
done
86+
87+
- name: Generate Homebrew formula
88+
run: |
89+
TAG="${{ inputs.tag }}"
90+
VERSION="${TAG#v}"
91+
92+
# Validate checksum files exist and are non-empty
93+
for f in bashkit-aarch64-apple-darwin.tar.gz.sha256 \
94+
bashkit-x86_64-apple-darwin.tar.gz.sha256 \
95+
bashkit-x86_64-unknown-linux-gnu.tar.gz.sha256; do
96+
if [[ ! -s "$f" ]]; then
97+
echo "Error: checksum file '$f' is missing or empty." >&2
98+
exit 1
99+
fi
100+
done
101+
102+
SHA_ARM64=$(awk '{print $1}' bashkit-aarch64-apple-darwin.tar.gz.sha256)
103+
SHA_X86_64_MACOS=$(awk '{print $1}' bashkit-x86_64-apple-darwin.tar.gz.sha256)
104+
SHA_LINUX=$(awk '{print $1}' bashkit-x86_64-unknown-linux-gnu.tar.gz.sha256)
105+
106+
for var in SHA_ARM64 SHA_X86_64_MACOS SHA_LINUX; do
107+
if [[ -z "${!var}" ]]; then
108+
echo "Error: extracted $var is empty." >&2
109+
exit 1
110+
fi
111+
done
112+
113+
BASE_URL="${{ github.server_url }}/${{ github.repository }}/releases/download/${TAG}"
114+
115+
cat > bashkit.rb <<FORMULA
116+
# typed: false
117+
# frozen_string_literal: true
118+
119+
class Bashkit < Formula
120+
desc "Virtual bash interpreter with sandboxed execution"
121+
homepage "${{ github.server_url }}/${{ github.repository }}"
122+
version "${VERSION}"
123+
license "Apache-2.0"
124+
125+
on_macos do
126+
if Hardware::CPU.arm?
127+
url "${BASE_URL}/bashkit-aarch64-apple-darwin.tar.gz"
128+
sha256 "${SHA_ARM64}"
129+
else
130+
url "${BASE_URL}/bashkit-x86_64-apple-darwin.tar.gz"
131+
sha256 "${SHA_X86_64_MACOS}"
132+
end
133+
end
134+
135+
on_linux do
136+
depends_on arch: :x86_64
137+
url "${BASE_URL}/bashkit-x86_64-unknown-linux-gnu.tar.gz"
138+
sha256 "${SHA_LINUX}"
139+
end
140+
141+
def install
142+
bin.install "bashkit"
143+
end
144+
145+
test do
146+
assert_match version.to_s, shell_output("#{bin}/bashkit --version")
147+
end
148+
end
149+
FORMULA
150+
151+
# Remove leading whitespace from heredoc
152+
sed -i 's/^ //' bashkit.rb
153+
154+
echo "Generated formula:"
155+
cat bashkit.rb
156+
157+
- name: Install Doppler CLI
158+
uses: dopplerhq/cli-action@v3
159+
160+
- name: Push formula to homebrew-tap
161+
env:
162+
DOPPLER_TOKEN: ${{ secrets.DOPPLER_TOKEN }}
163+
run: |
164+
TAG="${{ inputs.tag }}"
165+
VERSION="${TAG#v}"
166+
167+
# Fetch the GitHub PAT from Doppler (has push access to homebrew-tap)
168+
GH_PAT=$(doppler secrets get GITHUB_TOKEN --plain)
169+
170+
# Clone the tap repo
171+
git clone "https://x-access-token:${GH_PAT}@github.com/everruns/homebrew-tap.git" tap
172+
cp bashkit.rb tap/Formula/bashkit.rb
173+
174+
cd tap
175+
git config user.name "github-actions[bot]"
176+
git config user.email "github-actions[bot]@users.noreply.github.com"
177+
git add Formula/bashkit.rb
178+
git diff --cached --quiet && echo "No changes to commit" && exit 0
179+
git commit -m "bashkit ${VERSION}"
180+
git push origin main

.github/workflows/release.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,12 @@ jobs:
7979
gh workflow run publish-js.yml
8080
env:
8181
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
82+
83+
- name: Trigger CLI binary builds for release tag
84+
env:
85+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
86+
run: |
87+
TAG="v${{ steps.version.outputs.version }}"
88+
echo "Triggering CLI binary builds for tag $TAG..."
89+
gh workflow run cli-binaries.yml --ref "$TAG" -f "tag=$TAG"
90+
echo "CLI binary builds triggered for $TAG"

specs/008-release-process.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,32 @@ The CI workflows handle this automatically on GitHub Release.
170170
### release.yml
171171

172172
- **Trigger**: Push to `main` with commit message starting with `chore(release): prepare v`
173-
- **Actions**: Creates GitHub Release with tag and release notes from CHANGELOG
173+
- **Actions**: Creates GitHub Release with tag and release notes from CHANGELOG, then dispatches publish and binary build workflows
174174
- **File**: `.github/workflows/release.yml`
175175

176+
### cli-binaries.yml
177+
178+
- **Trigger**: Dispatched by release.yml after GitHub Release is created
179+
- **Actions**: Builds prebuilt CLI binaries for macOS (ARM64, x86_64) and Linux (x86_64), uploads to GitHub Release, updates Homebrew formula
180+
- **File**: `.github/workflows/cli-binaries.yml`
181+
- **Secret required**: `DOPPLER_TOKEN` (for Homebrew tap push via Doppler-managed GitHub PAT)
182+
183+
#### CLI binary matrix
184+
185+
| OS | Target | Runner |
186+
|----|--------|--------|
187+
| macOS | aarch64-apple-darwin | macos-latest |
188+
| macOS | x86_64-apple-darwin | macos-13 |
189+
| Linux | x86_64-unknown-linux-gnu | ubuntu-latest |
190+
191+
#### Homebrew
192+
193+
After binaries are built, the workflow generates a Homebrew formula and pushes it to `everruns/homebrew-tap`. Users install via:
194+
195+
```bash
196+
brew install everruns/tap/bashkit
197+
```
198+
176199
### publish.yml
177200

178201
- **Trigger**: GitHub Release published
@@ -294,7 +317,8 @@ Note: Yanked versions can still be used by existing Cargo.lock files but won't b
294317

295318
Each release includes:
296319

297-
- **GitHub Release**: Tag, release notes, source archives
320+
- **GitHub Release**: Tag, release notes, source archives, prebuilt CLI binaries (macOS ARM64/x86_64, Linux x86_64)
298321
- **crates.io**: Published crates for `cargo add bashkit`
299322
- **PyPI**: Pre-built wheels for `pip install bashkit`
300323
- **npm**: Native NAPI-RS bindings for `npm install @everruns/bashkit`
324+
- **Homebrew**: Formula at `everruns/homebrew-tap` for `brew install everruns/tap/bashkit`

supply-chain/audits.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11

22
# cargo-vet audits file
33

4-
[audits]
4+
[[audits.aws-lc-sys]]
5+
who = "Mykhailo Chalyi <mike@chaliy.name>"
6+
criteria = "safe-to-deploy"
7+
version = "0.39.1"

supply-chain/config.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,6 @@ criteria = "safe-to-deploy"
102102
version = "1.16.2"
103103
criteria = "safe-to-deploy"
104104

105-
[[exemptions.aws-lc-sys]]
106-
version = "0.39.0"
107-
criteria = "safe-to-deploy"
108-
109105
[[exemptions.base64]]
110106
version = "0.22.1"
111107
criteria = "safe-to-deploy"

0 commit comments

Comments
 (0)