Files
BrowserOS/.github/workflows/release-cli.yml
Nikhil 6c053a5f29 feat: upload CLI binaries to CDN and gate release to core team (#602)
* feat: upload CLI binaries to CDN during release and gate workflow to core team

- Extend scripts/build/cli/upload.ts with uploadCliRelease() that pushes
  archives + checksums to R2 under versioned (cli/v{VERSION}/) and latest
  (cli/latest/) paths, plus a version.txt for lightweight latest resolution
- Update scripts/build/cli.ts entry point with --release/--version/--binaries-dir
  flags (existing no-args behavior preserved for upload:cli-installers)
- Rewrite install.sh and install.ps1 to fetch from cdn.browseros.com instead of
  GitHub releases API — eliminates rate limits and API dependency
- Add environment: release-core to release-cli.yml for core-team gating via
  GitHub environment protection rules
- Add Bun setup + CDN upload step to the workflow between build and GitHub release

* fix: address review feedback for PR #602

- Make loadProdEnv return empty map when .env.production is absent so
  pickEnv falls through to process.env in CI (Greptile P1)
- Add semver format validation for version string in install.sh and
  install.ps1 to guard against malformed CDN responses
- Pass inputs.version via env var instead of inline ${{ }} interpolation
  to prevent command injection in workflow shell
2026-03-27 11:47:31 -07:00

168 lines
5.2 KiB
YAML

name: Release CLI
on:
workflow_dispatch:
inputs:
version:
description: "Release version (e.g. 0.1.0)"
required: true
type: string
concurrency:
group: release-cli
cancel-in-progress: false
jobs:
release:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: release-core
permissions:
contents: write
pull-requests: write
defaults:
run:
working-directory: packages/browseros-agent/apps/cli
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version-file: packages/browseros-agent/apps/cli/go.mod
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.6"
- name: Run tests
run: go test ./... -v
- name: Run vet
run: go vet ./...
- name: Build all platforms
run: |
VERSION="${{ inputs.version }}"
LDFLAGS="-s -w -X main.version=${VERSION}"
DIST="dist"
mkdir -p "$DIST"
for pair in darwin/amd64 darwin/arm64 linux/amd64 linux/arm64 windows/amd64 windows/arm64; do
OS="${pair%/*}"
ARCH="${pair#*/}"
BIN="browseros-cli"
EXT=""
if [ "$OS" = "windows" ]; then EXT=".exe"; fi
echo "Building ${OS}/${ARCH}..."
GOOS=$OS GOARCH=$ARCH CGO_ENABLED=0 go build -trimpath -ldflags "$LDFLAGS" -o "${DIST}/${BIN}${EXT}" .
ARCHIVE="browseros-cli_${VERSION}_${OS}_${ARCH}"
if [ "$OS" = "windows" ]; then
(cd "$DIST" && zip "${ARCHIVE}.zip" "${BIN}${EXT}")
else
(cd "$DIST" && tar czf "${ARCHIVE}.tar.gz" "${BIN}")
fi
rm "${DIST}/${BIN}${EXT}"
done
(cd "$DIST" && sha256sum *.tar.gz *.zip > checksums.txt)
echo "=== Built artifacts ==="
ls -lh "$DIST"
- name: Install dependencies
run: bun install
working-directory: packages/browseros-agent
- name: Upload to CDN
env:
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
R2_BUCKET: ${{ secrets.R2_BUCKET }}
R2_UPLOAD_PREFIX: cli
CLI_VERSION: ${{ inputs.version }}
run: |
bun scripts/build/cli.ts \
--release \
--version "$CLI_VERSION" \
--binaries-dir apps/cli/dist
working-directory: packages/browseros-agent
- name: Generate release notes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
CLI_PATH="packages/browseros-agent/apps/cli"
TAG="browseros-cli-v${{ inputs.version }}"
CHANGELOG_FILE="/tmp/release-changelog.md"
PREV_TAG=$(git tag -l "browseros-cli-v*" --sort=-v:refname | grep -v "^${TAG}$" | head -n 1)
if [ -z "$PREV_TAG" ]; then
echo "Initial release of browseros-cli." > "$CHANGELOG_FILE"
else
COMMITS=$(git log "$PREV_TAG"..HEAD --pretty=format:"%H" -- "$CLI_PATH")
if [ -z "$COMMITS" ]; then
echo "No notable changes." > "$CHANGELOG_FILE"
else
echo "## What's Changed" > "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
while IFS= read -r SHA; do
SUBJECT=$(git log -1 --pretty=format:"%s" "$SHA")
PR_NUM=$(gh api "/repos/${{ github.repository }}/commits/${SHA}/pulls" --jq '.[0].number // empty' 2>/dev/null)
if [ -n "$PR_NUM" ] && ! echo "$SUBJECT" | grep -qF "(#${PR_NUM})"; then
echo "- ${SUBJECT} (#${PR_NUM})" >> "$CHANGELOG_FILE"
else
echo "- ${SUBJECT}" >> "$CHANGELOG_FILE"
fi
done <<< "$COMMITS"
fi
fi
cat "$CHANGELOG_FILE" > /tmp/release-notes.md
cat >> /tmp/release-notes.md <<'EOF'
## Install `browseros-cli`
### macOS / Linux
```bash
curl -fsSL https://cdn.browseros.com/cli/install.sh | bash
```
### Windows
```powershell
irm https://cdn.browseros.com/cli/install.ps1 | iex
```
After install, run `browseros-cli init` to point the CLI at your BrowserOS MCP server.
EOF
working-directory: ${{ github.workspace }}
- name: Create tag and release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="browseros-cli-v${{ inputs.version }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if ! git rev-parse "$TAG" >/dev/null 2>&1; then
git tag -a "$TAG" -m "browseros-cli v${{ inputs.version }}"
git push origin "$TAG"
fi
CLI_DIST="packages/browseros-agent/apps/cli/dist"
gh release create "$TAG" \
--title "browseros-cli v${{ inputs.version }}" \
--notes-file /tmp/release-notes.md \
${CLI_DIST}/*
working-directory: ${{ github.workspace }}