Repository navigation
chore: bump version to 0.3.105 #1111
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: tests | |
| on: | |
| pull_request: | |
| branches: [main] | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| inputs: | |
| test_tier: | |
| description: 'Test tier to run' | |
| type: choice | |
| options: | |
| - smoke | |
| - standard | |
| - full | |
| default: full | |
| # Cancel in-progress runs when a new commit is pushed to the same branch/PR. | |
| # This prevents wasted CI minutes when iterating on a PR. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| # Native module CI expectations: | |
| # - better-sqlite3 requires a native .node binding compiled for the exact Node.js ABI in use. | |
| # - pnpm-workspace.yaml lists better-sqlite3 under ignoredBuiltDependencies, so pnpm install | |
| # alone will NOT compile the binding. An explicit `npm rebuild better-sqlite3` is required. | |
| # - The pnpm store cache key MUST include the Node.js version to prevent restoring bindings | |
| # compiled for a different ABI (cross-ABI cache poisoning). | |
| # - A verification step runs `require('better-sqlite3')` before tests to fail fast with | |
| # clear diagnostics if the native binding is missing or incompatible. | |
| # Test tier system: | |
| # - smoke: critical-path @smoke-tagged tests only (~50-100 tests, <3 min) | |
| # - standard: scoped tests based on change detection (current PR behavior) | |
| # - full: entire test suite (all shards, all tests) | |
| # | |
| # Tier selection: | |
| # - pull_request: smoke (fast feedback) | |
| # - push to main: full (comprehensive) | |
| # - workflow_dispatch: user choice (default: full) | |
| # | |
| # Change-detection scoping (standard/full tiers): | |
| # - docs-only PRs skip all test suites entirely | |
| # - Scoped source changes (pmo, execution) run only affected unit + e2e subsets | |
| # - Core/runtime changes (database, shared lib, config files) trigger the full suite | |
| # - The ci-status job serves as a single required check for branch protection | |
| jobs: | |
| detect-changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| run_tests: ${{ steps.classify.outputs.run_tests }} | |
| scope: ${{ steps.classify.outputs.scope }} | |
| tier: ${{ steps.classify.outputs.tier }} | |
| reason: ${{ steps.classify.outputs.reason }} | |
| e2e_shards: ${{ steps.classify.outputs.e2e_shards }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Fetch base branch | |
| if: github.event_name == 'pull_request' | |
| run: git fetch origin ${{ github.base_ref }} | |
| - name: Classify changed paths | |
| id: classify | |
| shell: bash | |
| run: | | |
| # Determine test tier based on event type | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| TIER="${{ github.event.inputs.test_tier }}" | |
| TIER="${TIER:-full}" | |
| elif [[ "${{ github.event_name }}" == "push" ]]; then | |
| TIER="full" | |
| else | |
| # pull_request: use smoke tier for fast feedback | |
| TIER="smoke" | |
| fi | |
| echo "tier=$TIER" >> "$GITHUB_OUTPUT" | |
| echo "Selected tier: $TIER" | |
| # For push to main and manual dispatch (standard/full), always run full suite | |
| if [[ "${{ github.event_name }}" == "push" ]]; then | |
| echo "run_tests=true" >> "$GITHUB_OUTPUT" | |
| echo "scope=full" >> "$GITHUB_OUTPUT" | |
| echo "reason=Full suite: push event" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=["pmo","execution","agent-flows","json-mode","integrations","standalone","infrastructure"]' >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| echo "run_tests=true" >> "$GITHUB_OUTPUT" | |
| if [[ "$TIER" == "smoke" ]]; then | |
| echo "scope=smoke" >> "$GITHUB_OUTPUT" | |
| echo "reason=Smoke tier: manual dispatch with smoke tier selected" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=["smoke"]' >> "$GITHUB_OUTPUT" | |
| else | |
| echo "scope=full" >> "$GITHUB_OUTPUT" | |
| echo "reason=Full suite: manual dispatch with $TIER tier selected" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=["pmo","execution","agent-flows","json-mode","integrations","standalone","infrastructure"]' >> "$GITHUB_OUTPUT" | |
| fi | |
| exit 0 | |
| fi | |
| # Get the list of changed files relative to the PR base | |
| MERGE_BASE=$(git merge-base origin/${{ github.base_ref }} HEAD || true) | |
| if [[ -z "$MERGE_BASE" ]]; then | |
| echo "run_tests=true" >> "$GITHUB_OUTPUT" | |
| echo "scope=full" >> "$GITHUB_OUTPUT" | |
| echo "reason=Full suite: unable to compute merge-base with origin/${{ github.base_ref }}" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=["pmo","execution","agent-flows","json-mode","integrations","standalone","infrastructure"]' >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| CHANGED=$(git diff --name-only "$MERGE_BASE" HEAD) | |
| if [[ -z "$CHANGED" ]]; then | |
| echo "run_tests=false" >> "$GITHUB_OUTPUT" | |
| echo "scope=none" >> "$GITHUB_OUTPUT" | |
| echo "reason=No files changed" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=[]' >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "Changed files:" | |
| echo "$CHANGED" | |
| echo "---" | |
| # Classify each file into a category | |
| HAS_DOCS=false | |
| HAS_SCRIPTS=false | |
| HAS_PMO=false | |
| HAS_EXECUTION=false | |
| HAS_CORE=false | |
| while IFS= read -r file; do | |
| [[ -z "$file" ]] && continue | |
| case "$file" in | |
| # Documentation files | |
| docs/*|CONTRIBUTING.md|CHANGELOG.md|LICENSE|specs/*) | |
| HAS_DOCS=true | |
| ;; | |
| # Markdown files at root (but not CLAUDE.md which affects dev workflow) | |
| README.md|apps/cli/README.md) | |
| HAS_DOCS=true | |
| ;; | |
| # Scripts directory | |
| scripts/*) | |
| HAS_SCRIPTS=true | |
| ;; | |
| # PMO domain: ticket/project/board management source and tests | |
| apps/cli/src/lib/pmo/*|\ | |
| apps/cli/src/commands/ticket/*|\ | |
| apps/cli/src/commands/project/*|\ | |
| apps/cli/src/commands/board/*|\ | |
| apps/cli/src/commands/epic/*|\ | |
| apps/cli/src/commands/spec/*|\ | |
| apps/cli/src/commands/roadmap/*|\ | |
| apps/cli/src/commands/category/*|\ | |
| apps/cli/src/commands/label/*|\ | |
| apps/cli/src/commands/workflow/*|\ | |
| apps/cli/src/commands/status/*|\ | |
| apps/cli/src/commands/template/*|\ | |
| apps/cli/src/commands/priority/*|\ | |
| apps/cli/src/commands/phase/*|\ | |
| apps/cli/src/commands/diet.ts|\ | |
| apps/cli/src/commands/pull.ts|\ | |
| apps/cli/test/e2e/pmo-*|\ | |
| apps/cli/test/unit/pmo*) | |
| HAS_PMO=true | |
| ;; | |
| # Execution domain: work/agent/docker/session orchestration | |
| apps/cli/src/lib/execution/*|\ | |
| apps/cli/src/commands/work/*|\ | |
| apps/cli/src/commands/agent/*|\ | |
| apps/cli/src/commands/docker/*|\ | |
| apps/cli/src/commands/session/*|\ | |
| apps/cli/src/commands/orchestrator/*|\ | |
| apps/cli/src/lib/agents/*|\ | |
| apps/cli/src/lib/docker/*|\ | |
| apps/cli/test/e2e/work-*|\ | |
| apps/cli/test/e2e/*-agent-flow*|\ | |
| apps/cli/test/unit/execution-*|\ | |
| apps/cli/test/unit/agent-*|\ | |
| apps/cli/test/unit/spawner*|\ | |
| apps/cli/test/unit/session-*|\ | |
| apps/cli/test/unit/ephemeral-*) | |
| HAS_EXECUTION=true | |
| ;; | |
| # Everything else is core (shared lib, database, config, CI, etc.) | |
| *) | |
| HAS_CORE=true | |
| ;; | |
| esac | |
| done <<< "$CHANGED" | |
| echo "Classification: docs=$HAS_DOCS scripts=$HAS_SCRIPTS pmo=$HAS_PMO execution=$HAS_EXECUTION core=$HAS_CORE" | |
| # Check for docs-only changes first (skip tests entirely regardless of tier) | |
| if [[ "$HAS_CORE" != "true" && "$HAS_PMO" != "true" && "$HAS_EXECUTION" != "true" ]]; then | |
| echo "run_tests=false" >> "$GITHUB_OUTPUT" | |
| echo "scope=docs-only" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=[]' >> "$GITHUB_OUTPUT" | |
| PARTS="" | |
| [[ "$HAS_DOCS" == "true" ]] && PARTS="documentation" | |
| [[ "$HAS_SCRIPTS" == "true" ]] && PARTS="${PARTS:+$PARTS + }scripts" | |
| echo "reason=Skipped: only ${PARTS:-non-code} files changed — no test suites needed" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # For smoke tier (default on PRs): run only @smoke-tagged tests | |
| if [[ "$TIER" == "smoke" ]]; then | |
| echo "run_tests=true" >> "$GITHUB_OUTPUT" | |
| echo "scope=smoke" >> "$GITHUB_OUTPUT" | |
| echo "reason=Smoke tier: running @smoke-tagged critical-path tests only (<3 min)" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=["smoke"]' >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # For standard/full tiers: determine scope based on classification | |
| if [[ "$HAS_CORE" == "true" ]]; then | |
| echo "run_tests=true" >> "$GITHUB_OUTPUT" | |
| echo "scope=full" >> "$GITHUB_OUTPUT" | |
| echo "reason=Full suite: core/shared files changed (database, lib, config, CI, or unscoped source)" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=["pmo","execution","agent-flows","json-mode","integrations","standalone","infrastructure"]' >> "$GITHUB_OUTPUT" | |
| elif [[ "$HAS_PMO" == "true" && "$HAS_EXECUTION" == "true" ]]; then | |
| echo "run_tests=true" >> "$GITHUB_OUTPUT" | |
| echo "scope=full" >> "$GITHUB_OUTPUT" | |
| echo "reason=Full suite: changes span multiple domains (pmo + execution)" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=["pmo","execution","agent-flows","json-mode","integrations","standalone","infrastructure"]' >> "$GITHUB_OUTPUT" | |
| elif [[ "$HAS_PMO" == "true" ]]; then | |
| echo "run_tests=true" >> "$GITHUB_OUTPUT" | |
| echo "scope=pmo" >> "$GITHUB_OUTPUT" | |
| echo "reason=Scoped run: only PMO-related files changed (ticket/project/board management)" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=["pmo"]' >> "$GITHUB_OUTPUT" | |
| elif [[ "$HAS_EXECUTION" == "true" ]]; then | |
| echo "run_tests=true" >> "$GITHUB_OUTPUT" | |
| echo "scope=execution" >> "$GITHUB_OUTPUT" | |
| echo "reason=Scoped run: only execution-related files changed (work/agent/docker orchestration)" >> "$GITHUB_OUTPUT" | |
| echo 'e2e_shards=["execution","agent-flows"]' >> "$GITHUB_OUTPUT" | |
| fi | |
| build: | |
| needs: [detect-changes] | |
| if: needs.detect-changes.outputs.run_tests == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| matrix: | |
| node-version: ['22'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| - name: Get pnpm store directory | |
| id: pnpm-cache | |
| shell: bash | |
| run: echo "store-path=$(pnpm store path)" >> $GITHUB_OUTPUT | |
| # Cache key includes Node.js version to avoid restoring native bindings compiled | |
| # for a different ABI when lts/* resolves to a new Node.js release. | |
| - uses: actions/cache@v4 | |
| with: | |
| path: ${{ steps.pnpm-cache.outputs.store-path }} | |
| key: ${{ runner.os }}-node-${{ matrix.node-version }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-node-${{ matrix.node-version }}-pnpm-store- | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| # Rebuild better-sqlite3 native binding for the current Node.js ABI. | |
| # pnpm skips this during install because better-sqlite3 is in ignoredBuiltDependencies. | |
| # Retry once on failure to handle EEXIST race condition in node-gyp symlink creation. | |
| # The binding is cached as an artifact so test jobs can skip this step. | |
| - name: Rebuild better-sqlite3 native binding | |
| run: | | |
| cd apps/cli | |
| if node -e "require('better-sqlite3')" 2>/dev/null; then | |
| echo "better-sqlite3 binding already present, skipping rebuild" | |
| else | |
| echo "Rebuilding better-sqlite3 native binding..." | |
| npm rebuild better-sqlite3 || npm rebuild better-sqlite3 | |
| fi | |
| # Fail fast if the native binding is missing or was compiled for a different ABI. | |
| - name: Verify better-sqlite3 native binding | |
| run: | | |
| node -e " | |
| try { | |
| require('better-sqlite3'); | |
| console.log('better-sqlite3 loaded successfully'); | |
| console.log('Node version:', process.version); | |
| console.log('ABI version:', process.versions.modules); | |
| console.log('Platform:', process.platform, process.arch); | |
| } catch (err) { | |
| console.error('Failed to load better-sqlite3:'); | |
| console.error(err.message); | |
| console.error('Node version:', process.version); | |
| console.error('ABI version:', process.versions.modules); | |
| console.error('Platform:', process.platform, process.arch); | |
| process.exit(1); | |
| } | |
| " | |
| working-directory: apps/cli | |
| - name: Build | |
| run: pnpm -r build | |
| # Upload build output (dist + native binding) so test jobs skip rebuilding. | |
| # This saves ~60-90s per test job (6 jobs total = ~6-9 min saved). | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: build-output-node-${{ matrix.node-version }} | |
| path: | | |
| apps/cli/dist/ | |
| retention-days: 1 | |
| # Cache the better-sqlite3 native binding separately. | |
| # Test jobs restore this cache after pnpm install to skip the native rebuild. | |
| - name: Cache better-sqlite3 native binding | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: apps/cli/node_modules/.pnpm/**/better-sqlite3/build | |
| key: ${{ runner.os }}-node-${{ matrix.node-version }}-better-sqlite3-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| # Unit tests run via ts-node directly (no compiled dist/ needed), so they | |
| # can start in parallel with the build job instead of waiting for it. | |
| # The postinstall script handles better-sqlite3 native binding rebuild. | |
| unit-tests: | |
| needs: [detect-changes] | |
| if: needs.detect-changes.outputs.run_tests == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| matrix: | |
| node-version: ['22'] | |
| fail-fast: false | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| - name: Get pnpm store directory | |
| id: pnpm-cache | |
| shell: bash | |
| run: echo "store-path=$(pnpm store path)" >> $GITHUB_OUTPUT | |
| # Cache key includes Node.js version to avoid cross-ABI cache poisoning. | |
| - uses: actions/cache@v4 | |
| with: | |
| path: ${{ steps.pnpm-cache.outputs.store-path }} | |
| key: ${{ runner.os }}-node-${{ matrix.node-version }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-node-${{ matrix.node-version }}-pnpm-store- | |
| # pnpm install handles better-sqlite3 rebuild via postinstall script. | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| # Fail fast if the native binding is missing or was compiled for a different ABI. | |
| - name: Verify better-sqlite3 native binding | |
| run: | | |
| node -e " | |
| try { | |
| require('better-sqlite3'); | |
| console.log('better-sqlite3 loaded successfully'); | |
| } catch (err) { | |
| console.error('Failed to load better-sqlite3:', err.message); | |
| process.exit(1); | |
| } | |
| " | |
| working-directory: apps/cli | |
| - name: Run unit tests | |
| working-directory: apps/cli | |
| run: | | |
| SCOPE="${{ needs.detect-changes.outputs.scope }}" | |
| TIER="${{ needs.detect-changes.outputs.tier }}" | |
| echo "Unit test scope: $SCOPE (tier: $TIER)" | |
| case "$SCOPE" in | |
| smoke) | |
| echo "Running smoke unit tests (@smoke tagged only)" | |
| pnpm test:smoke:unit | |
| ;; | |
| full) | |
| echo "Running full unit test suite" | |
| pnpm test:unit | |
| ;; | |
| pmo) | |
| echo "Running PMO-scoped unit tests" | |
| npx mocha --forbid-only "test/unit/pmo-*.test.ts" | |
| ;; | |
| execution) | |
| echo "Running execution-scoped unit tests" | |
| npx mocha --forbid-only \ | |
| "test/unit/execution-*.test.ts" \ | |
| "test/unit/agent-*.test.ts" \ | |
| "test/unit/session-*.test.ts" \ | |
| "test/unit/spawner*.test.ts" \ | |
| "test/unit/codex-*.test.ts" | |
| ;; | |
| *) | |
| echo "Running full unit test suite (unrecognized scope: $SCOPE)" | |
| pnpm test:unit | |
| ;; | |
| esac | |
| # TKT-1169: Codex spawn smoke tests run as a dedicated step so failures | |
| # are immediately visible. Any Codex command contract change will fail here. | |
| # Only runs for execution or full scope since codex is in the execution domain. | |
| - name: Codex spawn smoke checks | |
| if: | | |
| needs.detect-changes.outputs.scope == 'full' || | |
| needs.detect-changes.outputs.scope == 'execution' | |
| run: pnpm --filter @proletariat/cli mocha --forbid-only "test/unit/codex-spawn-smoke.test.ts" | |
| e2e-tests: | |
| needs: [detect-changes, build] | |
| if: | | |
| always() && | |
| needs.detect-changes.outputs.run_tests == 'true' && | |
| needs.build.result == 'success' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 35 | |
| strategy: | |
| matrix: | |
| node-version: ['22'] | |
| shard: ${{ fromJson(needs.detect-changes.outputs.e2e_shards) }} | |
| fail-fast: false | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| - name: Get pnpm store directory | |
| id: pnpm-cache | |
| shell: bash | |
| run: echo "store-path=$(pnpm store path)" >> $GITHUB_OUTPUT | |
| # Cache key includes Node.js version to avoid cross-ABI cache poisoning. | |
| - uses: actions/cache@v4 | |
| with: | |
| path: ${{ steps.pnpm-cache.outputs.store-path }} | |
| key: ${{ runner.os }}-node-${{ matrix.node-version }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-node-${{ matrix.node-version }}-pnpm-store- | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| # Restore better-sqlite3 native binding from cache (built by the build job). | |
| # Falls back to a full rebuild if the cache is unavailable. | |
| - name: Restore better-sqlite3 native binding cache | |
| id: sqlite-cache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: apps/cli/node_modules/.pnpm/**/better-sqlite3/build | |
| key: ${{ runner.os }}-node-${{ matrix.node-version }}-better-sqlite3-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| - name: Rebuild better-sqlite3 native binding (cache miss) | |
| if: steps.sqlite-cache.outputs.cache-hit != 'true' | |
| run: npm rebuild better-sqlite3 || npm rebuild better-sqlite3 | |
| working-directory: apps/cli | |
| # Fail fast if the native binding is missing or was compiled for a different ABI. | |
| - name: Verify better-sqlite3 native binding | |
| run: | | |
| node -e " | |
| try { | |
| require('better-sqlite3'); | |
| console.log('better-sqlite3 loaded successfully'); | |
| console.log('Node version:', process.version); | |
| console.log('ABI version:', process.versions.modules); | |
| console.log('Platform:', process.platform, process.arch); | |
| } catch (err) { | |
| console.error('Failed to load better-sqlite3:'); | |
| console.error(err.message); | |
| console.error('Node version:', process.version); | |
| console.error('ABI version:', process.versions.modules); | |
| console.error('Platform:', process.platform, process.arch); | |
| process.exit(1); | |
| } | |
| " | |
| working-directory: apps/cli | |
| # Download pre-built dist/ from the build job instead of rebuilding TypeScript. | |
| - name: Download build artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: build-output-node-${{ matrix.node-version }} | |
| path: apps/cli/dist/ | |
| - name: Run e2e tests (${{ matrix.shard }}) | |
| working-directory: apps/cli | |
| run: | | |
| SHARD="${{ matrix.shard }}" | |
| echo "E2E shard: $SHARD" | |
| case "$SHARD" in | |
| smoke) | |
| echo "Running smoke e2e tests (@smoke tagged only)" | |
| pnpm test:smoke:e2e | |
| ;; | |
| pmo) | |
| echo "Running PMO e2e tests" | |
| npx mocha --forbid-only "test/e2e/pmo-*.test.ts" | |
| ;; | |
| execution) | |
| echo "Running execution/work e2e tests" | |
| npx mocha --forbid-only "test/e2e/work-*.test.ts" | |
| ;; | |
| agent-flows) | |
| echo "Running agent flow e2e tests" | |
| npx mocha --forbid-only "test/e2e/*-agent-flow.test.ts" | |
| ;; | |
| json-mode) | |
| echo "Running JSON/machine mode e2e tests" | |
| npx mocha --forbid-only \ | |
| --ignore "test/e2e/work-*.test.ts" \ | |
| "test/e2e/*-json-mode.test.ts" \ | |
| "test/e2e/json-mode-*.test.ts" \ | |
| "test/e2e/machine-mode-*.test.ts" \ | |
| "test/e2e/agent-json-mode.test.ts" | |
| ;; | |
| integrations) | |
| echo "Running integration e2e tests" | |
| npx mocha --forbid-only \ | |
| --ignore "test/e2e/*-agent-flow.test.ts" \ | |
| --ignore "test/e2e/*-json-mode.test.ts" \ | |
| "test/e2e/gh-*.test.ts" \ | |
| "test/e2e/pr-*.test.ts" \ | |
| "test/e2e/branch-*.test.ts" \ | |
| "test/e2e/linear-*.test.ts" \ | |
| "test/e2e/monday-*.test.ts" \ | |
| "test/e2e/mcp-board-*.test.ts" \ | |
| "test/e2e/session-*.test.ts" | |
| ;; | |
| infrastructure) | |
| echo "Running infrastructure e2e tests" | |
| npx mocha --forbid-only \ | |
| "test/e2e/docker-*.test.ts" \ | |
| "test/e2e/mcp-server.test.ts" \ | |
| "test/e2e/execution-*.test.ts" | |
| ;; | |
| standalone) | |
| echo "Running standalone e2e tests" | |
| npx mocha --forbid-only --timeout 30000 \ | |
| --ignore "test/e2e/pmo-*.test.ts" \ | |
| --ignore "test/e2e/work-*.test.ts" \ | |
| --ignore "test/e2e/*-agent-flow.test.ts" \ | |
| --ignore "test/e2e/*-json-mode.test.ts" \ | |
| --ignore "test/e2e/json-mode-*.test.ts" \ | |
| --ignore "test/e2e/machine-mode-*.test.ts" \ | |
| --ignore "test/e2e/gh-*.test.ts" \ | |
| --ignore "test/e2e/pr-*.test.ts" \ | |
| --ignore "test/e2e/branch-*.test.ts" \ | |
| --ignore "test/e2e/linear-*.test.ts" \ | |
| --ignore "test/e2e/monday-*.test.ts" \ | |
| --ignore "test/e2e/mcp-*.test.ts" \ | |
| --ignore "test/e2e/docker-*.test.ts" \ | |
| --ignore "test/e2e/session-*.test.ts" \ | |
| --ignore "test/e2e/execution-*.test.ts" \ | |
| "test/e2e/**/*.test.ts" | |
| ;; | |
| *) | |
| echo "Unknown shard: $SHARD, running full suite" | |
| pnpm test:e2e | |
| ;; | |
| esac | |
| # Single required status check for branch protection. | |
| # Always runs and reports success only when all test jobs succeeded | |
| # or were appropriately skipped by change detection. | |
| ci-status: | |
| name: CI Status | |
| if: always() | |
| needs: [detect-changes, build, unit-tests, e2e-tests] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: CI Summary | |
| run: | | |
| SCOPE="${{ needs.detect-changes.outputs.scope }}" | |
| TIER="${{ needs.detect-changes.outputs.tier }}" | |
| REASON="${{ needs.detect-changes.outputs.reason }}" | |
| BUILD="${{ needs.build.result }}" | |
| UNIT="${{ needs.unit-tests.result }}" | |
| E2E="${{ needs.e2e-tests.result }}" | |
| echo "## CI Summary" >> "$GITHUB_STEP_SUMMARY" | |
| echo "" >> "$GITHUB_STEP_SUMMARY" | |
| echo "**Tier:** \`$TIER\`" >> "$GITHUB_STEP_SUMMARY" | |
| echo "**Scope:** \`$SCOPE\`" >> "$GITHUB_STEP_SUMMARY" | |
| echo "**Reason:** $REASON" >> "$GITHUB_STEP_SUMMARY" | |
| echo "" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| Job | Result |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "|-----|--------|" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| detect-changes | ${{ needs.detect-changes.result }} |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| build | $BUILD |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| unit-tests | $UNIT |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| e2e-tests (all shards) | $E2E |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "" >> "$GITHUB_STEP_SUMMARY" | |
| echo "**E2E shards:** ${{ needs.detect-changes.outputs.e2e_shards }}" >> "$GITHUB_STEP_SUMMARY" | |
| echo "" | |
| echo "=== CI Results ===" | |
| echo "Tier: $TIER" | |
| echo "Scope: $SCOPE" | |
| echo "Reason: $REASON" | |
| echo "E2E shards: ${{ needs.detect-changes.outputs.e2e_shards }}" | |
| echo "detect-changes: ${{ needs.detect-changes.result }}" | |
| echo "build: $BUILD" | |
| echo "unit-tests: $UNIT" | |
| echo "e2e-tests: $E2E" | |
| - name: Verify no failures | |
| run: | | |
| # Fail if any job that ran actually failed | |
| if [[ "${{ needs.detect-changes.result }}" == "failure" ]]; then | |
| echo "FAIL: detect-changes failed" | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.build.result }}" == "failure" ]]; then | |
| echo "FAIL: build failed" | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.unit-tests.result }}" == "failure" ]]; then | |
| echo "FAIL: unit-tests failed" | |
| exit 1 | |
| fi | |
| if [[ "${{ needs.e2e-tests.result }}" == "failure" ]]; then | |
| echo "FAIL: e2e-tests failed" | |
| exit 1 | |
| fi | |
| echo "All checks passed (or were appropriately skipped)." |