Repository navigation
Checkpoint functional query flows and current implementation stages #215
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: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| workflow_dispatch: | |
| workflow_run: | |
| workflows: [Benchmarks] | |
| types: [completed] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: keyload-ci-${{ github.event_name == 'workflow_run' && 'site' || github.event_name == 'pull_request' && github.ref || github.run_id }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| repository-checks: | |
| if: github.event_name != 'workflow_run' | |
| 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: | |
| if: github.event_name != 'workflow_run' | |
| name: Test code analyzers | |
| 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: Run analyzer tests | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=analyzers --KeyLoadTests:ReportTrx=true | |
| - 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: | |
| if: github.event_name != 'workflow_run' | |
| name: Build and test KeyLoad | |
| 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: 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: 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: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=analyzers --KeyLoadTests:ReportTrx=true | |
| - name: Test prompt termination on Aspire resource failures | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=comparison '--KeyLoadTests:Filter=/*/*/AspireFailure*/*' --KeyLoadTests:ResultsDirectory=TestResults/aspire-failure --KeyLoadTests:ReportTrx=true | |
| - name: Test Aspire recovery prerequisite ownership | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=comparison '--KeyLoadTests:Filter=/*/*/PriorProbePrerequisiteTests/*' --KeyLoadTests:ResultsDirectory=TestResults/recovery-prerequisites --KeyLoadTests:ReportTrx=true | |
| - name: Test live benchmark progress capture | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=comparison '--KeyLoadTests:Filter=/*/*/ComparisonProgress*/*' --KeyLoadTests:ResultsDirectory=TestResults/live-benchmark-progress --KeyLoadTests:ReportTrx=true | |
| - name: Test live benchmark process entry | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=unit '--KeyLoadTests:Filter=/*/*/NativeBenchmarkProgressEntryTests/*' --KeyLoadTests:ResultsDirectory=TestResults/live-benchmark-entry --KeyLoadTests:ReportTrx=true | |
| - name: Test benchmark phase and attempt counters | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=unit '--KeyLoadTests:Filter=/*/*/ComparisonLiveProgress*/*' --KeyLoadTests:ResultsDirectory=TestResults/live-benchmark-counters --KeyLoadTests:ReportTrx=true | |
| - name: Test Aspire workflow entry contracts | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=unit '--KeyLoadTests:Filter=/*/*/WorkflowLayoutAspireEntryTests/*' --KeyLoadTests:ResultsDirectory=TestResults/live-benchmark-workflow --KeyLoadTests:ReportTrx=true | |
| - name: Run unit tests | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=unit --KeyLoadTests:ReportTrx=true | |
| - name: Run unit tests without CPU intrinsics | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' }} | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=unit-scalar --KeyLoadTests:ReportTrx=true | |
| - name: Test recovery after process crashes | |
| if: ${{ !cancelled() && steps.build.outcome == 'success' }} | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=recovery --KeyLoadTests:ReportTrx=true | |
| - 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 | |
| docker-rf3: | |
| if: github.event_name != 'workflow_run' | |
| name: Test three-node database | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| 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 and benchmark Docker images | |
| id: images | |
| run: node scripts/Features/BenchmarkComparisons/prepare-images.mjs | |
| - name: Build the genuine previous KeyLoad server image | |
| id: prior-images | |
| run: node scripts/Features/StorageRecovery/prepare-native5-server-image.mjs | |
| - name: Build the genuine epoch-six RPC1 KeyLoad server image | |
| id: rpc1-images | |
| run: node scripts/Features/ClusterRouting/prepare-rpc1-server-image.mjs | |
| - name: Build the genuine epoch-seven interface-three KeyLoad server image | |
| id: interface3-images | |
| run: node scripts/Features/ClusterRouting/prepare-interface3-server-image.mjs | |
| - name: Configure Docker image references | |
| shell: bash | |
| env: | |
| KEYLOAD_SERVER_IMAGE: ${{ steps.images.outputs.server-image }} | |
| KEYLOAD_RUNNER_IMAGE: ${{ steps.images.outputs.load-generator-image }} | |
| KEYLOAD_PRIOR_SERVER_IMAGE: ${{ steps.prior-images.outputs.prior-server-image }} | |
| KEYLOAD_PRIOR_IMAGE_RECEIPT: ${{ steps.prior-images.outputs.prior-image-receipt }} | |
| KEYLOAD_PRIOR_SERVER_MANIFEST: ${{ steps.prior-images.outputs.prior-server-manifest }} | |
| KEYLOAD_RPC1_SERVER_IMAGE: ${{ steps.rpc1-images.outputs.KEYLOAD_RPC1_SERVER_IMAGE }} | |
| KEYLOAD_RPC1_IMAGE_RECEIPT: ${{ steps.rpc1-images.outputs.KEYLOAD_RPC1_IMAGE_RECEIPT }} | |
| KEYLOAD_RPC1_SERVER_MANIFEST: ${{ steps.rpc1-images.outputs.KEYLOAD_RPC1_SERVER_MANIFEST }} | |
| KEYLOAD_INTERFACE3_SERVER_IMAGE: ${{ steps.interface3-images.outputs.KEYLOAD_INTERFACE3_SERVER_IMAGE }} | |
| KEYLOAD_INTERFACE3_IMAGE_RECEIPT: ${{ steps.interface3-images.outputs.KEYLOAD_INTERFACE3_IMAGE_RECEIPT }} | |
| KEYLOAD_INTERFACE3_SERVER_MANIFEST: ${{ steps.interface3-images.outputs.KEYLOAD_INTERFACE3_SERVER_MANIFEST }} | |
| KEYLOAD_INTERFACE3_SERVER_INVENTORY: ${{ steps.interface3-images.outputs.KEYLOAD_INTERFACE3_SERVER_INVENTORY }} | |
| KEYLOAD_INTERFACE3_SERVER_ARCHIVE: ${{ steps.interface3-images.outputs.KEYLOAD_INTERFACE3_SERVER_ARCHIVE }} | |
| run: | | |
| test -n "$KEYLOAD_SERVER_IMAGE" && test -n "$KEYLOAD_RUNNER_IMAGE" | |
| test -n "$KEYLOAD_PRIOR_SERVER_IMAGE" && test -n "$KEYLOAD_PRIOR_IMAGE_RECEIPT" && test -n "$KEYLOAD_PRIOR_SERVER_MANIFEST" | |
| test -n "$KEYLOAD_RPC1_SERVER_IMAGE" && test -n "$KEYLOAD_RPC1_IMAGE_RECEIPT" && test -n "$KEYLOAD_RPC1_SERVER_MANIFEST" | |
| test -n "$KEYLOAD_INTERFACE3_SERVER_IMAGE" && test -n "$KEYLOAD_INTERFACE3_IMAGE_RECEIPT" && test -n "$KEYLOAD_INTERFACE3_SERVER_MANIFEST" | |
| test -n "$KEYLOAD_INTERFACE3_SERVER_INVENTORY" && test -n "$KEYLOAD_INTERFACE3_SERVER_ARCHIVE" | |
| printf 'KeyLoad__ContainerImages__Server=%s\nBenchmarks__ContainerImages__LoadGenerator=%s\nKEYLOAD_IMAGE_RECEIPT=%s\n' "$KEYLOAD_SERVER_IMAGE" "$KEYLOAD_RUNNER_IMAGE" "$RUNNER_TEMP/keyload-images/image-receipt.json" >> "$GITHUB_ENV" | |
| printf 'KEYLOAD_PRIOR_SERVER_IMAGE=%s\nKEYLOAD_PRIOR_IMAGE_RECEIPT=%s\nKEYLOAD_PRIOR_SERVER_MANIFEST=%s\n' "$KEYLOAD_PRIOR_SERVER_IMAGE" "$KEYLOAD_PRIOR_IMAGE_RECEIPT" "$KEYLOAD_PRIOR_SERVER_MANIFEST" >> "$GITHUB_ENV" | |
| printf 'KEYLOAD_RPC1_SERVER_IMAGE=%s\nKEYLOAD_RPC1_IMAGE_RECEIPT=%s\nKEYLOAD_RPC1_SERVER_MANIFEST=%s\n' "$KEYLOAD_RPC1_SERVER_IMAGE" "$KEYLOAD_RPC1_IMAGE_RECEIPT" "$KEYLOAD_RPC1_SERVER_MANIFEST" >> "$GITHUB_ENV" | |
| printf 'KEYLOAD_INTERFACE3_SERVER_IMAGE=%s\nKEYLOAD_INTERFACE3_IMAGE_RECEIPT=%s\nKEYLOAD_INTERFACE3_SERVER_MANIFEST=%s\nKEYLOAD_INTERFACE3_SERVER_INVENTORY=%s\nKEYLOAD_INTERFACE3_SERVER_ARCHIVE=%s\n' "$KEYLOAD_INTERFACE3_SERVER_IMAGE" "$KEYLOAD_INTERFACE3_IMAGE_RECEIPT" "$KEYLOAD_INTERFACE3_SERVER_MANIFEST" "$KEYLOAD_INTERFACE3_SERVER_INVENTORY" "$KEYLOAD_INTERFACE3_SERVER_ARCHIVE" >> "$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 three-node database tests | |
| run: dotnet build tests/KeyLoad.IntegrationTests --no-restore --configuration Release | |
| - name: Test three-node database with .NET and MCP clients | |
| run: dotnet run --project src/KeyLoad.AppHost --no-build --no-restore --configuration Release -- --KeyLoadTests:Suite=rf3 --KeyLoadTests:ReportTrx=true | |
| - 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 | |
| qualify: | |
| name: Check website | |
| concurrency: | |
| group: keyload-site-qualification | |
| cancel-in-progress: false | |
| if: >- | |
| github.repository == 'managedcode/KeyLoad' && github.event.repository.id == 477801965 && | |
| ((github.ref == 'refs/heads/main' && | |
| (github.event_name == 'push' || github.event_name == 'workflow_dispatch')) || | |
| (github.event_name == 'workflow_run' && | |
| github.event.workflow_run.head_repository.id == 477801965 && | |
| github.event.workflow_run.head_branch == 'main' && | |
| github.event.workflow_run.name == 'Benchmarks' && | |
| github.event.workflow_run.path == '.github/workflows/benchmarks.yml' && | |
| github.event.workflow_run.status == 'completed' && | |
| (github.event.workflow_run.event == 'push' || github.event.workflow_run.event == 'workflow_dispatch') && | |
| (github.event.workflow_run.conclusion == 'success' || github.event.workflow_run.conclusion == 'failure'))) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 180 | |
| permissions: {contents: read, actions: read} | |
| outputs: | |
| mode: ${{ steps.qualification.outputs.mode }} | |
| site_revision: ${{ steps.qualification.outputs.site_revision }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ github.workflow_sha }} | |
| path: control | |
| persist-credentials: false | |
| - name: Run website checks | |
| id: qualification | |
| uses: ./control/.github/workflows/Features/BenchmarkComparisons/QualifySite | |
| deploy: | |
| name: Publish website | |
| concurrency: | |
| group: keyload-site-deployment | |
| cancel-in-progress: false | |
| needs: qualify | |
| if: ${{ always() && !cancelled() && needs.qualify.result == 'success' && needs.qualify.outputs.mode == 'publish' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 90 | |
| permissions: {contents: read, actions: read, pages: write, id-token: write} | |
| environment: {name: github-pages, url: '${{ steps.publication.outputs.page_url }}'} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| QUALIFIED_REVISION: ${{ needs.qualify.outputs.site_revision }} | |
| CONTROL_REVISION: ${{ github.workflow_sha }} | |
| steps: | |
| - name: Download source code | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ github.workflow_sha }} | |
| path: control | |
| persist-credentials: false | |
| - name: Publish website | |
| id: publication | |
| uses: ./control/.github/workflows/Features/BenchmarkComparisons/DeploySite |