test(parity): run setup_cmd through the lane's CLI binary, not a hard… #75
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: Go CLI | |
| on: | |
| push: | |
| branches: [main, master] | |
| pull_request: | |
| branches: [main, master] | |
| workflow_dispatch: {} | |
| schedule: | |
| # Daily 06:00 UTC: the full runtime parity matrix + publish parity. On | |
| # push/PR only the cases affected by the change run (see parity-runtime). | |
| - cron: "0 6 * * *" | |
| jobs: | |
| lint-and-test: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| code-quality: write | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: go.mod | |
| - uses: go-task/setup-task@v2 | |
| with: | |
| version: 3.x | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - run: task lint | |
| - run: task spec:compliance | |
| - run: task vuln | |
| - run: task test:race | |
| - run: task coverage | |
| - name: Coverage summary | |
| if: always() | |
| run: bash scripts/coverage-report.sh coverage.out "unit (hermetic)" >> "$GITHUB_STEP_SUMMARY" | |
| - run: task test:integration | |
| - run: task build | |
| - run: ./devcontainer --version | |
| # Convert the Go coverage profile (coverage.out) to Cobertura XML for | |
| # GitHub's native Code Quality feature. | |
| - name: Convert coverage to Cobertura XML | |
| run: | | |
| go install github.com/boumenot/gocover-cobertura@latest | |
| gocover-cobertura < coverage.out > coverage.xml | |
| - name: Upload coverage report | |
| uses: actions/upload-code-coverage@v1 | |
| with: | |
| file: coverage.xml | |
| language: Go | |
| label: code-coverage/go | |
| # Binary covdata for the cross-lane merge (coverage-report job). | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: covdata-unit | |
| path: artifacts/coverage/data/unit | |
| if-no-files-found: error | |
| e2e: | |
| runs-on: ubuntu-latest | |
| needs: lint-and-test | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: go.mod | |
| - uses: go-task/setup-task@v2 | |
| with: | |
| version: 3.x | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - run: task coverage:e2e | |
| - name: Coverage summary | |
| if: always() | |
| run: bash scripts/coverage-report.sh artifacts/coverage/data/e2e "e2e" >> "$GITHUB_STEP_SUMMARY" | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: covdata-e2e | |
| path: artifacts/coverage/data/e2e | |
| if-no-files-found: error | |
| - if: always() | |
| run: task clean | |
| # Hermetic parity gate: read-configuration golden comparison + the contract | |
| # lane of the parity matrix (flag validation / output contract, no Docker). | |
| parity: | |
| runs-on: ubuntu-latest | |
| needs: lint-and-test | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: go.mod | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: "20" | |
| - uses: go-task/setup-task@v2 | |
| with: | |
| version: 3.x | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - run: task reference | |
| - run: task parity:contract | |
| - run: task parity:network | |
| # Coverage is measured separately with an instrumented Go binary. Keep the | |
| # functional parity run above release-like, and avoid conflating subprocess | |
| # coverage with the hermetic unit profile. | |
| - run: task coverage:parity-contract | |
| - name: Coverage summary | |
| if: always() | |
| run: bash scripts/coverage-report.sh artifacts/coverage/data/contract "parity:contract" >> "$GITHUB_STEP_SUMMARY" | |
| - if: always() | |
| run: | | |
| mkdir -p artifacts | |
| git -C reference rev-parse HEAD > artifacts/reference-commit.txt | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: parity-contract-network-v0.88.0 | |
| path: artifacts/ | |
| if-no-files-found: error | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: covdata-contract | |
| path: artifacts/coverage/data/contract | |
| if-no-files-found: error | |
| # Runtime lane of the parity matrix (creates real containers via Docker) on | |
| # push/PR, SCOPED to the commands affected by the change: the full matrix takes | |
| # ~45 min, so scripts/parity-affected.sh maps the diff to a | |
| # PARITY_COMMAND allowlist (or "all"/"none"). The daily parity-runtime-full job | |
| # is the backstop that always runs the whole thing. | |
| parity-runtime-shard: | |
| if: github.event_name == 'push' || github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| needs: lint-and-test | |
| strategy: | |
| # Split the affected runtime cases across independent runners (each with its | |
| # own docker daemon). fail-fast off so one shard's failure still reports the | |
| # others. The harness selects this shard's slice via PARITY_SHARD_INDEX. | |
| fail-fast: false | |
| matrix: | |
| shard: [0, 1] | |
| env: | |
| PARITY_RUNTIME_TIMEOUT: "10m" | |
| # Two shards, each running two cases at a time: the per-case isolation | |
| # (unique id-labels / COMPOSE_PROJECT_NAME / BUILDX_BUILDER) makes -parallel 2 | |
| # safe on a 2-core runner now that each runner only owns half the cases. | |
| PARITY_PARALLEL: "2" | |
| PARITY_SHARD_INDEX: ${{ matrix.shard }} | |
| PARITY_SHARD_TOTAL: "2" | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| # Full history so the diff base (PR base / previous push) is present. | |
| fetch-depth: 0 | |
| - name: Determine affected parity commands | |
| id: affected | |
| run: | | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| base="${{ github.event.pull_request.base.sha }}"; head="${{ github.event.pull_request.head.sha }}" | |
| else | |
| base="${{ github.event.before }}"; head="${{ github.sha }}" | |
| fi | |
| bash scripts/parity-affected-commands.sh "$base" "$head" >> "$GITHUB_OUTPUT" | |
| # Toolchain + runner prep + reference oracle, shared with parity-runtime-full. | |
| - if: steps.affected.outputs.run == 'true' | |
| uses: ./.github/actions/setup-parity-runtime | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - if: steps.affected.outputs.run == 'true' | |
| env: | |
| PARITY_COMMAND: ${{ steps.affected.outputs.commands }} | |
| run: task parity:runtime | |
| - if: always() && steps.affected.outputs.run == 'true' | |
| run: | | |
| mkdir -p artifacts | |
| git -C reference rev-parse HEAD > artifacts/reference-commit.txt | |
| - uses: actions/upload-artifact@v7 | |
| if: always() && steps.affected.outputs.run == 'true' | |
| with: | |
| name: parity-runtime-v0.88.0-shard-${{ matrix.shard }} | |
| path: artifacts/ | |
| if-no-files-found: error | |
| - if: always() && steps.affected.outputs.run == 'true' | |
| run: task clean | |
| # Stable required-check name aggregating the sharded runtime lane, so sharding | |
| # does not change the check name branch protection depends on. | |
| parity-runtime: | |
| if: always() && (github.event_name == 'push' || github.event_name == 'pull_request') | |
| runs-on: ubuntu-latest | |
| needs: parity-runtime-shard | |
| steps: | |
| - name: Gate on all runtime shards | |
| run: | | |
| result="${{ needs.parity-runtime-shard.result }}" | |
| echo "parity-runtime-shard aggregate result: $result" | |
| case "$result" in | |
| success|skipped) exit 0 ;; | |
| *) echo "one or more runtime shards failed"; exit 1 ;; | |
| esac | |
| # Gate the expensive daily lanes on "did the repo change today?". A manual dispatch | |
| # always runs; a scheduled run only proceeds if HEAD has a commit within the last | |
| # day (scripts/daily-changed.sh). On a private/billed repo this skips the full | |
| # runtime matrix + publish on quiet days. Runs on schedule/dispatch so it is never | |
| # skipped for those events — the heavy jobs `needs:` it, and a skipped need would | |
| # skip them regardless of its output. | |
| daily-changes: | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| outputs: | |
| run: ${{ steps.check.outputs.run }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - id: check | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "manual dispatch → always run" >&2 | |
| echo "run=true" >> "$GITHUB_OUTPUT" | |
| else | |
| bash scripts/daily-changed.sh >> "$GITHUB_OUTPUT" | |
| fi | |
| # Full runtime parity matrix. Runs once a day (schedule, only when the repo changed | |
| # — see daily-changes) and on manual dispatch — the exhaustive backstop for the | |
| # scoped push/PR job above. Sharded across independent runners (same | |
| # PARITY_SHARD_INDEX/TOTAL harness as the push/PR lane) so the 175-case matrix no | |
| # longer contends for one runner's CPU/disk/daemon, which was starving the | |
| # container setups and failing downstream exec cases. PARITY_SHARD_TOTAL MUST equal | |
| # the length of matrix.shard — parity_sharding_workflow_test.go enforces that, so a | |
| # mismatch can't silently drop cases. | |
| parity-runtime-full: | |
| needs: [lint-and-test, daily-changes] | |
| if: needs.daily-changes.outputs.run == 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| # fail-fast off so one shard's failure still reports the others. | |
| fail-fast: false | |
| matrix: | |
| shard: [0, 1, 2, 3] | |
| env: | |
| PARITY_RUNTIME_TIMEOUT: "10m" | |
| # Each shard owns ~a quarter of the matrix, so -parallel 2 per runner matches | |
| # the push/PR shard lane's proven-safe load instead of the old single-runner 3. | |
| PARITY_PARALLEL: "2" | |
| PARITY_SHARD_INDEX: ${{ matrix.shard }} | |
| PARITY_SHARD_TOTAL: "4" | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| - uses: ./.github/actions/setup-parity-runtime | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| # Instrumented binary: measures coverage AND gates parity on this shard's slice. | |
| - run: task coverage:parity-runtime | |
| - name: Coverage summary | |
| if: always() | |
| run: bash scripts/coverage-report.sh artifacts/coverage/data/runtime "parity:runtime shard ${{ matrix.shard }}" >> "$GITHUB_STEP_SUMMARY" | |
| - if: always() | |
| run: | | |
| mkdir -p artifacts | |
| git -C reference rev-parse HEAD > artifacts/reference-commit.txt | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: parity-runtime-full-v0.88.0-shard-${{ matrix.shard }} | |
| path: artifacts/ | |
| if-no-files-found: error | |
| # covdata slice for the cross-lane merge (distinct name per shard so the merge | |
| # job unions them instead of clobbering). | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: covdata-runtime-shard-${{ matrix.shard }} | |
| path: artifacts/coverage/data/runtime | |
| if-no-files-found: error | |
| - if: always() | |
| run: task clean | |
| # Publish parity (features/templates → ephemeral OCI registry). Independent of the | |
| # runtime matrix, so it runs as its own job rather than stealing a runtime shard's | |
| # runner. Was folded into the old monolithic parity-runtime-full. | |
| parity-publish-full: | |
| needs: [lint-and-test, daily-changes] | |
| if: needs.daily-changes.outputs.run == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| - uses: ./.github/actions/setup-parity-runtime | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - run: task coverage:parity-publish | |
| - name: Coverage summary | |
| if: always() | |
| run: bash scripts/coverage-report.sh artifacts/coverage/data/publish "parity:publish" >> "$GITHUB_STEP_SUMMARY" | |
| - uses: actions/upload-artifact@v7 | |
| if: always() | |
| with: | |
| name: covdata-publish | |
| path: artifacts/coverage/data/publish | |
| if-no-files-found: error | |
| - if: always() | |
| run: task clean | |
| # Daily gate + cross-lane coverage. Aggregates the sharded runtime lane and the | |
| # publish lane into one pass/fail (mirrors the push/PR parity-runtime gate) and | |
| # merges every lane's covdata — unit + e2e + contract (which also run on schedule) | |
| # plus the runtime shards + publish — into the one true cross-lane number. | |
| parity-runtime-full-report: | |
| if: always() && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') | |
| runs-on: ubuntu-latest | |
| needs: [lint-and-test, e2e, parity, parity-runtime-full, parity-publish-full] | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: go.mod | |
| - uses: go-task/setup-task@v2 | |
| with: | |
| version: 3.x | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Download all lane covdata | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: covdata-* | |
| path: artifacts/coverage/data | |
| # download-artifact nests each artifact under covdata-<lane>/; flatten to <lane>/ | |
| # so coverage:merge sees one dir per lane (the runtime shards stay distinct). | |
| - name: Normalize lane dirs | |
| run: | | |
| cd artifacts/coverage/data | |
| for d in covdata-*; do [ -d "$d" ] && mv "$d" "${d#covdata-}"; done | |
| ls -R . || true | |
| - name: Merged coverage report | |
| run: task coverage:merge | tee -a "$GITHUB_STEP_SUMMARY" | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: covdata-merged-full | |
| path: artifacts/coverage/data/merged.out | |
| if-no-files-found: warn | |
| # Final verdict last, so the coverage report is posted even when a shard failed. | |
| - name: Gate on all runtime shards + publish | |
| run: | | |
| runtime="${{ needs.parity-runtime-full.result }}" | |
| publish="${{ needs.parity-publish-full.result }}" | |
| echo "runtime shards: $runtime, publish: $publish" | |
| for r in "$runtime" "$publish"; do | |
| case "$r" in | |
| success|skipped) ;; | |
| *) echo "runtime/publish parity failed"; exit 1 ;; | |
| esac | |
| done | |
| # Experimental, NON-gating: arm64 runtime via QEMU emulation. arm64 runtime is | |
| # unsupported for now, so its cases are skipped-arm64 in the gate above. This job | |
| # is SLOW (QEMU) and only runs on a manual trigger (workflow_dispatch), not on | |
| # every push/PR — enable it when validating arm64. | |
| parity-runtime-arm64-experimental: | |
| if: github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| needs: lint-and-test | |
| continue-on-error: true | |
| env: | |
| PARITY_ARM64: "true" | |
| PARITY_RUNTIME_TIMEOUT: "15m" | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| submodules: recursive | |
| - name: Set up QEMU (arm64 emulation) | |
| uses: docker/setup-qemu-action@v4 | |
| with: | |
| platforms: arm64 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: go.mod | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: "20" | |
| - uses: go-task/setup-task@v2 | |
| with: | |
| version: 3.x | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - run: task ci:prepare-runner | |
| - run: task reference | |
| - run: task parity:runtime | |
| - if: always() | |
| run: task clean | |
| # Cross-lane coverage: merge the per-PR lanes' covdata (unit + e2e + contract) | |
| # into the one number no single lane shows, and post it to the run summary. | |
| coverage-report: | |
| if: always() && (github.event_name == 'push' || github.event_name == 'pull_request') | |
| runs-on: ubuntu-latest | |
| needs: [lint-and-test, e2e, parity] | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: go.mod | |
| - uses: go-task/setup-task@v2 | |
| with: | |
| version: 3.x | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Download lane covdata | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: covdata-* | |
| path: artifacts/coverage/data | |
| # download-artifact nests each artifact under covdata-<lane>/; flatten to <lane>/. | |
| - name: Normalize lane dirs | |
| run: | | |
| cd artifacts/coverage/data | |
| for d in covdata-*; do [ -d "$d" ] && mv "$d" "${d#covdata-}"; done | |
| ls -R . || true | |
| - name: Merged coverage report | |
| run: task coverage:merge | tee -a "$GITHUB_STEP_SUMMARY" | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: covdata-merged | |
| path: artifacts/coverage/data/merged.out | |
| if-no-files-found: warn | |
| cross-compile: | |
| runs-on: ubuntu-latest | |
| needs: lint-and-test | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: go.mod | |
| - uses: go-task/setup-task@v2 | |
| with: | |
| version: 3.x | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - run: task build:cross | |
| - run: ls -lh dist/ |