# Spec-Diff Gate - Contract Verification Workflow # Sprint: Testing Enhancement Advisory - Phase 1.1 # Verifies that OpenAPI specifications match code implementations name: spec-diff-gate on: pull_request: branches: [main, develop] paths: - 'src/**/WebService/**' - 'src/**/Endpoints/**' - 'src/**/Controllers/**' - 'docs/api/**' - 'docs/contracts/**' - 'docs/db/**' push: branches: [main] workflow_dispatch: concurrency: group: spec-diff-${{ github.ref }} cancel-in-progress: true jobs: # ========================================================================== # Contract Spec Diff Tests # ========================================================================== spec-diff: name: Contract Spec Diff runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Checkout uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: "10.0.100" - name: Restore dependencies run: dotnet restore src/__Tests/Architecture/StellaOps.Architecture.Contracts.Tests/StellaOps.Architecture.Contracts.Tests.csproj - name: Build spec-diff tests run: dotnet build src/__Tests/Architecture/StellaOps.Architecture.Contracts.Tests/StellaOps.Architecture.Contracts.Tests.csproj --configuration Release --no-restore - name: Run OpenAPI spec validation run: | dotnet test src/__Tests/Architecture/StellaOps.Architecture.Contracts.Tests \ --configuration Release \ --no-build \ --filter "Category=Architecture&Category=Contract" \ --logger "trx;LogFileName=spec-diff.trx" \ --results-directory ./TestResults - name: Generate spec-diff report if: always() run: | dotnet test src/__Tests/Architecture/StellaOps.Architecture.Contracts.Tests \ --configuration Release \ --no-build \ --filter "FullyQualifiedName~SpecDiff_GeneratesReport" \ --logger "console;verbosity=detailed" \ 2>&1 | tee ./TestResults/spec-diff-report.txt || true - name: Upload test results uses: actions/upload-artifact@v4 if: always() with: name: spec-diff-results path: TestResults/** - name: Publish test summary uses: dorny/test-reporter@v1 if: always() with: name: Spec Diff Test Results path: TestResults/**/*.trx reporter: dotnet-trx # ========================================================================== # Schema Compliance Tests # ========================================================================== schema-compliance: name: Schema Compliance runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: "10.0.100" - name: Restore dependencies run: dotnet restore src/__Tests/Architecture/StellaOps.Architecture.Contracts.Tests/StellaOps.Architecture.Contracts.Tests.csproj - name: Build schema tests run: dotnet build src/__Tests/Architecture/StellaOps.Architecture.Contracts.Tests/StellaOps.Architecture.Contracts.Tests.csproj --configuration Release --no-restore - name: Run schema compliance tests run: | dotnet test src/__Tests/Architecture/StellaOps.Architecture.Contracts.Tests \ --configuration Release \ --no-build \ --filter "FullyQualifiedName~SchemaCompliance" \ --logger "trx;LogFileName=schema-compliance.trx" \ --results-directory ./TestResults - name: Upload schema test results uses: actions/upload-artifact@v4 if: always() with: name: schema-compliance-results path: TestResults/** # ========================================================================== # API Governance Check (existing, enhanced) # ========================================================================== api-governance: name: API Governance runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install spectral run: npm install -g @stoplight/spectral-cli - name: Lint OpenAPI specs run: | find docs/api -name "*.yaml" -o -name "*.yml" | while read spec; do echo "Linting: $spec" spectral lint "$spec" --ruleset .spectral.yaml || true done - name: Check for breaking changes run: | if [ -f ".gitea/scripts/validate/api-compat-diff.mjs" ]; then node .gitea/scripts/validate/api-compat-diff.mjs --baseline docs/contracts/api-aggregate-*.yaml else echo "API compat diff script not found, skipping" fi # ========================================================================== # Combined Gate Status # ========================================================================== gate-status: name: Spec Diff Gate Status runs-on: ubuntu-latest needs: [spec-diff, schema-compliance, api-governance] if: always() steps: - name: Check gate status run: | if [ "${{ needs.spec-diff.result }}" == "failure" ]; then echo "::error::Spec diff tests failed - specs and code are out of sync" exit 1 fi if [ "${{ needs.schema-compliance.result }}" == "failure" ]; then echo "::error::Schema compliance tests failed - migrations may not comply with specifications" exit 1 fi if [ "${{ needs.api-governance.result }}" == "failure" ]; then echo "::warning::API governance checks had issues - review API lint results" fi echo "All spec-diff checks passed!"