Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions .github/workflows/cli-binaries.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# Prebuilt CLI binaries — dispatched by release.yml after GitHub Release is created.
# GITHUB_TOKEN-created releases don't trigger `release: published` (anti-recursion).
# The Release workflow dispatches this workflow explicitly, same pattern as everruns/everruns.
name: Publish CLI Binaries

on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag (e.g., v0.1.13)'
required: true
type: string

permissions:
contents: write

jobs:
build:
name: Build CLI (${{ matrix.target }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- target: aarch64-apple-darwin
runner: macos-latest
archive: bashkit-aarch64-apple-darwin.tar.gz
- target: x86_64-apple-darwin
runner: macos-13
archive: bashkit-x86_64-apple-darwin.tar.gz
- target: x86_64-unknown-linux-gnu
runner: ubuntu-latest
archive: bashkit-x86_64-unknown-linux-gnu.tar.gz

steps:
- uses: actions/checkout@v6
with:
ref: ${{ inputs.tag }}

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}

- name: Cache Rust
uses: Swatinem/rust-cache@v2
with:
shared-key: "cli-${{ matrix.target }}"

- name: Build CLI binary
run: cargo build --release --target ${{ matrix.target }} -p bashkit-cli --no-default-features

- name: Package binary
run: |
cd target/${{ matrix.target }}/release
tar czf "$GITHUB_WORKSPACE/${{ matrix.archive }}" bashkit
cd "$GITHUB_WORKSPACE"
shasum -a 256 "${{ matrix.archive }}" > "${{ matrix.archive }}.sha256"

- name: Upload to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload "${{ inputs.tag }}" \
"${{ matrix.archive }}" \
"${{ matrix.archive }}.sha256" \
--clobber

update-homebrew:
name: Update Homebrew formula
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Download SHA256 checksums from release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${{ inputs.tag }}"
for target in aarch64-apple-darwin x86_64-apple-darwin x86_64-unknown-linux-gnu; do
gh release download "$TAG" \
--repo "${{ github.repository }}" \
--pattern "bashkit-${target}.tar.gz.sha256"
done

- name: Generate Homebrew formula
run: |
TAG="${{ inputs.tag }}"
VERSION="${TAG#v}"

# Validate checksum files exist and are non-empty
for f in bashkit-aarch64-apple-darwin.tar.gz.sha256 \
bashkit-x86_64-apple-darwin.tar.gz.sha256 \
bashkit-x86_64-unknown-linux-gnu.tar.gz.sha256; do
if [[ ! -s "$f" ]]; then
echo "Error: checksum file '$f' is missing or empty." >&2
exit 1
fi
done

SHA_ARM64=$(awk '{print $1}' bashkit-aarch64-apple-darwin.tar.gz.sha256)
SHA_X86_64_MACOS=$(awk '{print $1}' bashkit-x86_64-apple-darwin.tar.gz.sha256)
SHA_LINUX=$(awk '{print $1}' bashkit-x86_64-unknown-linux-gnu.tar.gz.sha256)

for var in SHA_ARM64 SHA_X86_64_MACOS SHA_LINUX; do
if [[ -z "${!var}" ]]; then
echo "Error: extracted $var is empty." >&2
exit 1
fi
done

BASE_URL="${{ github.server_url }}/${{ github.repository }}/releases/download/${TAG}"

cat > bashkit.rb <<FORMULA
# typed: false
# frozen_string_literal: true

class Bashkit < Formula
desc "Virtual bash interpreter with sandboxed execution"
homepage "${{ github.server_url }}/${{ github.repository }}"
version "${VERSION}"
license "Apache-2.0"

on_macos do
if Hardware::CPU.arm?
url "${BASE_URL}/bashkit-aarch64-apple-darwin.tar.gz"
sha256 "${SHA_ARM64}"
else
url "${BASE_URL}/bashkit-x86_64-apple-darwin.tar.gz"
sha256 "${SHA_X86_64_MACOS}"
end
end

on_linux do
depends_on arch: :x86_64
url "${BASE_URL}/bashkit-x86_64-unknown-linux-gnu.tar.gz"
sha256 "${SHA_LINUX}"
end

def install
bin.install "bashkit"
end

test do
assert_match version.to_s, shell_output("#{bin}/bashkit --version")
end
end
FORMULA

# Remove leading whitespace from heredoc
sed -i 's/^ //' bashkit.rb

echo "Generated formula:"
cat bashkit.rb

- name: Install Doppler CLI
uses: dopplerhq/cli-action@v3

- name: Push formula to homebrew-tap
env:
DOPPLER_TOKEN: ${{ secrets.DOPPLER_TOKEN }}
run: |
TAG="${{ inputs.tag }}"
VERSION="${TAG#v}"

# Fetch the GitHub PAT from Doppler (has push access to homebrew-tap)
GH_PAT=$(doppler secrets get GITHUB_TOKEN --plain)

# Clone the tap repo
git clone "https://x-access-token:${GH_PAT}@github.com/everruns/homebrew-tap.git" tap
cp bashkit.rb tap/Formula/bashkit.rb

cd tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/bashkit.rb
git diff --cached --quiet && echo "No changes to commit" && exit 0
git commit -m "bashkit ${VERSION}"
git push origin main
9 changes: 9 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,12 @@ jobs:
gh workflow run publish-js.yml
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Trigger CLI binary builds for release tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="v${{ steps.version.outputs.version }}"
echo "Triggering CLI binary builds for tag $TAG..."
gh workflow run cli-binaries.yml --ref "$TAG" -f "tag=$TAG"
echo "CLI binary builds triggered for $TAG"
28 changes: 26 additions & 2 deletions specs/008-release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,32 @@ The CI workflows handle this automatically on GitHub Release.
### release.yml

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

### cli-binaries.yml

- **Trigger**: Dispatched by release.yml after GitHub Release is created
- **Actions**: Builds prebuilt CLI binaries for macOS (ARM64, x86_64) and Linux (x86_64), uploads to GitHub Release, updates Homebrew formula
- **File**: `.github/workflows/cli-binaries.yml`
- **Secret required**: `DOPPLER_TOKEN` (for Homebrew tap push via Doppler-managed GitHub PAT)

#### CLI binary matrix

| OS | Target | Runner |
|----|--------|--------|
| macOS | aarch64-apple-darwin | macos-latest |
| macOS | x86_64-apple-darwin | macos-13 |
| Linux | x86_64-unknown-linux-gnu | ubuntu-latest |

#### Homebrew

After binaries are built, the workflow generates a Homebrew formula and pushes it to `everruns/homebrew-tap`. Users install via:

```bash
brew install everruns/tap/bashkit
```

### publish.yml

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

Each release includes:

- **GitHub Release**: Tag, release notes, source archives
- **GitHub Release**: Tag, release notes, source archives, prebuilt CLI binaries (macOS ARM64/x86_64, Linux x86_64)
- **crates.io**: Published crates for `cargo add bashkit`
- **PyPI**: Pre-built wheels for `pip install bashkit`
- **npm**: Native NAPI-RS bindings for `npm install @everruns/bashkit`
- **Homebrew**: Formula at `everruns/homebrew-tap` for `brew install everruns/tap/bashkit`
5 changes: 4 additions & 1 deletion supply-chain/audits.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@

# cargo-vet audits file

[audits]
[[audits.aws-lc-sys]]
who = "Mykhailo Chalyi <mike@chaliy.name>"
criteria = "safe-to-deploy"
version = "0.39.1"
4 changes: 0 additions & 4 deletions supply-chain/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,6 @@ criteria = "safe-to-deploy"
version = "1.16.2"
criteria = "safe-to-deploy"

[[exemptions.aws-lc-sys]]
version = "0.39.0"
criteria = "safe-to-deploy"

[[exemptions.base64]]
version = "0.22.1"
criteria = "safe-to-deploy"
Expand Down
Loading