Skip to content

chore: bump version to 0.3.105 #1111

chore: bump version to 0.3.105

chore: bump version to 0.3.105 #1111

Workflow file for this run

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)."