From b38df3d4948cb538495efd38b1a03d3abfa03e33 Mon Sep 17 00:00:00 2001 From: Thomas Kosiewski Date: Tue, 3 Nov 2026 22:45:28 +0000 Subject: [PATCH] ci: run the macOS integration tests in three shards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As one serial job, quality-gates-macos took 18 to 30 minutes, and the integration tests were 75 to 80 percent of it (1251 s of 27 min in the #306 run). The suite grows by about 3 minutes a day, so the 45-minute limit would last about a week. The macOS tests now run in four jobs at once: checks-macos (format, lint, typecheck, build, unit and e2e tests) and test-integration-macos (1/3, 2/3, 3/3), each with a 30-minute limit. quality-gates-macos stays as the check that the main ruleset requires. It now runs on Ubuntu, needs those jobs, and fails when any of them failed, was cancelled or was skipped, the same way quality-gates gates the Linux jobs. --- _Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `xhigh`_ --- .github/workflows/ci.yml | 68 +++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a893915..0e485800 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -242,13 +242,14 @@ jobs: if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }} run: exit 1 - # macOS counterpart to the Ubuntu quality gates above. It runs the static - # checks and the full test suite serially in one job, so PTY spawning, - # process groups and Unix domain sockets are tested on macOS too. - # A passing run takes 18 to 28 minutes, so 45 leaves room for a slow runner. - quality-gates-macos: + # macOS counterpart to the Ubuntu quality gates above, so PTY spawning, + # process groups and Unix domain sockets are tested on macOS too. As one + # serial job it took 18 to 30 minutes, 75 to 80 percent of it in the + # integration tests, so the integration tests run in three shards next to + # one job for the static checks, the unit tests and the e2e tests. + checks-macos: runs-on: macos-latest - timeout-minutes: 45 + timeout-minutes: 30 steps: - name: Check out repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -258,8 +259,8 @@ jobs: - name: Set up mise uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 with: - # The macOS job does not run workflow linting or Communique, so avoid - # installing release-only tools. It still needs aube for bootstrap-ci. + # The macOS jobs do not run workflow linting or Communique, so avoid + # installing release-only tools. They still need aube for bootstrap-ci. install_args: --locked node python aube - name: Install CI dependencies @@ -285,12 +286,55 @@ jobs: env: AGENT_TTY_REQUIRE_MOUSE_NATIVE: '1' - - name: Test integration - run: mise run test-integration + - name: Test e2e + run: mise run test-e2e env: AGENT_TTY_REQUIRE_MOUSE_NATIVE: '1' - - name: Test e2e - run: mise run test-e2e + test-integration-macos: + runs-on: macos-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + shard: [1/3, 2/3, 3/3] + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Set up mise + uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 + with: + install_args: --locked node python aube + + - name: Install CI dependencies + run: mise run bootstrap-ci + + - name: Install Playwright Chromium + run: npx playwright install chromium + + - name: Test integration shard + run: npm run test:integration -- --shard=${{ matrix.shard }} env: AGENT_TTY_REQUIRE_MOUSE_NATIVE: '1' + + # The ruleset for main requires this check, so it gates the macOS jobs + # above the way quality-gates gates the Linux ones. + quality-gates-macos: + runs-on: ubuntu-latest + timeout-minutes: 5 + needs: + - checks-macos + - test-integration-macos + if: ${{ always() }} + steps: + - name: Report macOS quality gate results + run: | + echo "checks-macos: ${{ needs.checks-macos.result }}" + echo "test-integration-macos: ${{ needs.test-integration-macos.result }}" + + - name: Fail if any macOS quality gate failed + if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped') }} + run: exit 1