feat: policy intelligence pre-check for EHR demo #168
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: | |
| pull_request: | |
| branches: [main] | |
| push: | |
| branches: [main] | |
| env: | |
| DOTNET_VERSION: '10.0.x' | |
| DOTNET_QUALITY: 'preview' | |
| NODE_VERSION: '20' | |
| PYTHON_VERSION: '3.11' | |
| COVERAGE_THRESHOLD: 59 | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| jobs: | |
| changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| dashboard: ${{ steps.filter.outputs.dashboard }} | |
| gateway: ${{ steps.filter.outputs.gateway }} | |
| intelligence: ${{ steps.filter.outputs.intelligence }} | |
| orchestration: ${{ steps.filter.outputs.orchestration }} | |
| shared: ${{ steps.filter.outputs.shared }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dorny/paths-filter@v3 | |
| id: filter | |
| with: | |
| filters: | | |
| dashboard: | |
| - 'apps/dashboard/**' | |
| gateway: | |
| - 'apps/gateway/**' | |
| intelligence: | |
| - 'apps/intelligence/**' | |
| orchestration: | |
| - 'orchestration/**' | |
| shared: | |
| - 'shared/**' | |
| - 'package.json' | |
| - 'orval.config.ts' | |
| schema-check: | |
| name: Schema Sync Check | |
| needs: changes | |
| if: needs.changes.outputs.gateway == 'true' || needs.changes.outputs.intelligence == 'true' || needs.changes.outputs.shared == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| dotnet-quality: ${{ env.DOTNET_QUALITY }} | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| - uses: astral-sh/setup-uv@v5 | |
| with: | |
| version: "latest" | |
| - name: Restore .NET tools | |
| run: dotnet tool restore | |
| - name: Install npm dependencies | |
| run: npm install --legacy-peer-deps | |
| - name: Install Python dev dependencies | |
| working-directory: apps/intelligence | |
| run: uv sync --all-extras | |
| - name: Sync schemas | |
| run: npm run sync:schemas | |
| - name: Check for schema drift | |
| run: | | |
| # Check all paths that should be in sync with source models | |
| DRIFT_PATHS=( | |
| "shared/schemas/" | |
| "apps/gateway/openapi.json" | |
| "apps/intelligence/openapi.json" | |
| "apps/intelligence/src/models/generated/" | |
| "apps/gateway/Gateway.API/Models/Generated/" | |
| "shared/types/src/generated/" | |
| "shared/validation/src/generated/" | |
| "apps/dashboard/src/api/generated/" | |
| ) | |
| # Filter to only existing paths (some may not exist yet) | |
| EXISTING_PATHS=() | |
| for path in "${DRIFT_PATHS[@]}"; do | |
| if [[ -e "$path" ]]; then | |
| EXISTING_PATHS+=("$path") | |
| fi | |
| done | |
| if [[ ${#EXISTING_PATHS[@]} -gt 0 ]] && [[ -n $(git status --porcelain "${EXISTING_PATHS[@]}") ]]; then | |
| echo "::error::Schema drift detected! Run 'npm run sync:schemas' and commit the changes." | |
| echo "" | |
| echo "Changed files:" | |
| git status --porcelain "${EXISTING_PATHS[@]}" | |
| echo "" | |
| echo "Diff summary:" | |
| git diff --stat "${EXISTING_PATHS[@]}" | |
| exit 1 | |
| fi | |
| echo "No schema drift detected" | |
| gateway-build: | |
| name: Gateway Build & Test | |
| needs: changes | |
| if: needs.changes.outputs.gateway == 'true' || needs.changes.outputs.orchestration == 'true' || needs.changes.outputs.shared == 'true' | |
| runs-on: ubuntu-latest | |
| env: | |
| # Enable new Microsoft Testing Platform integration for .NET 10+ / TUnit | |
| DOTNET_CLI_TESTINGPLATFORM_ENABLE: '1' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| dotnet-quality: ${{ env.DOTNET_QUALITY }} | |
| - name: Restore | |
| run: dotnet restore apps/gateway/Gateway.API.Tests/Gateway.API.Tests.csproj | |
| - name: Build | |
| run: dotnet build apps/gateway/Gateway.API.Tests/Gateway.API.Tests.csproj --no-restore --configuration Release | |
| - name: Test with coverage | |
| run: | | |
| # TUnit uses Microsoft.Testing.Platform - run tests with native coverage | |
| mkdir -p ./apps/gateway/coverage | |
| dotnet run --no-build --project apps/gateway/Gateway.API.Tests/Gateway.API.Tests.csproj \ | |
| --configuration Release \ | |
| -- \ | |
| --coverage \ | |
| --coverage-output-format cobertura \ | |
| --coverage-output "${GITHUB_WORKSPACE}/apps/gateway/coverage/coverage.cobertura.xml" \ | |
| --coverage-settings "${GITHUB_WORKSPACE}/apps/gateway/coverage.settings.xml" | |
| - name: Check Coverage Threshold | |
| if: success() | |
| run: | | |
| if [ ! -f ./apps/gateway/coverage/coverage.cobertura.xml ]; then | |
| echo "::error::Coverage file not found" | |
| exit 1 | |
| fi | |
| COVERAGE=$(grep -oP 'line-rate="\K[0-9.]+' ./apps/gateway/coverage/coverage.cobertura.xml | head -1) | |
| COVERAGE_PCT=$(echo "$COVERAGE * 100" | bc | cut -d. -f1) | |
| echo "Coverage: ${COVERAGE_PCT}%" | |
| if [ "$COVERAGE_PCT" -lt "${{ env.COVERAGE_THRESHOLD }}" ]; then | |
| echo "::error::Coverage ${COVERAGE_PCT}% is below ${{ env.COVERAGE_THRESHOLD }}% threshold" | |
| exit 1 | |
| fi | |
| - name: Upload coverage | |
| if: success() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: gateway-coverage | |
| path: ./apps/gateway/coverage/coverage.cobertura.xml | |
| retention-days: 7 | |
| if-no-files-found: warn | |
| intelligence-build: | |
| name: Intelligence Build & Test | |
| needs: changes | |
| if: needs.changes.outputs.intelligence == 'true' || needs.changes.outputs.shared == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: astral-sh/setup-uv@v5 | |
| with: | |
| version: "latest" | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install dependencies | |
| working-directory: apps/intelligence | |
| run: uv sync --all-extras | |
| - name: Lint with ruff | |
| working-directory: apps/intelligence | |
| run: uv run ruff check . | |
| - name: Type check with mypy | |
| working-directory: apps/intelligence | |
| run: uv run mypy src/ | |
| - name: Test with coverage | |
| working-directory: apps/intelligence | |
| run: | | |
| uv run pytest src/tests/ \ | |
| --cov=src \ | |
| --cov-report=xml:coverage.xml \ | |
| --cov-fail-under=${{ env.COVERAGE_THRESHOLD }} | |
| - name: Upload coverage | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: intelligence-coverage | |
| path: apps/intelligence/coverage.xml | |
| retention-days: 7 | |
| if-no-files-found: warn | |
| dashboard-build: | |
| name: Dashboard Build & Test | |
| needs: changes | |
| if: needs.changes.outputs.dashboard == 'true' || needs.changes.outputs.shared == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Install dependencies (fresh install for native bindings) | |
| run: | | |
| rm -f package-lock.json | |
| npm install --legacy-peer-deps | |
| - name: Build shared packages | |
| run: | | |
| npm run build --workspace=shared/types --if-present | |
| npm run build --workspace=shared/validation --if-present | |
| - name: Lint | |
| run: npm run lint --workspace=apps/dashboard | |
| - name: Type check | |
| run: npm run typecheck --workspace=apps/dashboard | |
| - name: Test | |
| run: npm run test:run --workspace=apps/dashboard | |
| - name: Build | |
| run: npm run build --workspace=apps/dashboard |