agent-desktop/.github/workflows/ci.yml
2026-06-17 19:38:33 -07:00

136 lines
4.8 KiB
YAML

name: CI
on:
push:
branches: [main, master]
pull_request:
workflow_dispatch:
# Cancel in-progress runs for the same ref so stale PR builds don't burn minutes.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
# Deny all permissions at workflow level; each job declares only what it needs.
permissions: {}
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
fmt:
name: Format
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- run: rustup component add rustfmt
- run: cargo fmt --all -- --check
test:
name: Test
runs-on: macos-latest
timeout-minutes: 30
permissions:
contents: read
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Install Rust toolchain
run: rustup show
- name: Cache cargo registry
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.lock', 'Cargo.toml', 'crates/**/Cargo.toml', 'src/Cargo.toml') }}
restore-keys: ${{ runner.os }}-cargo-
- name: Cache build artifacts
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: target/
key: ${{ runner.os }}-build-ci-${{ hashFiles('Cargo.lock', 'Cargo.toml', 'crates/**/Cargo.toml', 'src/Cargo.toml') }}-${{ hashFiles('crates/**/*.rs', 'src/**/*.rs', 'tests/**/*.rs') }}
restore-keys: |
${{ runner.os }}-build-ci-${{ hashFiles('Cargo.lock', 'Cargo.toml', 'crates/**/Cargo.toml', 'src/Cargo.toml') }}-
${{ runner.os }}-build-ci-
- name: Check dependency isolation
run: |
if cargo tree --locked -p agent-desktop-core 2>/dev/null | grep -E 'agent-desktop-(macos|windows|linux)'; then
echo "FAIL: core crate depends on platform crates"
exit 1
fi
echo "OK: core crate has no platform dependencies"
- name: Check release metadata consistency
run: scripts/check-release-consistency.sh
- name: Clippy
run: cargo clippy --locked --all-targets -- -D warnings
- name: Unit tests
run: cargo test --locked --lib --workspace
- name: Binary command tests
run: cargo test --locked -p agent-desktop
# The FFI crate ships integration harnesses under crates/ffi/tests/ that
# exercise the C-ABI from outside the crate (raw extern "C" decls, enum
# fuzzing, out-param zeroing, last-error lifetimes). The workspace --lib
# run skips them, so wire them in explicitly so regressions fail PR CI.
- name: FFI integration tests
run: cargo test --locked -p agent-desktop-ffi --tests
# Use the ci profile (no LTO, opt-level 1) — fast compile, still checks the binary builds.
- name: Build binary (ci profile)
run: cargo build --locked --profile ci
- name: Check binary size
run: |
SIZE=$(stat -f%z target/ci/agent-desktop)
LIMIT=$((15 * 1024 * 1024))
echo "Binary size: $(du -sh target/ci/agent-desktop | cut -f1)"
if [ "$SIZE" -gt "$LIMIT" ]; then
echo "FAIL: binary exceeds 15MB limit (${SIZE} bytes)"
exit 1
fi
echo "OK: binary within 15MB limit"
- name: FFI cdylib build (release-ffi profile)
run: cargo build --locked --profile release-ffi -p agent-desktop-ffi
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '24'
- name: NPM package contents
run: node scripts/check-npm-package.js
- name: NPM wrapper smoke
run: |
case "$(uname -s)-$(uname -m)" in
Darwin-arm64) NAME=agent-desktop-darwin-arm64 ;;
Darwin-x86_64) NAME=agent-desktop-darwin-x64 ;;
*)
echo "Unsupported smoke-test platform: $(uname -s)-$(uname -m)"
exit 1
;;
esac
trap 'rm -f "npm/bin/${NAME}"' EXIT
cp target/ci/agent-desktop "npm/bin/${NAME}"
chmod +x "npm/bin/${NAME}"
node npm/bin/agent-desktop.js version --json > /tmp/agent-desktop-version.json
node -e "
const out = require('fs').readFileSync('/tmp/agent-desktop-version.json', 'utf8');
const json = JSON.parse(out);
if (json.ok !== true || !json.data || typeof json.data.version !== 'string') {
throw new Error('agent-desktop npm wrapper did not return version JSON');
}
"