Files
ccs/.github/workflows/ci.yml
T
Tam Nhu Tran 5101e21ecd ci: run PR CI for account-pools epic branch
Phase PRs target kai/feat/1464-account-pools instead of dev; without
this the full CI matrix never runs on them. Revisit at the final
epic-to-dev promotion PR.
2026-06-10 23:10:55 -04:00

197 lines
6.1 KiB
YAML

name: CI
on:
pull_request:
branches: [main, dev, kai/feat/1464-account-pools]
# Design notes:
# - Matrix parallelism cuts wall time from ~3-4min to ~60-90s (cache warm).
# - Concurrency group cancels superseded runs on the same ref (saves runner time on rapid pushes).
# - Build leg produces dist/ artifact; test leg downloads it instead of rebuilding (DRY).
# - fail-fast: false so every failure is visible in one run (no re-pushing to see the next failure).
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
validate:
if: >-
contains(fromJSON('["COLLABORATOR","MEMBER","OWNER"]'), github.event.pull_request.author_association)
runs-on: [self-hosted, linux, x64]
env:
# Keep Bun cache isolated per job workspace so parallel self-hosted runs
# do not race on ~/.bun/install/cache and corrupt restore/install state.
BUN_INSTALL_CACHE_DIR: ${{ github.workspace }}/.bun/install/cache
strategy:
fail-fast: false
matrix:
check:
- { name: typecheck, cmd: 'bun run typecheck' }
- { name: lint, cmd: 'bun run lint' }
- { name: format, cmd: 'bun run format:check' }
name: ${{ matrix.check.name }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: '1.3.9'
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Restore bun package cache
uses: actions/cache@v4
with:
path: |
${{ env.BUN_INSTALL_CACHE_DIR }}
key: ${{ runner.os }}-bun-cache-v2-${{ hashFiles('bun.lock', 'ui/bun.lock') }}
- name: Ensure dependencies
run: bash scripts/ensure-deps.sh
- name: Run ${{ matrix.check.name }}
run: ${{ matrix.check.cmd }}
build:
if: >-
contains(fromJSON('["COLLABORATOR","MEMBER","OWNER"]'), github.event.pull_request.author_association)
runs-on: [self-hosted, linux, x64]
name: build
env:
BUN_INSTALL_CACHE_DIR: ${{ github.workspace }}/.bun/install/cache
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: '1.3.9'
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Restore bun package cache
uses: actions/cache@v4
with:
path: |
${{ env.BUN_INSTALL_CACHE_DIR }}
key: ${{ runner.os }}-bun-cache-v2-${{ hashFiles('bun.lock', 'ui/bun.lock') }}
- name: Ensure dependencies
run: bash scripts/ensure-deps.sh
- name: Build
run: bun run build:all
- name: Upload dist artifact
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 1
if-no-files-found: error
test:
if: >-
contains(fromJSON('["COLLABORATOR","MEMBER","OWNER"]'), github.event.pull_request.author_association)
runs-on: [self-hosted, linux, x64]
name: test
needs: [build]
env:
BUN_INSTALL_CACHE_DIR: ${{ github.workspace }}/.bun/install/cache
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: '1.3.9'
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Restore bun package cache
uses: actions/cache@v4
with:
path: |
${{ env.BUN_INSTALL_CACHE_DIR }}
key: ${{ runner.os }}-bun-cache-v2-${{ hashFiles('bun.lock', 'ui/bun.lock') }}
- name: Ensure dependencies
run: bash scripts/ensure-deps.sh
- name: Download dist artifact
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Test
run: bun run test:all
- name: Test CLI e2e
env:
CCS_E2E_SKIP_BUILD: '1'
run: bun run test:e2e
compose-parity:
if: >-
contains(fromJSON('["COLLABORATOR","MEMBER","OWNER"]'), github.event.pull_request.author_association)
runs-on: [self-hosted, linux, x64, cliproxy]
name: compose-parity
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Assert compose parity (compose.yaml vs docker-compose.integrated.yml)
run: bash tests/docker/compose-parity.sh
# Single always-reporting status that branch protection requires.
#
# The validate/build/test jobs are gated to trusted author associations so
# untrusted fork code never executes on the self-hosted runners. A job skipped
# by a job-level `if` reports no status, so requiring those job names directly
# leaves fork PRs stuck on "Expected - waiting for status to be reported"
# forever. Requiring this gate instead keeps the contract satisfiable:
# - trusted PR: gate is green only if every gated job actually succeeded
# - fork PR: gated jobs skip, gate reports green so the PR is mergeable
# (fork code is still reviewed by a maintainer before merge)
#
# No checkout here: the gate only inspects upstream job results, so it runs no
# third-party code and is safe on the self-hosted runner.
ci-gate:
if: always()
needs: [validate, build, test]
runs-on: [self-hosted, linux, x64]
name: CI Gate
steps:
- name: Verify gated jobs did not fail
env:
VALIDATE: ${{ needs.validate.result }}
BUILD: ${{ needs.build.result }}
TEST: ${{ needs.test.result }}
run: |
echo "validate=$VALIDATE build=$BUILD test=$TEST"
for result in "$VALIDATE" "$BUILD" "$TEST"; do
if [ "$result" = "failure" ] || [ "$result" = "cancelled" ]; then
echo "[X] A required CI job did not pass (result: $result)"
exit 1
fi
done
echo "[OK] CI gate satisfied (success or skipped-for-fork)"