348 lines
13 KiB
YAML
348 lines
13 KiB
YAML
name: Build CLI Binaries
|
|
|
|
on:
|
|
push:
|
|
branches: [next]
|
|
paths:
|
|
- 'ts/packages/cli/**'
|
|
- 'ts/packages/cli-local-tools/**'
|
|
- '.github/actions/setup-node-pnpm-bun/action.yml'
|
|
- '.github/scripts/cli-release/**'
|
|
- '.github/workflows/build-cli-binaries.yml'
|
|
- 'mise.toml'
|
|
- 'mise.lock'
|
|
workflow_dispatch:
|
|
inputs:
|
|
action:
|
|
description: 'What to do'
|
|
type: choice
|
|
options:
|
|
- build-beta
|
|
- promote-stable
|
|
default: build-beta
|
|
beta_tag:
|
|
description: 'Existing beta release tag to promote (only for promote-stable, e.g. @composio/cli@0.2.20-beta.42)'
|
|
required: false
|
|
|
|
# Least privilege by default: only the release job creates/edits releases and uploads assets.
|
|
# `prepare` reads releases (gh release list) and `build` uploads workflow artifacts — both work
|
|
# with read access. The release job opts up to `contents: write` for itself.
|
|
permissions:
|
|
contents: read
|
|
|
|
# Print Turborepo telemetry events to the logs instead of sending them.
|
|
env:
|
|
TURBO_TELEMETRY_DEBUG: 1
|
|
|
|
jobs:
|
|
prepare:
|
|
name: Resolve Release Metadata
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
checkout_ref: ${{ steps.resolve.outputs.checkout_ref }}
|
|
release_name: ${{ steps.resolve.outputs.release_name }}
|
|
release_tag: ${{ steps.resolve.outputs.release_tag }}
|
|
release_version: ${{ steps.resolve.outputs.release_version }}
|
|
prerelease: ${{ steps.resolve.outputs.prerelease }}
|
|
make_latest: ${{ steps.resolve.outputs.make_latest }}
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
ref: ${{ github.sha }}
|
|
|
|
- name: Resolve release target
|
|
id: resolve
|
|
env:
|
|
EVENT_NAME: ${{ github.event_name }}
|
|
ACTION_INPUT: ${{ inputs.action }}
|
|
BETA_TAG_INPUT: ${{ inputs.beta_tag }}
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
REPOSITORY: ${{ github.repository }}
|
|
RUN_NUMBER: ${{ github.run_number }}
|
|
COMMIT_SHA: ${{ github.sha }}
|
|
run: bash .github/scripts/cli-release/resolve-release-target.sh
|
|
|
|
build:
|
|
name: Build ${{ matrix.artifact }}
|
|
needs: prepare
|
|
if: needs.prepare.result == 'success'
|
|
runs-on: ${{ matrix.runner }}
|
|
strategy:
|
|
# Never publish a partial platform set: with fail-fast disabled, the build job's
|
|
# result is `success` only when EVERY matrix leg passes, so a single failure makes
|
|
# `needs.build.result != 'success'` and the release job is skipped. It also surfaces
|
|
# all platform failures at once instead of cancelling siblings on the first error.
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- target: bun-linux-x64
|
|
artifact: composio-linux-x64
|
|
runner: ubuntu-latest
|
|
local_tools_target: ''
|
|
- target: bun-linux-arm64
|
|
artifact: composio-linux-aarch64
|
|
runner: ubuntu-latest
|
|
local_tools_target: ''
|
|
- target: bun-darwin-x64
|
|
artifact: composio-darwin-x64
|
|
runner: macos-15-intel
|
|
local_tools_target: ''
|
|
- target: bun-darwin-arm64
|
|
artifact: composio-darwin-aarch64
|
|
runner: macos-15
|
|
local_tools_target: darwin-arm64
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
ref: ${{ needs.prepare.outputs.checkout_ref }}
|
|
|
|
- name: Setup Node.js, pnpm, Bun
|
|
uses: ./.github/actions/setup-node-pnpm-bun
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Setup Swift 6.2 for local-tool sidecars
|
|
if: matrix.local_tools_target != ''
|
|
uses: swift-actions/setup-swift@364295d9c23900ce04d4e5cc708387921b4e50f9 # v3
|
|
with:
|
|
swift-version: '6.2'
|
|
|
|
- name: Verify Swift toolchain
|
|
if: matrix.local_tools_target != ''
|
|
run: swift --version
|
|
|
|
- name: Build packages
|
|
run: pnpm build:packages
|
|
|
|
- name: Build local-tool sidecar binaries
|
|
if: matrix.local_tools_target != ''
|
|
run: pnpm --filter @composio/cli-local-tools build:local-tool-binaries -- --target ${{ matrix.local_tools_target }}
|
|
|
|
- name: Verify local-tool sidecars
|
|
if: matrix.local_tools_target != ''
|
|
run: |
|
|
test -x ts/packages/cli-local-tools/local-tools-binaries/beeper-imessage/${{ matrix.local_tools_target }}/imessage-cli
|
|
test -x ts/packages/cli-local-tools/local-tools-binaries/peekaboo/${{ matrix.local_tools_target }}/peekaboo
|
|
test -x ts/packages/cli-local-tools/local-tools-binaries/composio-native-ui/${{ matrix.local_tools_target }}/composio-native-ui
|
|
|
|
- name: Cross-compile CLI binary
|
|
working-directory: ts/packages/cli
|
|
run: pnpm build:binary:cross --target ${{ matrix.target }}
|
|
|
|
- name: Verify binary
|
|
working-directory: ts/packages/cli
|
|
run: |
|
|
ls -la dist/binaries/${{ matrix.artifact }}
|
|
file dist/binaries/${{ matrix.artifact }}
|
|
|
|
- name: Test binary
|
|
if: matrix.target == 'bun-linux-x64'
|
|
working-directory: ts/packages/cli
|
|
env:
|
|
COMPOSIO_USER_API_KEY: test-dummy-api-key-for-ci
|
|
run: |
|
|
./dist/binaries/${{ matrix.artifact }} --version
|
|
./dist/binaries/${{ matrix.artifact }} --help | head -5
|
|
|
|
- name: Create archive
|
|
working-directory: ts/packages/cli
|
|
env:
|
|
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
|
|
run: pnpm build:binary:package
|
|
|
|
- name: Verify release metadata in archive
|
|
working-directory: ts/packages/cli
|
|
run: unzip -p dist/binaries/${{ matrix.artifact }}.zip ${{ matrix.artifact }}/release-tag.txt | grep -Fx '${{ needs.prepare.outputs.release_tag }}'
|
|
|
|
- name: Verify local-tool sidecars in archive
|
|
if: matrix.local_tools_target != ''
|
|
working-directory: ts/packages/cli
|
|
run: |
|
|
unzip -Z1 dist/binaries/${{ matrix.artifact }}.zip | grep -F "local-tools-binaries/beeper-imessage/${{ matrix.local_tools_target }}/imessage-cli"
|
|
unzip -Z1 dist/binaries/${{ matrix.artifact }}.zip | grep -F "local-tools-binaries/peekaboo/${{ matrix.local_tools_target }}/peekaboo"
|
|
unzip -Z1 dist/binaries/${{ matrix.artifact }}.zip | grep -F "local-tools-binaries/composio-native-ui/${{ matrix.local_tools_target }}/composio-native-ui"
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: ${{ matrix.artifact }}
|
|
path: ts/packages/cli/dist/binaries/${{ matrix.artifact }}.zip
|
|
retention-days: 7
|
|
|
|
release:
|
|
name: Release (draft → verify → publish)
|
|
needs: [prepare, build]
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write # create/edit the GitHub Release and upload assets
|
|
# fail-fast: false on the build matrix ⇒ this is `success` only if ALL platforms built,
|
|
# so a partial set can never reach the release path.
|
|
if: needs.build.result == 'success'
|
|
# Serialize runs that target the SAME release tag (e.g. two quick pushes, or a re-run
|
|
# racing the original) so they cannot interleave uploads. Keyed on the resolved tag so
|
|
# unrelated beta builds are not serialized behind each other. Job-level concurrency may
|
|
# read `needs.*` outputs (workflow-level cannot). The serialized loser fails loudly at the
|
|
# "already published" guard in create-or-resume-draft.sh — that red ❌ is by design.
|
|
concurrency:
|
|
group: cli-release-${{ needs.prepare.outputs.release_tag }}
|
|
cancel-in-progress: false
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
|
|
RELEASE_NAME: ${{ needs.prepare.outputs.release_name }}
|
|
PRERELEASE: ${{ needs.prepare.outputs.prerelease }}
|
|
MAKE_LATEST: ${{ needs.prepare.outputs.make_latest }}
|
|
CHECKOUT_REF: ${{ needs.prepare.outputs.checkout_ref }}
|
|
RELEASE_HELPERS_DIR: ${{ github.workspace }}/.release-workflow/.github/scripts/cli-release
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
ref: ${{ needs.prepare.outputs.checkout_ref }}
|
|
|
|
- name: Setup Node.js, pnpm, Bun
|
|
uses: ./.github/actions/setup-node-pnpm-bun
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
path: ts/packages/cli/dist/binaries
|
|
merge-multiple: true
|
|
|
|
# Package skills BEFORE generating checksums so composio-skill.zip is included in
|
|
# checksums.txt alongside the platform binaries (generate-checksums hashes every .zip
|
|
# in dist/binaries).
|
|
- name: Package skill files
|
|
working-directory: ts/packages/cli
|
|
env:
|
|
PRERELEASE: ${{ needs.prepare.outputs.prerelease }}
|
|
run: |
|
|
pnpm run validate:skills
|
|
if [[ "$PRERELEASE" == "true" ]]; then
|
|
channel=beta
|
|
else
|
|
channel=stable
|
|
fi
|
|
pnpm run build:skills -- --channel "$channel" --output-dir ./dist/skills
|
|
cd dist/skills && zip -r ../binaries/composio-skill.zip composio-cli/
|
|
|
|
- name: Generate checksums
|
|
working-directory: ts/packages/cli
|
|
run: bun run ./scripts/generate-checksums.ts
|
|
|
|
- name: Display checksums
|
|
run: cat ts/packages/cli/dist/binaries/checksums.txt
|
|
|
|
- name: Checkout workflow release helpers
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
with:
|
|
ref: ${{ github.workflow_sha }}
|
|
path: .release-workflow
|
|
sparse-checkout: |
|
|
.github/scripts/cli-release
|
|
sparse-checkout-cone-mode: false
|
|
|
|
# Build the release as a DRAFT first. Drafts fire no `release: published` event and are
|
|
# excluded from the `/releases/latest` redirect, so no anonymous consumer (install.sh,
|
|
# Homebrew, the redirect) can ever observe a release before its assets are attached and
|
|
# verified. The release is only flipped to published as the final step below.
|
|
- name: Create draft release with all assets
|
|
run: bash "$RELEASE_HELPERS_DIR/create-or-resume-draft.sh"
|
|
|
|
# Loud failure gate: assert the full canonical asset set is attached AND fully uploaded.
|
|
# An asset can appear in the list while still processing (`state != "uploaded"`), which is
|
|
# exactly how a release ends up serving 404s, so we require state == "uploaded".
|
|
- name: Verify all release assets are present and uploaded
|
|
run: bash "$RELEASE_HELPERS_DIR/verify-assets.sh"
|
|
|
|
# Publishing is the ONLY step that exposes the release. Do not edit the body here: a known
|
|
# GitHub PATCH race drops body changes made in the same call as the draft flip, and the
|
|
# notes were already generated at draft creation. Prerelease status was set on the draft.
|
|
- name: Publish release (flip draft → published)
|
|
run: gh release edit "$RELEASE_TAG" --draft=false --latest="$MAKE_LATEST"
|
|
|
|
test-installation:
|
|
name: Test Installation
|
|
needs: [prepare, release]
|
|
if: always() && !cancelled() && needs.release.result == 'success'
|
|
uses: ./.github/workflows/cli.test-installation.yml
|
|
with:
|
|
version: ${{ needs.prepare.outputs.release_tag }}
|
|
|
|
create-install-instructions:
|
|
name: Create Install Instructions
|
|
needs: [prepare, release]
|
|
runs-on: ubuntu-latest
|
|
if: always() && !cancelled() && needs.release.result == 'success'
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
|
|
- name: Create installation README
|
|
run: |
|
|
RELEASE_TAG="${{ needs.prepare.outputs.release_tag }}"
|
|
cat > INSTALL.md << 'EOF'
|
|
# Composio CLI Installation
|
|
|
|
## Quick Install (Recommended)
|
|
|
|
### Linux and macOS
|
|
```bash
|
|
curl -fsSL https://raw.githubusercontent.com/ComposioHQ/composio/next/install.sh | bash
|
|
```
|
|
|
|
### Install specific version
|
|
```bash
|
|
curl -fsSL https://raw.githubusercontent.com/ComposioHQ/composio/next/install.sh | bash -s -- RELEASE_TAG_PLACEHOLDER
|
|
```
|
|
|
|
## Manual Installation
|
|
|
|
1. Download the appropriate binary for your platform from the [releases page](https://github.com/ComposioHQ/composio/releases)
|
|
2. Extract the binary
|
|
3. Move it to a directory in your PATH (e.g., `/usr/local/bin`)
|
|
4. Make it executable: `chmod +x composio`
|
|
|
|
## Alternative: npm/pnpm Installation
|
|
|
|
```bash
|
|
npm install -g @composio/cli
|
|
# or
|
|
pnpm add -g @composio/cli
|
|
```
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
composio --help
|
|
composio login
|
|
composio generate
|
|
```
|
|
|
|
## Supported Platforms
|
|
|
|
- Linux x64
|
|
- Linux ARM64
|
|
- macOS x64 (Intel)
|
|
- macOS ARM64 (Apple Silicon)
|
|
|
|
Windows support coming soon!
|
|
EOF
|
|
sed -i.bak "s|RELEASE_TAG_PLACEHOLDER|$RELEASE_TAG|g" INSTALL.md && rm -f INSTALL.md.bak
|
|
|
|
- name: Upload install instructions
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: install-instructions
|
|
path: INSTALL.md
|