Bump coverlet.collector from 6.0.4 to 8.0.0 #139
Workflow file for this run
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
| # Sequential PR validation workflow with coverage gating | |
| # Stage 1: Linux tests with 90% coverage requirement | |
| # Stage 2: Windows and macOS tests (only if Linux passes) | |
| # Stage 3: .NET Framework 4.x tests on Windows (only if Stage 2 passes) | |
| name: PR Checks v2 (Gated) | |
| permissions: | |
| contents: read | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| jobs: | |
| # ============================================================================ | |
| # STAGE 1: Linux - .NET Core/5+ Tests with Coverage Gate | |
| # ============================================================================ | |
| test-linux-core: | |
| name: "Stage 1: Linux Tests (.NET 5.0-10.0) + Coverage Gate" | |
| runs-on: ubuntu-latest | |
| if: github.repository != 'Chris-Wolfgang/repo-template' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| # Fix for .NET 5.0 on Ubuntu 22.04+ - install libssl1.1 | |
| - name: Install OpenSSL 1.1 for .NET 5.0 | |
| run: | | |
| wget https://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb | |
| sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: | | |
| 5.0.x | |
| 6.0.x | |
| 7.0.x | |
| 8.0.x | |
| 9.0.x | |
| 10.0.x | |
| - name: Check Code Formatting | |
| run: | | |
| # dotnet format is built into .NET 6+ SDK (no separate installation needed) | |
| # Find solution file | |
| solution=$(find . -maxdepth 2 \( -name "*.sln" -o -name "*.slnx" \) | head -n 1) | |
| if [ -n "$solution" ]; then | |
| echo "Checking formatting for: $solution" | |
| dotnet format "$solution" --verify-no-changes --verbosity diagnostic | |
| else | |
| echo "No solution file found, checking entire workspace" | |
| dotnet format --verify-no-changes --verbosity diagnostic | |
| fi | |
| - name: Restore and build (exclude .NET Framework 4.x projects) | |
| run: | | |
| echo "Finding all projects in solution..." | |
| # Get list of all projects from solution file | |
| if [ -f "*.sln" ]; then | |
| sln_file=$(ls *.sln | head -n 1) | |
| echo "Using solution file: $sln_file" | |
| fi | |
| # Find all .csproj, .vbproj, and .fsproj files | |
| # Exclude those with 'dotnet4' or 'DotNet4' in the path (case-insensitive) | |
| projects=$(find . -type f \( -name "*.csproj" -o -name "*.vbproj" -o -name "*.fsproj" \) | grep -iv "dotnet4") | |
| if [ -z "$projects" ]; then | |
| echo "No projects found!" | |
| exit 1 | |
| fi | |
| echo "==========================================" | |
| echo "Projects to build (excluding .NET Framework 4.x):" | |
| echo "==========================================" | |
| echo "$projects" | |
| echo "" | |
| # Restore each project | |
| echo "Restoring projects..." | |
| for proj in $projects; do | |
| echo "Restoring: $proj" | |
| dotnet restore "$proj" || exit 1 | |
| done | |
| echo "" | |
| echo "Building projects..." | |
| # Build each project | |
| for proj in $projects; do | |
| echo "Building: $proj" | |
| dotnet build "$proj" --no-restore --configuration Release || exit 1 | |
| done | |
| echo "" | |
| echo "✅ All compatible projects built successfully" | |
| - name: Run tests with coverage (.NET Core 5.0 - 10.0) | |
| run: | | |
| # Find all test projects | |
| test_projects=$(find ./tests -type f -name "*.csproj") | |
| if [ -z "$test_projects" ]; then | |
| echo "❌ No test projects found in ./tests directory!" | |
| exit 1 | |
| fi | |
| echo "==========================================" | |
| echo "Found test projects:" | |
| echo "==========================================" | |
| echo "$test_projects" | |
| echo "" | |
| # Test each framework individually to ensure all are tested | |
| frameworks=(net5.0 net6.0 net7.0 net8.0 net9.0 net10.0) | |
| for test_proj in $test_projects; do | |
| echo "==========================================" | |
| echo "Testing project: $test_proj" | |
| echo "==========================================" | |
| for fw in "${frameworks[@]}"; do | |
| echo "Testing framework: $fw" | |
| dotnet test "$test_proj" \ | |
| --configuration Release \ | |
| --framework "$fw" \ | |
| --collect:"XPlat Code Coverage" \ | |
| --results-directory "./TestResults" \ | |
| --logger "console;verbosity=minimal" || exit 1 | |
| done | |
| echo "" | |
| done | |
| - name: Install ReportGenerator | |
| run: dotnet tool install -g dotnet-reportgenerator-globaltool | |
| - name: Generate coverage report | |
| run: | | |
| reportgenerator \ | |
| -reports:"TestResults/**/coverage.cobertura.xml" \ | |
| -targetdir:"CoverageReport" \ | |
| -reporttypes:"Html;TextSummary;MarkdownSummaryGithub;CsvSummary" | |
| - name: Enforce 90% coverage threshold | |
| run: | | |
| if [ ! -f CoverageReport/Summary.txt ]; then | |
| echo "❌ Coverage report not generated!" | |
| exit 1 | |
| fi | |
| echo "Coverage Summary:" | |
| cat CoverageReport/Summary.txt | |
| echo "" | |
| # Validate that the report contains expected content | |
| if ! grep -q "Summary" CoverageReport/Summary.txt; then | |
| echo "❌ Coverage report format is invalid!" | |
| exit 1 | |
| fi | |
| failed_projects="" | |
| threshold=90 | |
| while read -r line; do | |
| # Match lines with module names and percentages | |
| if echo "$line" | grep -qE '^[^ ].*[0-9]+%$' && ! echo "$line" | grep -q '^Summary'; then | |
| module=$(echo "$line" | awk '{print $1}') | |
| percent=$(echo "$line" | awk '{print $NF}' | tr -d '%') | |
| echo "Checking module: '$module' - Coverage: ${percent}%" | |
| if [ "$percent" -lt "$threshold" ]; then | |
| echo " ❌ FAIL: Below ${threshold}% threshold" | |
| failed_projects="$failed_projects $module (${percent}%)" | |
| else | |
| echo " ✅ PASS: Meets ${threshold}% threshold" | |
| fi | |
| fi | |
| done < CoverageReport/Summary.txt | |
| if [ -n "$failed_projects" ]; then | |
| echo "" | |
| echo "==========================================" | |
| echo "❌ COVERAGE GATE FAILED" | |
| echo "==========================================" | |
| echo "Projects below ${threshold}% coverage: $failed_projects" | |
| echo "" | |
| echo "Stage 1 failed. Windows, macOS, and .NET Framework tests will NOT run." | |
| exit 1 | |
| else | |
| echo "" | |
| echo "==========================================" | |
| echo "✅ COVERAGE GATE PASSED" | |
| echo "==========================================" | |
| echo "All projects meet ${threshold}% coverage threshold." | |
| echo "Proceeding to Stage 2 (Windows and macOS tests)." | |
| fi | |
| - name: Upload Linux coverage results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-linux | |
| path: | | |
| TestResults/ | |
| CoverageReport/ | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: build-output | |
| path: | | |
| src/**/bin/Release | |
| tests/**/bin/Release | |
| # ============================================================================ | |
| # STAGE 2: Windows & macOS - .NET Core/5+ Tests (Gated by Stage 1) | |
| # ============================================================================ | |
| test-windows-core: | |
| name: "Stage 2a: Windows Tests (.NET 5.0-10.0)" | |
| runs-on: windows-latest | |
| needs: test-linux-core | |
| if: github.repository != 'Chris-Wolfgang/repo-template' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: | | |
| 5.0.x | |
| 6.0.x | |
| 7.0.x | |
| 8.0.x | |
| 9.0.x | |
| 10.0.x | |
| - name: Restore dependencies | |
| run: dotnet restore | |
| - name: Build solution | |
| run: dotnet build --no-restore --configuration Release | |
| - name: Run tests (.NET Core 5.0 - 10.0) | |
| shell: pwsh | |
| run: | | |
| $testProjects = Get-ChildItem -Path './tests' -Recurse -Filter '*.csproj' | |
| if ($testProjects.Count -eq 0) { | |
| Write-Error "❌ No test projects found in ./tests directory!" | |
| exit 1 | |
| } | |
| Write-Host "==========================================" -ForegroundColor Cyan | |
| Write-Host "Found test projects:" -ForegroundColor Cyan | |
| Write-Host "==========================================" -ForegroundColor Cyan | |
| $testProjects | ForEach-Object { Write-Host $_.FullName -ForegroundColor White } | |
| Write-Host "" | |
| $frameworks = @('net5.0', 'net6.0', 'net7.0', 'net8.0', 'net9.0', 'net10.0') | |
| foreach ($testProj in $testProjects) { | |
| Write-Host "==========================================" -ForegroundColor Cyan | |
| Write-Host "Testing project: $($testProj.FullName)" -ForegroundColor Cyan | |
| Write-Host "==========================================" -ForegroundColor Cyan | |
| foreach ($fw in $frameworks) { | |
| Write-Host "Testing framework: $fw" -ForegroundColor Yellow | |
| dotnet test $testProj.FullName ` | |
| --configuration Release ` | |
| --framework $fw ` | |
| --logger "console;verbosity=normal" | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Error "Tests failed for $fw in $($testProj.Name)" | |
| exit 1 | |
| } | |
| } | |
| Write-Host "" | |
| } | |
| test-macos-core: | |
| name: "Stage 2b: macOS Tests (.NET 6.0-10.0)" | |
| runs-on: macos-latest | |
| needs: test-linux-core | |
| if: github.repository != 'Chris-Wolfgang/repo-template' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: | | |
| 6.0.x | |
| 7.0.x | |
| 8.0.x | |
| 9.0.x | |
| 10.0.x | |
| - name: Restore and build (exclude .NET Framework 4.x projects) | |
| run: | | |
| echo "Finding all projects in solution..." | |
| # Find all .csproj, .vbproj, and .fsproj files | |
| # Exclude those with 'dotnet4' or 'DotNet4' in the path (case-insensitive) | |
| projects=$(find . -type f \( -name "*.csproj" -o -name "*.vbproj" -o -name "*.fsproj" \) | grep -iv "dotnet4") | |
| if [ -z "$projects" ]; then | |
| echo "No projects found!" | |
| exit 1 | |
| fi | |
| echo "==========================================" | |
| echo "Projects to build (excluding .NET Framework 4.x):" | |
| echo "==========================================" | |
| echo "$projects" | |
| echo "" | |
| # Restore each project | |
| echo "Restoring projects..." | |
| for proj in $projects; do | |
| echo "Restoring: $proj" | |
| dotnet restore "$proj" || exit 1 | |
| done | |
| echo "" | |
| echo "Building projects..." | |
| # Build each project | |
| for proj in $projects; do | |
| echo "Building: $proj" | |
| dotnet build "$proj" --no-restore --configuration Release || exit 1 | |
| done | |
| echo "" | |
| echo "✅ All compatible projects built successfully" | |
| - name: Run tests (.NET 6.0 - 10.0 only - ARM64 compatible) | |
| run: | | |
| # Find all test projects | |
| test_projects=$(find ./tests -type f -name "*.csproj") | |
| if [ -z "$test_projects" ]; then | |
| echo "❌ No test projects found in ./tests directory!" | |
| exit 1 | |
| fi | |
| echo "==========================================" | |
| echo "Found test projects:" | |
| echo "==========================================" | |
| echo "$test_projects" | |
| echo "" | |
| # Skip .NET Core 5.0 and .NET 5.0 - no ARM64 support on macOS | |
| frameworks=(net6.0 net7.0 net8.0 net9.0 net10.0) | |
| for test_proj in $test_projects; do | |
| echo "==========================================" | |
| echo "Testing project: $test_proj" | |
| echo "==========================================" | |
| for fw in "${frameworks[@]}"; do | |
| echo "Testing framework: $fw" | |
| dotnet test "$test_proj" \ | |
| --configuration Release \ | |
| --framework "$fw" \ | |
| --logger "console;verbosity=normal" || exit 1 | |
| done | |
| echo "" | |
| done | |
| - name: Display macOS architecture info | |
| if: always() | |
| run: | | |
| echo "" | |
| echo "==========================================" | |
| echo "ℹ️ macOS Testing Notes" | |
| echo "==========================================" | |
| echo "Architecture: $(uname -m)" | |
| echo "" | |
| echo "Skipped frameworks (no ARM64 support):" | |
| echo " - .NET 5.0 ❌" | |
| echo "" | |
| echo "Tested frameworks (ARM64 compatible):" | |
| echo " - .NET 6.0 ✅" | |
| echo " - .NET 7.0 ✅" | |
| echo " - .NET 8.0 ✅" | |
| echo " - .NET 9.0 ✅" | |
| echo " - .NET 10.0 ✅" | |
| echo "" | |
| echo ".NET Core 5.0 are tested on Linux and Windows" | |
| # ============================================================================ | |
| # STAGE 3: Windows - .NET Framework 4.x Tests (Gated by Stage 2) | |
| # ============================================================================ | |
| test-windows-framework: | |
| name: "Stage 3: Windows .NET Framework Tests (4.6.2-4.8.1)" | |
| runs-on: windows-latest | |
| needs: [test-windows-core, test-macos-core] | |
| if: github.repository != 'Chris-Wolfgang/repo-template' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: | | |
| 8.0.x | |
| - name: Restore dependencies | |
| run: dotnet restore | |
| - name: Build solution | |
| run: dotnet build --no-restore --configuration Release | |
| - name: Run .NET Framework tests (4.6.2 - 4.8.1) | |
| shell: pwsh | |
| run: | | |
| $testProjects = Get-ChildItem -Path './tests' -Recurse -Filter '*.csproj' | |
| if ($testProjects.Count -eq 0) { | |
| Write-Error "❌ No test projects found in ./tests directory!" | |
| exit 1 | |
| } | |
| Write-Host "==========================================" -ForegroundColor Cyan | |
| Write-Host "Found test projects:" -ForegroundColor Cyan | |
| Write-Host "==========================================" -ForegroundColor Cyan | |
| $testProjects | ForEach-Object { Write-Host $_.FullName -ForegroundColor White } | |
| Write-Host "" | |
| $frameworks = @('net462', 'net472', 'net48', 'net481') | |
| foreach ($testProj in $testProjects) { | |
| Write-Host "==========================================" -ForegroundColor Cyan | |
| Write-Host "Testing project: $($testProj.FullName)" -ForegroundColor Cyan | |
| Write-Host "==========================================" -ForegroundColor Cyan | |
| foreach ($fw in $frameworks) { | |
| Write-Host "Testing framework: $fw" -ForegroundColor Yellow | |
| dotnet test $testProj.FullName ` | |
| --configuration Release ` | |
| --framework $fw ` | |
| --logger "console;verbosity=normal" | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Error "Tests failed for $fw in $($testProj.Name)" | |
| exit 1 | |
| } | |
| } | |
| Write-Host "" | |
| } | |
| Write-Host "" | |
| Write-Host "==========================================" -ForegroundColor Green | |
| Write-Host "✅ ALL STAGES PASSED" -ForegroundColor Green | |
| Write-Host "==========================================" -ForegroundColor Green | |
| Write-Host "Stage 1: Linux tests + 90% coverage ✅" -ForegroundColor Green | |
| Write-Host "Stage 2: Windows & macOS tests ✅" -ForegroundColor Green | |
| Write-Host "Stage 3: .NET Framework 4.x tests ✅" -ForegroundColor Green | |
| Write-Host "" | |
| Write-Host "PR is ready to merge! 🎉" -ForegroundColor Green | |
| # ============================================================================ | |
| # Security Scan (Runs in parallel with tests) | |
| # ============================================================================ | |
| security-scan: | |
| name: "Security Scan (DevSkim)" | |
| runs-on: ubuntu-latest | |
| if: github.repository != 'Chris-Wolfgang/repo-template' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install DevSkim CLI | |
| run: dotnet tool install --global Microsoft.CST.DevSkim.CLI | |
| - name: Run DevSkim security scan | |
| run: | | |
| devskim analyze \ | |
| --source-code . \ | |
| --file-format text \ | |
| --output-file devskim-results.txt \ | |
| -E \ | |
| --ignore-rule-ids DS176209 \ | |
| --ignore-globs "**/api/**,**/CoverageReport/**,**/TestResults/**" | |
| - name: Display security scan results | |
| if: always() | |
| run: | | |
| if [ -f devskim-results.txt ]; then | |
| echo "==========================================" | |
| echo "DevSkim Security Scan Results" | |
| echo "==========================================" | |
| cat devskim-results.txt | |
| echo "" | |
| if grep -qi "error\|critical\|high" devskim-results.txt; then | |
| echo "⚠️ Security issues detected - review required" | |
| else | |
| echo "✅ No critical security issues found" | |
| fi | |
| else | |
| echo "✅ No security issues found" | |
| fi | |
| - name: Upload security scan results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: devskim-results | |
| path: devskim-results.txt | |
| if-no-files-found: warn | |
| # ============================================================================ | |
| # CodeQL Analysis (Runs in parallel with tests) | |
| # ============================================================================ | |
| codeql-analysis: | |
| name: "CodeQL" | |
| runs-on: ubuntu-latest | |
| if: github.repository != 'Chris-Wolfgang/repo-template' | |
| permissions: | |
| actions: read | |
| contents: read | |
| security-events: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Initialize CodeQL | |
| uses: github/codeql-action/init@v3 | |
| with: | |
| languages: csharp | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: | | |
| 8.0.x | |
| - name: Build for CodeQL Analysis | |
| run: | | |
| echo "Building solution for CodeQL analysis..." | |
| # Find solution file (.sln or .slnx) | |
| solution=$(find . -maxdepth 2 \( -name "*.sln" -o -name "*.slnx" \) | head -n 1) | |
| if [ -n "$solution" ]; then | |
| echo "Found solution: $solution" | |
| dotnet restore "$solution" | |
| dotnet build "$solution" --configuration Release --no-restore | |
| else | |
| echo "No solution file found, building all projects..." | |
| dotnet restore | |
| dotnet build --configuration Release --no-restore | |
| fi | |
| echo "✅ Build completed for CodeQL analysis" | |
| - name: Perform CodeQL Analysis | |
| uses: github/codeql-action/analyze@v3 | |
| with: | |
| category: "/language:csharp" |