/ .github / workflows / ci.yml
ci.yml
  1  name: CI
  2  
  3  on:
  4    push:
  5      branches: [main, dev]
  6    pull_request:
  7      branches: [main, dev]
  8    schedule:
  9      - cron: '0 8 * * 1'  # Weekly Monday 08:00 UTC — smoke tests
 10    workflow_dispatch:
 11  
 12  concurrency:
 13    group: ci-${{ github.ref }}
 14    cancel-in-progress: true
 15  
 16  jobs:
 17    # ── Fast gate: typecheck + build ──
 18    build:
 19      runs-on: ${{ matrix.os }}
 20      strategy:
 21        fail-fast: false
 22        matrix:
 23          os: [ubuntu-latest, macos-latest, windows-latest]
 24      steps:
 25        - uses: actions/checkout@v6
 26  
 27        - uses: actions/setup-node@v6
 28          with:
 29            node-version: '22'
 30            cache: 'npm'
 31  
 32        - name: Install dependencies
 33          run: npm ci
 34  
 35        - name: Type check
 36          run: npx tsc --noEmit
 37  
 38        - name: Build
 39          run: npm run build
 40  
 41        # Guard: committed cli-manifest.json must match the one build regenerates.
 42        # Prevents silent drift where unrelated adapter entries vanish or change
 43        # across PRs (agent hits unexpected manifest diff → surgical-merge churn).
 44        - name: Check cli-manifest.json is up-to-date
 45          if: runner.os == 'Linux'
 46          shell: bash
 47          run: |
 48            if ! git diff --exit-code -- cli-manifest.json; then
 49              echo "::error::cli-manifest.json is out of sync with the source. Run 'npm run build' and commit the result."
 50              exit 1
 51            fi
 52  
 53    # ── Unit tests (vitest shard) ──
 54    # PR: ubuntu + Node 22 only (fast feedback, 2 jobs).
 55    # Push to main/dev: full matrix for cross-platform/cross-version coverage (12 jobs).
 56    unit-test:
 57      runs-on: ${{ matrix.os }}
 58      strategy:
 59        fail-fast: false
 60        matrix:
 61          os: ${{ (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && fromJSON('["ubuntu-latest","macos-latest","windows-latest"]') || fromJSON('["ubuntu-latest"]') }}
 62          node-version: ${{ (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && fromJSON('["22"]') || fromJSON('["22"]') }}
 63          shard: [1, 2]
 64      steps:
 65        - uses: actions/checkout@v6
 66  
 67        - uses: actions/setup-node@v6
 68          with:
 69            node-version: ${{ matrix.node-version }}
 70            cache: 'npm'
 71  
 72        - name: Install dependencies
 73          run: npm ci
 74  
 75        - name: Run unit tests (Node ${{ matrix.node-version }}, shard ${{ matrix.shard }}/2)
 76          run: npx vitest run --project unit --project extension --reporter=verbose --shard=${{ matrix.shard }}/2
 77  
 78    # ── Bun compatibility check ──
 79    bun-test:
 80      runs-on: ubuntu-latest
 81      steps:
 82        - uses: actions/checkout@v6
 83  
 84        - uses: oven-sh/setup-bun@v2
 85          with:
 86            bun-version: 1.3.5
 87  
 88        - uses: actions/setup-node@v6
 89          with:
 90            node-version: '22'
 91            cache: 'npm'
 92  
 93        - name: Install dependencies
 94          run: npm ci
 95  
 96        - name: Run unit tests under Bun
 97          run: bun vitest run --project unit --reporter=verbose
 98  
 99    # Adapter tests are pure unit tests — OS doesn't affect results.
100    adapter-test:
101      runs-on: ubuntu-latest
102      needs: build
103      steps:
104        - uses: actions/checkout@v6
105  
106        - uses: actions/setup-node@v6
107          with:
108            node-version: '22'
109            cache: 'npm'
110  
111        - name: Install dependencies
112          run: npm ci
113  
114        - name: Run focused adapter tests
115          run: npm run test:adapter -- --reporter=verbose
116  
117    # ── Smoke tests (scheduled / manual only) ──
118    smoke-test:
119      if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
120      needs: build
121      runs-on: ${{ matrix.os }}
122      strategy:
123        fail-fast: false
124        matrix:
125          # NOTE: Windows excluded — browser-actions/setup-chrome hangs during
126          # Chrome MSI installation on Windows runners (known issue).
127          os: [ubuntu-latest, macos-latest]
128      steps:
129        - uses: actions/checkout@v6
130  
131        - uses: actions/setup-node@v6
132          with:
133            node-version: '22'
134            cache: 'npm'
135  
136        - name: Install dependencies
137          run: npm ci
138  
139        - name: Setup Chrome
140          uses: ./.github/actions/setup-chrome
141          id: setup-chrome
142  
143        - name: Build
144          run: npm run build
145  
146        - name: Run smoke tests (Linux, via xvfb)
147          if: runner.os == 'Linux'
148          run: |
149            xvfb-run --auto-servernum --server-args="-screen 0 1280x720x24" \
150              npx vitest run tests/smoke/ --reporter=verbose
151  
152        - name: Run smoke tests (macOS / Windows)
153          if: runner.os != 'Linux'
154          run: npx vitest run tests/smoke/ --reporter=verbose
155      timeout-minutes: 15