Repository navigation
Integrate native activation and RF3 acceptance flows with 50 TUnit slots #66
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: Build and Tests | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| workflow_dispatch: | |
| inputs: | |
| task: | |
| description: 'Acceptance task; all runs complete qualification and all task lanes' | |
| type: choice | |
| default: all | |
| options: [all, KL-008, KL-011, KL-014, KL-015, KL-021, KL-027, KL-036, KL-033, KL-035, KL-029] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: keyload-build-tests-${{ github.event_name == 'pull_request' && github.ref || github.run_id }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| repository-checks: | |
| name: Check repository rules | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Check repository rules | |
| run: node scripts/Features/RepositoryGovernance/verify.mjs | |
| analyzer-rules: | |
| name: Test code analyzers | |
| if: ${{ github.event_name != 'workflow_dispatch' || inputs.task == 'all' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up .NET | |
| uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 | |
| with: | |
| global-json-file: global.json | |
| - name: Restore .NET packages | |
| run: dotnet restore KeyLoad.slnx | |
| - name: Build analyzer tests | |
| run: | | |
| dotnet build src/KeyLoad.AppHost --no-restore --configuration Release | |
| dotnet build tests/KeyLoad.Analyzers.Tests --no-restore --configuration Release | |
| - name: Prepare source-bound analyzer coverage | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'artifacts/code-quality/analyzer-coverage' | |
| New-Item -ItemType Directory -Path $evidence -Force | Out-Null | |
| Copy-Item scripts/Features/CodeQuality/site-analyzer-coverage.settings.xml (Join-Path $evidence 'coverage.config.xml') | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/site-analyzer-coverage.ps1 ` | |
| -Mode Prepare -Repository $root ` | |
| -Contract (Join-Path $root 'scripts/Features/CodeQuality/site-analyzer-coverage.contract.json') ` | |
| -EvidenceRoot $evidence | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Run analyzer tests | |
| id: analyzers | |
| run: | | |
| node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=analyzers --KeyLoadTests:ResultsDirectory=TestResults/analyzers --KeyLoadTests:ReportTrx=true "--KeyLoadTests:CoverageSettings=$GITHUB_WORKSPACE/artifacts/code-quality/analyzer-coverage/coverage.config.xml" "--KeyLoadTests:CoverageOutput=$GITHUB_WORKSPACE/artifacts/code-quality/analyzer-coverage/coverage.cobertura.xml" | |
| - name: Verify every analyzer test passed | |
| if: ${{ !cancelled() && steps.analyzers.outcome != 'skipped' }} | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $files = @(Get-ChildItem -LiteralPath (Join-Path $root 'TestResults/analyzers') -Filter '*.trx' -File) | |
| if ($files.Count -ne 1) { throw 'Expected exactly one analyzer TRX receipt' } | |
| [xml]$document = Get-Content -LiteralPath $files[0].FullName -Raw | |
| $counts = $document.TestRun.ResultSummary.Counters | |
| if ([int]$counts.total -le 0 -or [int]$counts.executed -ne [int]$counts.total -or | |
| [int]$counts.passed -ne [int]$counts.total) { | |
| throw 'Incomplete or failing analyzer qualification; skipped tests cannot pass' | |
| } | |
| [ordered]@{ | |
| sourceRevision = $env:GITHUB_SHA | |
| total = [int]$counts.total | |
| executed = [int]$counts.executed | |
| passed = [int]$counts.passed | |
| sha256 = (Get-FileHash -LiteralPath $files[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() | |
| } | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $root 'artifacts/code-quality/analyzer-coverage/test-receipt.json') -Encoding utf8NoBOM | |
| - name: Verify source-bound analyzer coverage | |
| if: ${{ !cancelled() && steps.analyzers.outcome != 'skipped' }} | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'artifacts/code-quality/analyzer-coverage' | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/site-analyzer-coverage.ps1 ` | |
| -Mode Verify -Repository $root ` | |
| -Contract (Join-Path $root 'scripts/Features/CodeQuality/site-analyzer-coverage.contract.json') ` | |
| -EvidenceRoot $evidence -CoverageReport (Join-Path $evidence 'coverage.cobertura.xml') | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Save analyzer test results | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: analyzer-rule-evidence | |
| path: | | |
| TestResults/** | |
| tests/KeyLoad.Analyzers.Tests/**/TestResults/** | |
| artifacts/code-quality/** | |
| if-no-files-found: error | |
| verify: | |
| name: Build and test KeyLoad | |
| if: ${{ github.event_name != 'workflow_dispatch' || inputs.task == 'all' }} | |
| needs: repository-checks | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest] | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 120 | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up .NET | |
| uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 | |
| with: | |
| global-json-file: global.json | |
| - name: Restore .NET packages | |
| run: dotnet restore KeyLoad.slnx | |
| - name: Build KeyLoad | |
| id: build | |
| run: dotnet build KeyLoad.slnx --no-restore --configuration Release | |
| - name: Prepare native source and test-image identity receipts | |
| id: native-source-identity | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'TestResults/native-source-identity' | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.production-source-manifest.ps1 ` | |
| -Mode prepare -Root $root -EvidenceRoot $evidence | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Verify the pinned native full-text package | |
| run: | | |
| node --input-type=module <<'JS' | |
| import fs from 'node:fs'; | |
| import path from 'node:path'; | |
| import crypto from 'node:crypto'; | |
| import { execFileSync, spawnSync } from 'node:child_process'; | |
| const cache = execFileSync('dotnet', ['nuget', 'locals', 'global-packages', '--list'], { encoding: 'utf8' }).trim(); | |
| const prefix = 'global-packages: '; | |
| if (!cache.startsWith(prefix) || cache.includes('\n')) throw new Error('Ambiguous NuGet package cache.'); | |
| const packagePath = path.join(cache.slice(prefix.length), 'zonetree.fulltextsearch', '1.0.9', 'zonetree.fulltextsearch.1.0.9.nupkg'); | |
| const digest = crypto.createHash('sha256').update(fs.readFileSync(packagePath)).digest('hex'); | |
| if (digest !== '7ea1fbb7aba0ad00391d78d2f414166b500335f5b1affe43c305d861b55719ff') throw new Error('Native FTS package differs from ADR-078.'); | |
| const verification = spawnSync('dotnet', ['nuget', 'verify', packagePath, '--all'], { encoding: 'utf8', maxBuffer: 1048576 }); | |
| fs.mkdirSync('artifacts/qualification', { recursive: true }); | |
| fs.writeFileSync('artifacts/qualification/native-full-text-package-signature.log', `Package SHA256: ${digest}\n${verification.stdout ?? ''}${verification.stderr ?? ''}`); | |
| process.stdout.write(verification.stdout ?? ''); | |
| process.stderr.write(verification.stderr ?? ''); | |
| if (verification.error || verification.status !== 0) throw verification.error ?? new Error('Native FTS package signature verification failed.'); | |
| JS | |
| - name: Build current Debug analyzer for native formatting | |
| run: dotnet build src/KeyLoad.Analyzers/KeyLoad.Analyzers.csproj --no-restore --configuration Debug | |
| - name: Check code formatting | |
| run: dotnet format KeyLoad.slnx --verify-no-changes --no-restore | |
| - name: Check repository rules | |
| run: node scripts/Features/RepositoryGovernance/verify.mjs | |
| - name: Test code analyzers | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=analyzers --KeyLoadTests:ReportTrx=true | |
| - name: Test native coverage source ownership | |
| id: source-ownership | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=unit '--KeyLoadTests:Filter=/*/*/(NativePathMapCompilerTests)|(ProductionSourceManifestSettlementTests)|(NativeSourceManifestChildSettlementTests)|(ProductionSourceManifestOperationTests)/*' --KeyLoadTests:ResultsDirectory=TestResults/native-source-ownership --KeyLoadTests:ReportTrx=true | |
| - name: Verify original source ownership test receipt | |
| if: ${{ !cancelled() && steps.source-ownership.outcome != 'skipped' }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| Set-StrictMode -Version Latest | |
| $reports = @(Get-ChildItem TestResults/native-source-ownership -Filter '*.trx' -Recurse -File) | |
| if ($reports.Count -ne 1) { throw 'Exactly one original source ownership TRX is required.' } | |
| [xml] $trx = Get-Content -LiteralPath $reports[0].FullName -Raw | |
| $counters = $trx.TestRun.ResultSummary.Counters | |
| if ([int] $counters.total -ne 10 -or [int] $counters.executed -ne 10 -or | |
| [int] $counters.passed -ne 10 -or [int] $counters.failed -ne 0) { | |
| throw 'Every native source ownership case must execute and pass.' | |
| } | |
| $receipt = [ordered]@{ | |
| source = $env:GITHUB_SHA; total = 10; executed = 10; passed = 10 | |
| originalTrxSha256 = (Get-FileHash -LiteralPath $reports[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant() | |
| } | |
| $receipt | ConvertTo-Json | Set-Content TestResults/native-source-ownership/test-receipt.json | |
| - name: Run unit tests | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' }} | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=unit --KeyLoadTests:ReportTrx=true | |
| - name: Run unit tests without CPU intrinsics | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' }} | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=unit-scalar --KeyLoadTests:ReportTrx=true | |
| - name: Test recovery after process crashes | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' }} | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=recovery --KeyLoadTests:ReportTrx=true | |
| - name: Verify native source and test-image identity receipts | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' && steps.native-source-identity.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'TestResults/native-source-identity' | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.production-source-manifest.ps1 ` | |
| -Mode verify -Root $root -EvidenceRoot $evidence | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Save test results | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: test-results-${{ matrix.os }} | |
| path: | | |
| **/TestResults/** | |
| artifacts/qualification/** | |
| if-no-files-found: ignore | |
| - name: Save build diagnostics | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: code-quality-${{ matrix.os }} | |
| path: artifacts/code-quality/** | |
| if-no-files-found: error | |
| task-acceptance: | |
| name: Qualify ${{ matrix.task }} (${{ matrix.profile }} caller) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 180 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| task: ${{ fromJSON(inputs.task == 'KL-008' && '["KL-008"]' || inputs.task == 'KL-011' && '["KL-011"]' || inputs.task == 'KL-014' && '["KL-014"]' || inputs.task == 'KL-015' && '["KL-015"]' || inputs.task == 'KL-021' && '["KL-021"]' || inputs.task == 'KL-027' && '["KL-027"]' || inputs.task == 'KL-036' && '["KL-036"]' || inputs.task == 'KL-033' && '["KL-033"]' || inputs.task == 'KL-035' && '["KL-035"]' || inputs.task == 'KL-029' && '["KL-029"]' || '["KL-008","KL-011","KL-014","KL-015","KL-021","KL-027","KL-036","KL-033","KL-035","KL-029"]') }} | |
| profile: [normal, scalar] | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up .NET | |
| uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 | |
| with: | |
| global-json-file: global.json | |
| - name: Check Docker | |
| if: ${{ matrix.task != 'KL-008' }} | |
| run: docker version | |
| - name: Build this task's KeyLoad server image | |
| if: ${{ matrix.task != 'KL-008' }} | |
| id: images | |
| run: node scripts/Features/BenchmarkComparisons/prepare-images.mjs --server-only | |
| - name: Configure this task's Docker image | |
| if: ${{ matrix.task != 'KL-008' }} | |
| shell: bash | |
| env: | |
| KEYLOAD_SERVER_IMAGE: ${{ steps.images.outputs.server-image }} | |
| run: | | |
| test -n "$KEYLOAD_SERVER_IMAGE" | |
| printf 'KeyLoad__ContainerImages__Server=%s\nKEYLOAD_IMAGE_RECEIPT=%s\n' "$KEYLOAD_SERVER_IMAGE" "$RUNNER_TEMP/keyload-images/image-receipt.json" >> "$GITHUB_ENV" | |
| - name: Restore .NET packages | |
| run: dotnet restore KeyLoad.slnx | |
| - name: Build the complete current solution | |
| id: build | |
| run: dotnet build KeyLoad.slnx --no-restore --configuration Release | |
| - name: Prepare original task source and test-image receipts | |
| id: source-identity | |
| shell: pwsh | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.production-source-manifest.ps1 ` | |
| -Mode prepare -Root $env:GITHUB_WORKSPACE ` | |
| -EvidenceRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/task-acceptance') | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Discover and execute this task's complete acceptance flows | |
| id: acceptance | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' && steps.source-identity.outcome == 'success' }} | |
| shell: pwsh | |
| env: | |
| KEYLOAD_ACCEPTANCE_TASK: ${{ matrix.task }} | |
| KEYLOAD_ACCEPTANCE_PROFILE: ${{ matrix.profile }} | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/task-acceptance.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE ` | |
| -EvidenceRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/task-acceptance') ` | |
| -Task $env:KEYLOAD_ACCEPTANCE_TASK -Profile $env:KEYLOAD_ACCEPTANCE_PROFILE | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Verify unchanged task source and test images | |
| if: ${{ !cancelled() && steps.source-identity.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.production-source-manifest.ps1 ` | |
| -Mode verify -Root $env:GITHUB_WORKSPACE ` | |
| -EvidenceRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/task-acceptance') | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Clean up this task's Docker registry | |
| if: ${{ always() && (steps.images.outcome == 'success' || steps.images.outcome == 'failure') }} | |
| run: node scripts/Features/BenchmarkComparisons/cleanup-images.mjs | |
| - name: Save this task's original acceptance results | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: task-acceptance-${{ matrix.task }}-${{ matrix.profile }} | |
| path: | | |
| TestResults/task-acceptance/** | |
| artifacts/code-quality/** | |
| ${{ runner.temp }}/keyload-images/** | |
| if-no-files-found: error | |
| docker-rf3: | |
| name: Test three-node database | |
| if: ${{ github.event_name != 'workflow_dispatch' || inputs.task == 'all' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 180 | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up .NET | |
| uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 | |
| with: | |
| global-json-file: global.json | |
| - name: Check Docker | |
| run: docker version | |
| - name: Build KeyLoad server Docker image | |
| id: images | |
| run: node scripts/Features/BenchmarkComparisons/prepare-images.mjs --server-only | |
| - name: Configure Docker image references | |
| shell: bash | |
| env: | |
| KEYLOAD_SERVER_IMAGE: ${{ steps.images.outputs.server-image }} | |
| run: | | |
| test -n "$KEYLOAD_SERVER_IMAGE" | |
| printf 'KeyLoad__ContainerImages__Server=%s\nKEYLOAD_IMAGE_RECEIPT=%s\n' "$KEYLOAD_SERVER_IMAGE" "$RUNNER_TEMP/keyload-images/image-receipt.json" >> "$GITHUB_ENV" | |
| - name: Find Chrome for admin tests | |
| shell: bash | |
| run: | | |
| admin_chrome=$(command -v google-chrome || command -v google-chrome-stable || command -v chromium || command -v chromium-browser) | |
| test -n "$admin_chrome" && test -x "$admin_chrome" | |
| "$admin_chrome" --version | |
| printf 'KEYLOAD_ADMIN_CHROME_PATH=%s\n' "$admin_chrome" >> "$GITHUB_ENV" | |
| - name: Restore .NET packages | |
| run: dotnet restore KeyLoad.slnx | |
| - name: Build the complete native coverage cohort | |
| run: dotnet build KeyLoad.slnx --no-restore --configuration Release | |
| - name: Prepare original source and test-image receipts | |
| id: coverage-source | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'TestResults/functional-coverage/rf3' | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.production-source-manifest.ps1 ` | |
| -Mode prepare -Root $root -EvidenceRoot $evidence | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| "KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST=$evidence/functional-coverage.production-source-manifest.json" | Add-Content $env:GITHUB_ENV | |
| - name: Test three-node database with .NET and MCP clients | |
| id: rf3-required | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=rf3 --KeyLoadTests:ResultsDirectory=TestResults/rf3-required --KeyLoadTests:ReportTrx=true | |
| - name: Check original three-node reports for diagnostic upload | |
| id: rf3-original-reports | |
| if: ${{ !cancelled() && (steps.rf3-required.outcome == 'success' || steps.rf3-required.outcome == 'failure') }} | |
| shell: bash | |
| run: | | |
| test -d TestResults/rf3-required | |
| original_trx=$(find TestResults/rf3-required -type f -name '*.trx' -size +0c -print -quit) | |
| test -n "$original_trx" | |
| printf '%s\n' "$original_trx" | |
| - name: Save original three-node diagnostics before covered suites | |
| if: ${{ !cancelled() && steps.rf3-original-reports.outcome == 'success' }} | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: docker-rf3-original-diagnostics | |
| path: | | |
| TestResults/rf3-required/** | |
| TestResults/functional-coverage/rf3/** | |
| if-no-files-found: error | |
| - name: Reconcile original native full and five-group discovery in both modes | |
| id: native-census | |
| if: ${{ !cancelled() && steps.coverage-source.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.workflow-discovery.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE ` | |
| -EvidenceRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/rf3') | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Execute full censuses and twelve original covered suite inputs | |
| id: functional-coverage | |
| if: ${{ !cancelled() && steps.native-census.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.workflow-collect.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE ` | |
| -EvidenceRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/rf3') ` | |
| -SourceManifestPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Verify original coverage source and test-image receipts after all children settle | |
| id: coverage-source-after | |
| if: ${{ !cancelled() && steps.coverage-source.outcome == 'success' }} | |
| shell: pwsh | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.production-source-manifest.ps1 ` | |
| -Mode verify -Root $env:GITHUB_WORKSPACE ` | |
| -EvidenceRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/rf3') | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Assemble product descriptor from original reports | |
| id: product-descriptor | |
| if: ${{ success() }} | |
| shell: pwsh | |
| env: | |
| RECOVERY_EXIT_CODE: ${{ steps.functional-coverage.outputs.recovery_exit_code }} | |
| RF3_EXIT_CODE: ${{ steps.functional-coverage.outputs.rf3_exit_code }} | |
| run: | | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.native-product-descriptor.ps1 ` | |
| -Repository $env:GITHUB_WORKSPACE ` | |
| -SourceManifestPath $env:KEYLOAD_PRODUCT_COVERAGE_SOURCE_MANIFEST ` | |
| -ResultsRoot (Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/rf3') ` | |
| -UnitRunStatusPath (Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/rf3/functional-coverage.unit-run-status.v1.json') ` | |
| -RecoveryExitCode ([int]$env:RECOVERY_EXIT_CODE) -Rf3ExitCode ([int]$env:RF3_EXIT_CODE) | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Exercise original product admission and copied TRX denial with healthy re-admission | |
| id: product-admission | |
| if: ${{ success() }} | |
| env: | |
| KEYLOAD_NATIVE_PRODUCT_ADMISSION_REQUIRED: 'true' | |
| KEYLOAD_NATIVE_PRODUCT_DESCRIPTOR_PATH: ${{ github.workspace }}/TestResults/functional-coverage/rf3/functional-coverage.native-product-descriptor.v1.json | |
| run: node scripts/Features/TestInfrastructure/run-tests.mjs --KeyLoadTests:Suite=unit '--KeyLoadTests:Filter=/*/*/NativeCoverageMergeTests/*' --KeyLoadTests:ResultsDirectory=TestResults/native-product-admission --KeyLoadTests:ReportTrx=true | |
| - name: Verify original product-admission test and closed phase receipt | |
| if: ${{ !cancelled() && steps.product-admission.outcome != 'skipped' }} | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| Set-StrictMode -Version Latest | |
| $directory = Join-Path $env:GITHUB_WORKSPACE 'TestResults/native-product-admission' | |
| $reports = @(Get-ChildItem -LiteralPath $directory -Filter '*.trx' -File -Recurse) | |
| $receipts = @(Get-ChildItem -LiteralPath $directory -Filter 'native-product-admission-phase.v1.json' -File -Recurse) | |
| if ($reports.Count -ne 1 -or $receipts.Count -ne 1 -or $receipts[0].Length -le 0 -or $receipts[0].Length -gt 65536) { | |
| throw 'Exactly one original TRX and bounded product-admission receipt are required.' | |
| } | |
| [xml] $trx = Get-Content -LiteralPath $reports[0].FullName -Raw | |
| $counts = $trx.TestRun.ResultSummary.Counters | |
| if ([int] $counts.total -ne 1 -or [int] $counts.executed -ne 1 -or [int] $counts.passed -ne 1 -or [int] $counts.failed -ne 0) { | |
| throw 'The real product-admission whole operation must execute and pass.' | |
| } | |
| . ./scripts/Features/CodeQuality/functional-coverage.native-merge.inputs.ps1 | |
| $bytes = [IO.File]::ReadAllBytes($receipts[0].FullName) | |
| $document = [Text.Json.JsonDocument]::Parse([ReadOnlyMemory[byte]]::new($bytes)) | |
| try { Assert-FcNativeJsonUnique $document.RootElement } | |
| finally { $document.Dispose() } | |
| $phase = ConvertFrom-Json ([Text.Encoding]::UTF8.GetString($bytes)) -AsHashtable | |
| Assert-FcNativeExactKeys $phase @('schemaVersion','phase','descriptorSha256','healthyAdmissions','rejectedAdmissions','rejectedOutcome') | |
| $descriptor = Join-Path $env:GITHUB_WORKSPACE 'TestResults/functional-coverage/rf3/functional-coverage.native-product-descriptor.v1.json' | |
| foreach ($name in @('schemaVersion','healthyAdmissions','rejectedAdmissions')) { | |
| if ($phase[$name] -isnot [int] -and $phase[$name] -isnot [long]) { throw 'Invalid product phase integer.' } | |
| } | |
| if ($phase.schemaVersion -ne 1 -or $phase.phase -cne 'product-admission' -or | |
| $phase.descriptorSha256 -cne (Get-FileHash $descriptor -Algorithm SHA256).Hash.ToLowerInvariant() -or | |
| $phase.healthyAdmissions -ne 2 -or $phase.rejectedAdmissions -ne 1 -or | |
| $phase.rejectedOutcome -cne 'An original native test outcome report does not match the exact contributor inventory.') { | |
| throw 'The product-admission phase does not bind the original descriptor and complete flow.' | |
| } | |
| - name: Validate and merge native product coverage | |
| if: ${{ success() }} | |
| shell: pwsh | |
| run: | | |
| $root = $env:GITHUB_WORKSPACE | |
| $evidence = Join-Path $root 'TestResults/functional-coverage/rf3' | |
| $descriptorPath = Join-Path $evidence 'functional-coverage.native-product-descriptor.v1.json' | |
| $boundsPath = Join-Path $evidence 'functional-coverage.native-options.v1.json' | |
| $descriptor = Get-Content -LiteralPath $descriptorPath -Raw | ConvertFrom-Json | |
| $nativeOptions = Get-Content -LiteralPath $boundsPath -Raw | |
| & pwsh -NoLogo -NoProfile -File scripts/Features/CodeQuality/functional-coverage.native-merge.ps1 ` | |
| -Mode Product -Repository $root -EvidenceRoot $evidence -DescriptorPath $descriptorPath ` | |
| -ToolPackageRoot $descriptor.tool.packageRoot -ToolVersion $descriptor.tool.version ` | |
| -NativeOptionsJson $nativeOptions | |
| if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } | |
| - name: Clean up Docker registry | |
| if: ${{ always() && (steps.images.outcome == 'success' || steps.images.outcome == 'failure') }} | |
| run: node scripts/Features/BenchmarkComparisons/cleanup-images.mjs | |
| - name: Save three-node Docker image logs | |
| if: ${{ always() && (steps.images.outcome == 'success' || steps.images.outcome == 'failure') }} | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: docker-rf3-image-evidence | |
| path: ${{ runner.temp }}/keyload-images/** | |
| if-no-files-found: error | |
| - name: Save three-node database test results | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: docker-rf3-qualification | |
| path: | | |
| TestResults/** | |
| tests/KeyLoad.IntegrationTests/**/TestResults/** | |
| artifacts/qualification/** | |
| if-no-files-found: error | |
| - name: Save three-node build diagnostics | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: code-quality-docker-rf3 | |
| path: artifacts/code-quality/** | |
| if-no-files-found: error |