𧬠Mutation Tests (Stryker) #39
Workflow file for this run
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
| # ============================================================ | |
| # WorldScript Studio β Mutation Testing (Stryker) β Parallel + Incremental | |
| # QNBS-v3: Matrix-parallel Stryker with per-module caches and fail-safe aggregation. | |
| # Run manually via workflow_dispatch. Each matrix job targets one curated module; | |
| # runtime and score remain measured outputs rather than undocumented promises. | |
| # ============================================================ | |
| name: 𧬠Mutation Tests (Stryker) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| mode: | |
| description: 'Run mode' | |
| required: true | |
| default: 'incremental' | |
| type: choice | |
| options: | |
| - incremental | |
| - force | |
| module: | |
| description: 'Scope selector: all, tier-a, or one module name' | |
| required: false | |
| default: 'all' | |
| per_job_concurrency: | |
| description: 'Concurrency per job (default: 2)' | |
| required: false | |
| default: '2' | |
| concurrency: | |
| group: mutation-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| scope: | |
| name: 𧬠Validate Stryker Scope | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.scope.outputs.matrix }} | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - id: scope | |
| shell: bash | |
| run: | | |
| SELECTOR="${{ github.event.inputs.module || 'all' }}" | |
| node scripts/stryker-scope.mjs --selector "$SELECTOR" | |
| echo "matrix=$(node scripts/stryker-scope.mjs --matrix --selector "$SELECTOR")" >> "$GITHUB_OUTPUT" | |
| # ============================================ | |
| # PARALLEL MATRIX JOBS (one per module) | |
| # ============================================ | |
| stryker: | |
| name: 𧬠Stryker ${{ matrix.name }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| needs: scope | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJSON(needs.scope.outputs.matrix) }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: ./.github/actions/setup | |
| # === Incremental cache (per module) === | |
| - name: Restore Stryker incremental cache | |
| id: cache-incremental | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| with: | |
| path: reports/stryker-incremental-${{ matrix.name }}.json | |
| key: stryker-incremental-${{ matrix.name }}-${{ github.sha }} | |
| restore-keys: | | |
| stryker-incremental-${{ matrix.name }}- | |
| - name: Prepare incremental file | |
| run: | | |
| mkdir -p reports | |
| MODE="${{ github.event.inputs.mode || 'incremental' }}" | |
| if [ "$MODE" = "force" ]; then | |
| echo "π§Ή Force mode β clearing incremental cache for ${{ matrix.name }}" | |
| rm -f reports/stryker-incremental-${{ matrix.name }}.json | |
| elif [ -f "reports/stryker-incremental-${{ matrix.name }}.json" ]; then | |
| echo "β»οΈ Using existing incremental cache for ${{ matrix.name }}" | |
| else | |
| echo "π No incremental cache found β will create new one" | |
| fi | |
| - name: Run Stryker (${{ matrix.name }}) | |
| run: | | |
| MODE="${{ github.event.inputs.mode || 'incremental' }}" | |
| FORCE_FLAG="" | |
| if [ "$MODE" = "force" ]; then | |
| FORCE_FLAG="--force" | |
| fi | |
| CONCURRENCY="${{ github.event.inputs.per_job_concurrency || '2' }}" | |
| echo "βΆοΈ Module: ${{ matrix.name }}" | |
| echo " Pattern: ${{ matrix.mutate }}" | |
| echo " Concurrency: $CONCURRENCY" | |
| echo " Mode: $MODE" | |
| # QNBS-v3: pass the supported CLI option; arbitrary env vars are not Stryker config. | |
| INCREMENTAL_FILE="reports/stryker-incremental-${{ matrix.name }}.json" | |
| pnpm exec stryker run \ | |
| stryker.config.mjs \ | |
| --incremental \ | |
| --incrementalFile "$INCREMENTAL_FILE" \ | |
| $FORCE_FLAG \ | |
| --concurrency "$CONCURRENCY" \ | |
| --mutate "${{ matrix.mutate }}" \ | |
| --reporters progress,json,html | |
| env: | |
| STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} | |
| - name: Upload Stryker report | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: stryker-report-${{ matrix.name }} | |
| path: reports/mutation/ | |
| if-no-files-found: error | |
| retention-days: 30 | |
| # ============================================ | |
| # AGGREGATE JOB β combined summary | |
| # ============================================ | |
| aggregate: | |
| name: π Stryker Aggregate Report | |
| runs-on: ubuntu-latest | |
| needs: [scope, stryker] | |
| if: always() | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Download all Stryker reports | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| path: all-reports | |
| pattern: stryker-report-* | |
| merge-multiple: false | |
| - name: Build combined summary | |
| run: | | |
| if [ "${{ needs.stryker.result }}" != "success" ]; then | |
| echo "Stryker matrix did not complete successfully: ${{ needs.stryker.result }}" >&2 | |
| exit 1 | |
| fi | |
| node scripts/aggregate-stryker-reports.mjs all-reports | tee -a "$GITHUB_STEP_SUMMARY" | |
| echo "> Mode: \`${{ github.event.inputs.mode || 'incremental' }}\` | Concurrency: \`${{ github.event.inputs.per_job_concurrency || '2' }}\`" >> "$GITHUB_STEP_SUMMARY" | |
| echo "> Threshold: break β₯ 75 | low β₯ 70 | high β₯ 85" >> "$GITHUB_STEP_SUMMARY" | |
| echo "> Individual HTML/JSON reports are available as artifacts." >> "$GITHUB_STEP_SUMMARY" |