chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,347 @@
|
||||
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
|
||||
Reference in New Issue
Block a user