Files
2026-07-13 12:38:34 +08:00

639 lines
21 KiB
YAML

name: Test Installation
on:
push:
tags:
# Temporary compatibility window: support both legacy v* and package-scoped CLI tags.
- 'v*'
- '@composio/cli@*'
workflow_dispatch:
inputs:
version:
description: 'Version to test (e.g., 1.0.0 or @composio/cli@1.0.0)'
required: true
workflow_call:
inputs:
version:
description: 'Release tag or semver version to test'
required: false
default: 'latest'
type: string
permissions:
contents: read
jobs:
toolchain-versions:
name: Read toolchain test matrix
runs-on: ubuntu-latest
outputs:
node_install_compat: ${{ steps.versions.outputs.node_install_compat }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Read versions
id: versions
run: echo "node_install_compat=$(jq -c '.node_install_compat' toolchain-versions.json)" >> "$GITHUB_OUTPUT"
install-script-unit-tests:
name: Install Script Unit Tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Test release resolution fallback
run: bash test/install-sh-release-resolution.test.sh
test-install-script:
name: Test Install Script
needs: install-script-unit-tests
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Ubuntu x64 versions
- os: ubuntu-22.04
name: 'Ubuntu 22.04 x64'
shell: bash
- os: ubuntu-22.04
name: 'Ubuntu 22.04 x64 (zsh)'
shell: zsh
- os: ubuntu-latest
name: 'Ubuntu Latest x64'
shell: bash
# Ubuntu ARM64 versions (using Depot)
- os: depot-ubuntu-24.04-arm
name: 'Ubuntu 24.04 ARM64'
shell: bash
- os: depot-ubuntu-22.04-arm
name: 'Ubuntu 22.04 ARM64'
shell: bash
- os: depot-ubuntu-22.04-arm
name: 'Ubuntu 22.04 ARM64 (zsh)'
shell: zsh
# macOS versions
- os: macos-15-intel
name: 'macOS 15 (Intel)'
shell: bash
- os: macos-15-intel
name: 'macOS 15 (Intel, zsh)'
shell: zsh
- os: macos-14
name: 'macOS 14 (Sonoma)'
shell: bash
- os: macos-15
name: 'macOS 15 (Apple Silicon)'
shell: bash
- os: macos-15
name: 'macOS 15 (Apple Silicon, zsh)'
shell: zsh
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Resolve and validate target release
id: release_target
shell: bash
env:
VERSION_INPUT: ${{ inputs.version }}
run: |
raw_input="$VERSION_INPUT"
if [[ -z "$raw_input" || "$raw_input" == "latest" ]]; then
echo "use_latest=true" >> "$GITHUB_OUTPUT"
echo "release_tag=" >> "$GITHUB_OUTPUT"
exit 0
fi
# For manual runs, accept a full package tag or semver and normalize to a package tag.
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
if [[ "$raw_input" =~ ^@composio/cli@ ]]; then
echo "use_latest=false" >> "$GITHUB_OUTPUT"
echo "release_tag=$raw_input" >> "$GITHUB_OUTPUT"
exit 0
elif [[ "$raw_input" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
echo "use_latest=false" >> "$GITHUB_OUTPUT"
echo "release_tag=@composio/cli@$raw_input" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Invalid version: '$raw_input'"
echo "Expected format like: 1.2.3, 1.2.3-beta.1, 1.2.3+build.7, or @composio/cli@1.2.3"
exit 1
fi
# For workflow_call / push, accept a full package tag, semver, or legacy v* tag.
if [[ "$raw_input" =~ ^@composio/cli@ ]]; then
echo "use_latest=false" >> "$GITHUB_OUTPUT"
echo "release_tag=$raw_input" >> "$GITHUB_OUTPUT"
elif [[ "$raw_input" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
echo "use_latest=false" >> "$GITHUB_OUTPUT"
echo "release_tag=@composio/cli@$raw_input" >> "$GITHUB_OUTPUT"
else
echo "use_latest=false" >> "$GITHUB_OUTPUT"
echo "release_tag=$raw_input" >> "$GITHUB_OUTPUT"
exit 0
fi
- name: Setup shell environment
run: |
if [[ "${{ matrix.shell }}" == "zsh" ]]; then
# Install zsh if not present
if ! command -v zsh &> /dev/null; then
if [[ "${{ runner.os }}" == "Linux" ]]; then
sudo apt-get update
sudo apt-get install -y zsh
elif [[ "${{ runner.os }}" == "macOS" ]]; then
# zsh is default on macOS
echo "zsh already available"
fi
fi
# Create .zshrc if it doesn't exist
touch ~/.zshrc
# Set zsh as the shell for this session
export SHELL=$(which zsh)
echo "SHELL=$(which zsh)" >> $GITHUB_ENV
else
# Ensure bash is available and create .bashrc
touch ~/.bashrc
export SHELL=$(which bash)
echo "SHELL=$(which bash)" >> $GITHUB_ENV
fi
- name: Test install script (latest version)
if: steps.release_target.outputs.use_latest == 'true'
shell: bash
run: |
echo "Testing installation with auto-detected latest CLI version..."
# Test the install script without version (it will auto-detect latest CLI release)
bash install.sh
# Verify installation
source ~/.bashrc 2>/dev/null || source ~/.zshrc 2>/dev/null || true
export PATH="$HOME/.composio:$PATH"
# Check if binary exists
if [[ -f "$HOME/.composio/composio" ]]; then
echo "✅ Binary installed successfully"
ls -la "$HOME/.composio/composio"
else
echo "❌ Binary not found"
exit 1
fi
# Test binary execution
if "$HOME/.composio/composio" --version; then
echo "✅ Binary executes successfully"
else
echo "❌ Binary execution failed"
exit 1
fi
- name: Test install script (specific version)
if: steps.release_target.outputs.use_latest != 'true'
shell: bash
env:
RELEASE_TAG: ${{ steps.release_target.outputs.release_tag }}
run: |
echo "Testing installation with version: ${RELEASE_TAG}"
# Test the install script with specific version
bash install.sh "${RELEASE_TAG}"
# Verify installation
source ~/.bashrc 2>/dev/null || source ~/.zshrc 2>/dev/null || true
export PATH="$HOME/.composio:$PATH"
# Check if binary exists
if [[ -f "$HOME/.composio/composio" ]]; then
echo "✅ Binary installed successfully"
ls -la "$HOME/.composio/composio"
else
echo "❌ Binary not found"
exit 1
fi
# Test binary execution
if "$HOME/.composio/composio" --version; then
echo "✅ Binary executes successfully"
else
echo "❌ Binary execution failed"
exit 1
fi
- name: Test PATH integration
shell: bash
run: |
echo "Testing PATH integration with ${{ matrix.shell }}..."
# Debug: Check what files exist and their contents
echo "=== DEBUGGING ==="
echo "Checking shell config files:"
ls -la ~/ | grep -E '\.(bash|zsh)' || echo "No shell config files found"
if [[ -f ~/.bashrc ]]; then
echo "=== ~/.bashrc contents ==="
cat ~/.bashrc
fi
if [[ -f ~/.zshrc ]]; then
echo "=== ~/.zshrc contents ==="
cat ~/.zshrc
fi
echo "=== Installation directory ==="
ls -la ~/.composio/ || echo "~/.composio/ not found"
echo "=== Current PATH before sourcing ==="
echo "$PATH"
if [[ "${{ matrix.shell }}" == "zsh" ]]; then
if [[ -f ~/.zshrc ]]; then
echo "Testing interactive zsh startup..."
if zsh -ic 'echo "PATH after startup: $PATH"; command -v composio; composio --version; composio --help | head -5'; then
echo "✅ composio found in PATH via zsh"
else
echo "❌ composio not found in PATH via zsh"
exit 1
fi
else
echo "❌ ~/.zshrc not found - install script failed to create it"
exit 1
fi
else
if [[ -f ~/.bashrc ]]; then
echo "Testing interactive bash startup..."
if bash -ic 'echo "PATH after startup: $PATH"; command -v composio; composio --version; composio --help | head -5'; then
echo "✅ composio found in PATH via bash"
else
echo "❌ composio not found in PATH via bash"
exit 1
fi
else
echo "❌ ~/.bashrc not found - install script failed to create it"
exit 1
fi
fi
- name: Test bundled support files
shell: bash
run: |
echo "Checking bundled support files..."
install_dir="${COMPOSIO_INSTALL_DIR:-$HOME/.composio}"
release_tag=$(cat "$install_dir/release-tag.txt")
platform=$(uname -ms)
case $platform in
'Darwin x86_64') target=darwin-x64 ;;
'Darwin arm64') target=darwin-aarch64 ;;
'Linux aarch64' | 'Linux arm64')
target=linux-aarch64 ;;
'Linux x86_64') target=linux-x64 ;;
*) echo "❌ Unsupported platform: $platform"; exit 1 ;;
esac
if [[ $target = darwin-x64 ]]; then
if [[ $(sysctl -n sysctl.proc_translated 2>/dev/null) = 1 ]]; then
target=darwin-aarch64
fi
fi
archive_name="composio-$target.zip"
archive_url="https://github.com/ComposioHQ/composio/releases/download/$release_tag/$archive_name"
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
curl --fail --silent --location --output "$tmpdir/$archive_name" "$archive_url"
expected_paths="$(
unzip -Z1 "$tmpdir/$archive_name" \
| grep -v '/$' \
| sed "s#^composio-$target/##" \
| grep -v '^composio$' \
| sort
)"
if [ -z "$expected_paths" ]; then
echo "❌ No bundled support files found in $archive_name"
exit 1
fi
missing=""
echo "$expected_paths" | while IFS= read -r relative_path; do
if [ -f "$install_dir/$relative_path" ]; then
echo "✅ Found $relative_path"
else
echo "MISSING:$relative_path"
fi
done > "$tmpdir/check_output"
cat "$tmpdir/check_output" | grep -v '^MISSING:' || true
missing="$(grep '^MISSING:' "$tmpdir/check_output" | sed 's/^MISSING://' || true)"
if [ -n "$missing" ]; then
printf '❌ Missing bundled support files after install:\n' >&2
echo "$missing" | while IFS= read -r p; do
printf ' %s\n' "$p" >&2
done
exit 1
fi
- name: Test shell config updates
run: |
echo "Checking shell configuration updates..."
if [[ "${{ matrix.shell }}" == "zsh" ]]; then
config_file=~/.zshrc
else
config_file=~/.bashrc
fi
if grep -q "COMPOSIO_INSTALL_DIR" "$config_file"; then
echo "✅ $config_file updated with COMPOSIO_INSTALL_DIR"
else
echo "❌ $config_file not updated with COMPOSIO_INSTALL_DIR"
echo "=== $config_file contents ==="
cat "$config_file"
exit 1
fi
if grep -q 'export PATH=.*COMPOSIO_INSTALL_DIR.*PATH' "$config_file"; then
echo "✅ $config_file updated with PATH"
else
echo "❌ $config_file PATH not updated"
echo "=== $config_file contents ==="
cat "$config_file"
exit 1
fi
- name: Test custom install directory
shell: bash
env:
USE_LATEST: ${{ steps.release_target.outputs.use_latest }}
RELEASE_TAG: ${{ steps.release_target.outputs.release_tag }}
run: |
echo "Testing custom install directory..."
# Clean up previous installation
rm -rf ~/.composio
# Test with custom directory using the same version as the workflow
export COMPOSIO_INSTALL_DIR="/tmp/custom-composio"
if [[ "$USE_LATEST" == "true" ]]; then
bash install.sh
else
bash install.sh "${RELEASE_TAG}"
fi
# Verify custom installation
if [[ -f "/tmp/custom-composio/composio" ]]; then
echo "✅ Custom directory installation successful"
ls -la "/tmp/custom-composio/composio"
else
echo "❌ Custom directory installation failed"
exit 1
fi
# Test execution
if "/tmp/custom-composio/composio" --version; then
echo "✅ Custom installation executes successfully"
else
echo "❌ Custom installation execution failed"
exit 1
fi
- name: Test uninstallation
run: |
echo "Testing uninstallation..."
# Remove binary
rm -rf ~/.composio /tmp/custom-composio
# Check if binary is gone
if [[ ! -f "$HOME/.composio/composio" ]]; then
echo "✅ Binary removed successfully"
else
echo "❌ Binary removal failed"
exit 1
fi
- name: Test error handling
shell: bash
run: |
echo "Testing error handling..."
# Test with invalid version
if bash install.sh v999.999.999 2>&1 | grep -q "Failed"; then
echo "✅ Error handling works for invalid version"
else
echo "❌ Error handling failed"
# Don't exit 1 here as this is expected to fail
fi
test-npm-fallback:
name: Test npm Installation Fallback
needs: toolchain-versions
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-15]
node-version: ${{ fromJSON(needs.toolchain-versions.outputs.node_install_compat) }}
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ${{ matrix.node-version }}
- name: Test npm installation
run: |
echo "Testing npm installation as fallback..."
# This would normally install from npm registry
# For testing, we just verify the command works
if command -v npm &> /dev/null; then
echo "✅ npm is available"
npm --version
else
echo "❌ npm not available"
exit 1
fi
test-architecture-detection:
name: Test Architecture Detection
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
arch: x64
expected: 'Linux x64'
- os: depot-ubuntu-24.04-arm
arch: arm64
expected: 'Linux ARM64'
- os: macos-15-intel
arch: x64
expected: 'macOS x64'
- os: macos-15
arch: arm64
expected: 'macOS ARM64'
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Test architecture detection
run: |
echo "Testing architecture detection for: ${{ matrix.expected }}"
platform=$(uname -ms)
echo "Detected platform: $platform"
case $platform in
'Darwin x86_64')
detected="macOS x64"
;;
'Darwin arm64')
detected="macOS ARM64"
;;
'Linux x86_64')
detected="Linux x64"
;;
'Linux aarch64'|'Linux arm64')
detected="Linux ARM64"
;;
*)
echo "❌ Unknown platform: $platform"
exit 1
;;
esac
if [[ "$detected" == "${{ matrix.expected }}" ]]; then
echo "✅ Correctly detected: $detected"
else
echo "❌ Detection mismatch: expected '${{ matrix.expected }}', got '$detected'"
exit 1
fi
test-prerequisites:
name: Test Prerequisites
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-15]
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Test required tools
run: |
echo "Testing required tools..."
# Test curl
if command -v curl &> /dev/null; then
echo "✅ curl available"
curl --version | head -1
else
echo "❌ curl not available"
exit 1
fi
# Test unzip
if command -v unzip &> /dev/null; then
echo "✅ unzip available"
unzip -v | head -1
else
echo "❌ unzip not available"
exit 1
fi
- name: Test without prerequisites
run: |
echo "Testing error handling when prerequisites are missing..."
# Create a version of the script that will fail prerequisite check
sed 's/command -v curl/command -v nonexistent-tool/' install.sh > test-install.sh
if bash test-install.sh 2>&1 | grep -q "required to install"; then
echo "✅ Prerequisites check works"
else
echo "❌ Prerequisites check failed"
exit 1
fi
rm test-install.sh
summary:
name: Installation Test Summary
needs:
[
install-script-unit-tests,
test-install-script,
test-npm-fallback,
test-architecture-detection,
test-prerequisites,
]
runs-on: ubuntu-latest
if: always()
steps:
- name: Test Results Summary
run: |
echo "## Installation Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ needs.install-script-unit-tests.result }}" == "success" ]]; then
echo "✅ **Install Script Unit Tests**: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Install Script Unit Tests**: FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.test-install-script.result }}" == "success" ]]; then
echo "✅ **Install Script Tests**: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Install Script Tests**: FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.test-npm-fallback.result }}" == "success" ]]; then
echo "✅ **npm Fallback Tests**: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **npm Fallback Tests**: FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.test-architecture-detection.result }}" == "success" ]]; then
echo "✅ **Architecture Detection**: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Architecture Detection**: FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [[ "${{ needs.test-prerequisites.result }}" == "success" ]]; then
echo "✅ **Prerequisites Check**: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Prerequisites Check**: FAILED" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Test Matrix Coverage:**" >> $GITHUB_STEP_SUMMARY
echo "- **Linux x64**: Ubuntu 22.04, Latest" >> $GITHUB_STEP_SUMMARY
echo "- **Linux ARM64**: Ubuntu 22.04, 24.04 (via Depot)" >> $GITHUB_STEP_SUMMARY
echo "- **macOS x64**: macOS 15 (Intel)" >> $GITHUB_STEP_SUMMARY
echo "- **macOS ARM64**: macOS 14, macOS 15 (Apple Silicon)" >> $GITHUB_STEP_SUMMARY
echo "- **Shells**: Bash and Zsh" >> $GITHUB_STEP_SUMMARY
echo "- **Node.js**: 18, 20, 22 (npm fallback)" >> $GITHUB_STEP_SUMMARY
echo "- **Total platforms**: 4 architectures across 15+ environments" >> $GITHUB_STEP_SUMMARY