name: Conformance Matrix on: push: branches: [main] paths: - "tests/conformance/**" - "dart/engine/**" - "dart/shared/**" - "dart/compiler/**" - "ts/engine/**" - "ts/compiler/**" - "ts/shared/**" - "cpp/**" - "dart/self_host/**" schedule: - cron: "0 6 * * 1" # Weekly on Monday at 06:00 UTC workflow_dispatch: # Least-privilege: read-only token (conformance runs build + execute only). permissions: contents: read concurrency: group: conformance-${{ github.ref }} cancel-in-progress: true jobs: # ────────────────────────────────────────────────── # Dart engine (reference implementation) # ────────────────────────────────────────────────── dart-engine: name: Dart Engine runs-on: ubuntu-latest timeout-minutes: 90 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: dart-lang/setup-dart@65eb853c7ba17dde3be364c3d2858773e7144260 # v1 with: sdk: stable - name: Install dependencies run: cd dart && dart pub get - name: Run conformance tests id: conformance run: | cd dart/engine set +e output=$(dart test test/conformance_test.dart 2>&1) exit_code=$? echo "$output" # Parse pass/fail from dart test output passed=$(echo "$output" | grep -oP '^\+(\d+)' | tail -1 | grep -oP '\d+' || echo "0") # Dart test prints "+N -M" for failures or "+N" for all pass failed=$(echo "$output" | grep -oP '~?-(\d+)' | tail -1 | grep -oP '\d+' || echo "0") # Fallback: count from "All tests passed" or the summary line if echo "$output" | grep -q "All tests passed"; then total=$(echo "$output" | grep -oP '\+(\d+)' | tail -1 | grep -oP '\d+') passed="$total" failed="0" fi total=$((passed + failed)) echo "passed=$passed" >> "$GITHUB_OUTPUT" echo "failed=$failed" >> "$GITHUB_OUTPUT" echo "total=$total" >> "$GITHUB_OUTPUT" echo "" echo "=== Dart Engine ===" echo "Results: $passed passed, $failed failed, $total total" exit $exit_code outputs: passed: ${{ steps.conformance.outputs.passed }} failed: ${{ steps.conformance.outputs.failed }} total: ${{ steps.conformance.outputs.total }} # ────────────────────────────────────────────────── # TypeScript self-hosted engine (compiled from Ball) # ────────────────────────────────────────────────── ts-engine: name: TS Self-Hosted Engine runs-on: ubuntu-latest timeout-minutes: 90 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 cache: npm cache-dependency-path: ts/engine/package-lock.json - name: Install dependencies run: cd ts/engine && npm ci - name: Build run: cd ts/engine && npm run build - name: Run conformance tests id: conformance run: | cd ts/engine set +e output=$(node --experimental-strip-types test/engine_test.ts 2>&1) exit_code=$? echo "$output" # The TS engine prints: "Results: N passed, M failed, T total" passed=$(echo "$output" | grep -oP 'Results: \K\d+(?= passed)') failed=$(echo "$output" | grep -oP ', \K\d+(?= failed)') total=$(echo "$output" | grep -oP ', \K\d+(?= total)') echo "passed=${passed:-0}" >> "$GITHUB_OUTPUT" echo "failed=${failed:-0}" >> "$GITHUB_OUTPUT" echo "total=${total:-0}" >> "$GITHUB_OUTPUT" echo "" echo "=== TS Self-Hosted Engine ===" echo "Results: ${passed:-0} passed, ${failed:-0} failed, ${total:-0} total" exit $exit_code outputs: passed: ${{ steps.conformance.outputs.passed }} failed: ${{ steps.conformance.outputs.failed }} total: ${{ steps.conformance.outputs.total }} # ────────────────────────────────────────────────── # TS compiled engine (self-hosted Ball engine compiled to TS) # ────────────────────────────────────────────────── ts-compiled-engine: name: TS Compiled Engine runs-on: ubuntu-latest timeout-minutes: 90 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: 22 cache: npm cache-dependency-path: ts/compiler/package-lock.json - name: Install dependencies run: cd ts/compiler && npm ci - name: Build run: cd ts/compiler && npm run build - name: Run conformance tests id: conformance run: | cd ts/compiler set +e output=$(node --experimental-strip-types --test test/engine_runtime.test.ts 2>&1) exit_code=$? echo "$output" # node --test prints: "# pass N" and "# fail N" and "# tests N" passed=$(echo "$output" | grep -oP '^# pass \K\d+' || echo "0") failed=$(echo "$output" | grep -oP '^# fail \K\d+' || echo "0") total=$(echo "$output" | grep -oP '^# tests \K\d+' || echo "0") echo "passed=${passed:-0}" >> "$GITHUB_OUTPUT" echo "failed=${failed:-0}" >> "$GITHUB_OUTPUT" echo "total=${total:-0}" >> "$GITHUB_OUTPUT" echo "" echo "=== TS Compiled Engine ===" echo "Results: ${passed:-0} passed, ${failed:-0} failed, ${total:-0} total" exit $exit_code outputs: passed: ${{ steps.conformance.outputs.passed }} failed: ${{ steps.conformance.outputs.failed }} total: ${{ steps.conformance.outputs.total }} # ────────────────────────────────────────────────── # C++ compiled engine (Ball → C++ → g++ → run) # ────────────────────────────────────────────────── cpp-compiled: name: C++ Compiled runs-on: ubuntu-latest timeout-minutes: 90 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # NOTE: deliberately do NOT install a system protobuf. The checked-in # generated code in cpp/shared/gen/ targets the pinned protobuf # BALL_PROTOBUF_TAG (v34.1) and requires headers (runtime_version.h) # absent from Ubuntu apt's older libprotobuf-dev. CMake FetchContents the # matching version (same as ci.yml's C++ build). - name: ccache uses: hendrikmuhs/ccache-action@d62db5f07c26379fc4b4e0916f098a92573c3b03 # v1.2.23 with: key: cpp-compiled-matrix max-size: 1G - name: Install ninja run: sudo apt-get update && sudo apt-get install -y ninja-build - name: Configure CMake run: cmake -S cpp -B cpp/build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - name: Build Ball→C++ compiler run: cmake --build cpp/build --config Release --target ball_cpp_compile -j$(nproc) - name: Run C++ e2e conformance id: conformance run: | set +e output=$(bash cpp/test/full_e2e.sh 2>&1) exit_code=$? echo "$output" # Parse "Results: N passed, M failed, T total" line passed=$(echo "$output" | grep -oP 'Results: \K\d+(?= passed)') failed=$(echo "$output" | grep -oP ', \K\d+(?= failed)') total=$(echo "$output" | grep -oP ', \K\d+(?= total)') echo "passed=${passed:-0}" >> "$GITHUB_OUTPUT" echo "failed=${failed:-0}" >> "$GITHUB_OUTPUT" echo "total=${total:-0}" >> "$GITHUB_OUTPUT" echo "" echo "=== C++ Compiled ===" echo "Results: ${passed:-0} passed, ${failed:-0} failed, ${total:-0} total" exit $exit_code outputs: passed: ${{ steps.conformance.outputs.passed }} failed: ${{ steps.conformance.outputs.failed }} total: ${{ steps.conformance.outputs.total }} # ────────────────────────────────────────────────── # NEW LANGUAGE ENGINE TEMPLATE — copy and customize # ────────────────────────────────────────────────── # -engine: # name: Engine # runs-on: ubuntu-latest # steps: # - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # # - name: Setup # uses: # with: # -version: # # - name: Install & build # run: | # # # - name: Run conformance tests # id: conformance # run: | # set +e # output=$( 2>&1) # exit_code=$? # echo "$output" # # # Parse "Results: N passed, M failed, T total" line # passed=$(echo "$output" | grep -oP 'Results: \K\d+(?= passed)') # failed=$(echo "$output" | grep -oP ', \K\d+(?= failed)') # total=$(echo "$output" | grep -oP ', \K\d+(?= total)') # # echo "passed=${passed:-0}" >> "$GITHUB_OUTPUT" # echo "failed=${failed:-0}" >> "$GITHUB_OUTPUT" # echo "total=${total:-0}" >> "$GITHUB_OUTPUT" # # echo "" # echo "=== Engine ===" # echo "Results: ${passed:-0} passed, ${failed:-0} failed, ${total:-0} total" # # exit $exit_code # # outputs: # passed: ${{ steps.conformance.outputs.passed }} # failed: ${{ steps.conformance.outputs.failed }} # total: ${{ steps.conformance.outputs.total }} # # Then add to the summary job: # 1. Add "-engine" to the needs: array # 2. Add a print_row call for the new engine # 3. Add a failure check in the exit-code block # ────────────────────────────────────────────────── # Summary — parity matrix across all engines # ────────────────────────────────────────────────── summary: name: Parity Matrix runs-on: ubuntu-latest timeout-minutes: 90 if: always() needs: [dart-engine, ts-engine, ts-compiled-engine, cpp-compiled] steps: - name: Print conformance matrix run: | echo "╔══════════════════════════════╦════════╦════════╦════════╦════════╗" echo "║ Engine ║ Passed ║ Failed ║ Total ║ Status ║" echo "╠══════════════════════════════╬════════╬════════╬════════╬════════╣" print_row() { local name="$1" passed="$2" failed="$3" total="$4" result="$5" local status="PASS" if [ "$result" != "success" ]; then status="FAIL" fi printf "║ %-28s ║ %6s ║ %6s ║ %6s ║ %-6s ║\n" \ "$name" "${passed:-?}" "${failed:-?}" "${total:-?}" "$status" } print_row "Dart Engine (reference)" \ "${{ needs.dart-engine.outputs.passed }}" \ "${{ needs.dart-engine.outputs.failed }}" \ "${{ needs.dart-engine.outputs.total }}" \ "${{ needs.dart-engine.result }}" print_row "TS Self-Hosted Engine" \ "${{ needs.ts-engine.outputs.passed }}" \ "${{ needs.ts-engine.outputs.failed }}" \ "${{ needs.ts-engine.outputs.total }}" \ "${{ needs.ts-engine.result }}" print_row "TS Compiled Engine" \ "${{ needs.ts-compiled-engine.outputs.passed }}" \ "${{ needs.ts-compiled-engine.outputs.failed }}" \ "${{ needs.ts-compiled-engine.outputs.total }}" \ "${{ needs.ts-compiled-engine.result }}" print_row "C++ Compiled" \ "${{ needs.cpp-compiled.outputs.passed }}" \ "${{ needs.cpp-compiled.outputs.failed }}" \ "${{ needs.cpp-compiled.outputs.total }}" \ "${{ needs.cpp-compiled.result }}" echo "╚══════════════════════════════╩════════╩════════╩════════╩════════╝" # Fail the summary if any engine job failed if [ "${{ needs.dart-engine.result }}" != "success" ] || \ [ "${{ needs.ts-engine.result }}" != "success" ] || \ [ "${{ needs.ts-compiled-engine.result }}" != "success" ] || \ [ "${{ needs.cpp-compiled.result }}" != "success" ]; then echo "" echo "One or more engines failed conformance. See individual job logs above." exit 1 fi echo "" echo "All engines passed conformance."