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