chore: Bump dotnet-stryker from 4.12.0 to 4.13.0 #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 - Continuous Integration | |
| on: | |
| push: | |
| branches: [ main, develop, feature/** ] | |
| pull_request: | |
| branches: [ main, develop ] | |
| env: | |
| DOTNET_VERSION: '10.0.x' | |
| BUILD_CONFIGURATION: 'Release' | |
| jobs: | |
| # Job 1: Build and Unit Tests | |
| build-and-unit-tests: | |
| runs-on: ubuntu-latest | |
| name: Build and Unit Tests | |
| permissions: | |
| checks: write | |
| pull-requests: write | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Restore dependencies | |
| run: dotnet restore TheOfficeAPI.sln | |
| - name: Build solution | |
| run: dotnet build TheOfficeAPI.sln --configuration ${{ env.BUILD_CONFIGURATION }} --no-restore | |
| - name: Setup Allure config for unit tests | |
| run: | | |
| mkdir -p ${{ github.workspace }}/allure-results | |
| echo '{"allure":{"directory":"${{ github.workspace }}/allure-results"}}' > ${{ github.workspace }}/allureConfig.json | |
| echo "Created allureConfig.json:" | |
| cat ${{ github.workspace }}/allureConfig.json | |
| - name: Run unit tests | |
| run: | | |
| dotnet test tests/TheOfficeAPI.Common.Tests.Unit/TheOfficeAPI.Common.Tests.Unit.csproj --configuration ${{ env.BUILD_CONFIGURATION }} --no-build --verbosity normal --logger trx --collect:"XPlat Code Coverage" | |
| dotnet test tests/TheOfficeAPI.Level0.Tests.Unit/TheOfficeAPI.Level0.Tests.Unit.csproj --configuration ${{ env.BUILD_CONFIGURATION }} --no-build --verbosity normal --logger trx --collect:"XPlat Code Coverage" | |
| dotnet test tests/TheOfficeAPI.Level1.Tests.Unit/TheOfficeAPI.Level1.Tests.Unit.csproj --configuration ${{ env.BUILD_CONFIGURATION }} --no-build --verbosity normal --logger trx --collect:"XPlat Code Coverage" | |
| dotnet test tests/TheOfficeAPI.Level2.Tests.Unit/TheOfficeAPI.Level2.Tests.Unit.csproj --configuration ${{ env.BUILD_CONFIGURATION }} --no-build --verbosity normal --logger trx --collect:"XPlat Code Coverage" | |
| dotnet test tests/TheOfficeAPI.Level3.Tests.Unit/TheOfficeAPI.Level3.Tests.Unit.csproj --configuration ${{ env.BUILD_CONFIGURATION }} --no-build --verbosity normal --logger trx --collect:"XPlat Code Coverage" | |
| env: | |
| ALLURE_CONFIG: ${{ github.workspace }}/allureConfig.json | |
| - name: Collect Allure results | |
| if: always() | |
| run: | | |
| echo "=== Allure results collection ===" | |
| echo "Checking workspace allure-results:" | |
| ls -la ${{ github.workspace }}/allure-results 2>/dev/null || echo "No results at workspace level" | |
| echo "" | |
| echo "Searching for allure-results directories in tests:" | |
| find ./tests -name "allure-results" -type d 2>/dev/null || true | |
| echo "" | |
| mkdir -p allure-results | |
| # Copy from workspace level | |
| if [ -d "${{ github.workspace }}/allure-results" ] && [ "$(ls -A ${{ github.workspace }}/allure-results 2>/dev/null)" ]; then | |
| echo "Copying from workspace allure-results" | |
| cp -r ${{ github.workspace }}/allure-results/* allure-results/ 2>/dev/null || true | |
| fi | |
| # Also search in test project output directories | |
| find ./tests -path "*/bin/*" -name "allure-results" -type d -exec sh -c 'echo "Found: $1"; cp -r "$1"/* allure-results/ 2>/dev/null || true' _ {} \; | |
| echo "" | |
| echo "Final allure-results contents:" | |
| ls -la allure-results 2>/dev/null || echo "Directory is empty" | |
| echo "Total: $(ls -1 allure-results 2>/dev/null | wc -l) files" | |
| - name: Download previous Allure history from GitHub Pages | |
| if: always() | |
| run: | | |
| echo "Downloading Allure history from GitHub Pages..." | |
| mkdir -p allure-history | |
| # Try to download history from GitHub Pages (unit tests) | |
| HISTORY_URL="https://fszymaniak.github.io/TheOfficeAPI/allure/unit/history" | |
| # Download history files if they exist | |
| if curl -f -s "${HISTORY_URL}/history.json" -o allure-history/history.json 2>/dev/null; then | |
| echo "✓ Downloaded history.json" | |
| # Download other history files | |
| curl -f -s "${HISTORY_URL}/history-trend.json" -o allure-history/history-trend.json 2>/dev/null || true | |
| curl -f -s "${HISTORY_URL}/duration-trend.json" -o allure-history/duration-trend.json 2>/dev/null || true | |
| curl -f -s "${HISTORY_URL}/retry-trend.json" -o allure-history/retry-trend.json 2>/dev/null || true | |
| curl -f -s "${HISTORY_URL}/categories-trend.json" -o allure-history/categories-trend.json 2>/dev/null || true | |
| echo "✓ Allure history downloaded successfully from GitHub Pages" | |
| ls -la allure-history/ | |
| else | |
| echo "ℹ No previous Allure history found (first run or GitHub Pages not yet deployed)" | |
| echo "This is expected for the first run - history will be created after this build" | |
| fi | |
| continue-on-error: true | |
| - name: Install Allure CLI | |
| if: always() | |
| run: | | |
| curl -o allure-2.32.0.tgz -Ls https://github.com/allure-framework/allure2/releases/download/2.32.0/allure-2.32.0.tgz | |
| tar -zxvf allure-2.32.0.tgz | |
| echo "$PWD/allure-2.32.0/bin" >> $GITHUB_PATH | |
| - name: Generate Allure Report | |
| if: always() | |
| run: | | |
| if [ -d "allure-history" ]; then | |
| cp -r allure-history allure-results/history || true | |
| fi | |
| allure-2.32.0/bin/allure generate allure-results -o allure-report --clean | |
| cp -r allure-report/history allure-history || true | |
| - name: Upload Allure Report | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: allure-report | |
| path: allure-report | |
| retention-days: 30 | |
| - name: Publish unit test results | |
| uses: dorny/test-reporter@v1 | |
| if: success() || failure() | |
| with: | |
| name: Unit Test Results | |
| path: '**/*.trx' | |
| reporter: dotnet-trx | |
| - name: Upload coverage reports | |
| uses: codecov/codecov-action@v4 | |
| if: success() | |
| with: | |
| files: '**/coverage.cobertura.xml' | |
| fail_ci_if_error: false | |
| continue-on-error: true | |
| # Job 2: Mocked Integration Tests | |
| mocked-integration-tests: | |
| runs-on: ubuntu-latest | |
| name: Mocked Integration Tests | |
| needs: build-and-unit-tests | |
| permissions: | |
| checks: write | |
| pull-requests: write | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Restore dependencies | |
| run: dotnet restore TheOfficeAPI.sln | |
| - name: Build solution | |
| run: dotnet build TheOfficeAPI.sln --configuration ${{ env.BUILD_CONFIGURATION }} --no-restore | |
| - name: Setup Allure config for integration tests | |
| run: | | |
| mkdir -p ${{ github.workspace }}/allure-results | |
| echo '{"allure":{"directory":"${{ github.workspace }}/allure-results"}}' > ${{ github.workspace }}/allureConfig.json | |
| echo "Created allureConfig.json:" | |
| cat ${{ github.workspace }}/allureConfig.json | |
| - name: Run mocked integration tests | |
| run: | | |
| dotnet test tests/TheOfficeAPI.Level0.Tests.Integration/TheOfficeAPI.Level0.Tests.Integration.csproj --configuration ${{ env.BUILD_CONFIGURATION }} --no-build --verbosity normal --logger trx --filter "Category=Mocked" | |
| dotnet test tests/TheOfficeAPI.Level1.Tests.Integration/TheOfficeAPI.Level1.Tests.Integration.csproj --configuration ${{ env.BUILD_CONFIGURATION }} --no-build --verbosity normal --logger trx --filter "Category=Mocked" | |
| dotnet test tests/TheOfficeAPI.Level2.Tests.Integration/TheOfficeAPI.Level2.Tests.Integration.csproj --configuration ${{ env.BUILD_CONFIGURATION }} --no-build --verbosity normal --logger trx --filter "Category=Mocked" | |
| dotnet test tests/TheOfficeAPI.Level3.Tests.Integration/TheOfficeAPI.Level3.Tests.Integration.csproj --configuration ${{ env.BUILD_CONFIGURATION }} --no-build --verbosity normal --logger trx --filter "Category=Mocked" | |
| env: | |
| ASPNETCORE_ENVIRONMENT: Testing | |
| ALLURE_CONFIG: ${{ github.workspace }}/allureConfig.json | |
| - name: Collect Allure results | |
| if: always() | |
| run: | | |
| echo "=== Allure results collection ===" | |
| echo "Checking workspace allure-results:" | |
| ls -la ${{ github.workspace }}/allure-results 2>/dev/null || echo "No results at workspace level" | |
| mkdir -p allure-results | |
| if [ -d "${{ github.workspace }}/allure-results" ] && [ "$(ls -A ${{ github.workspace }}/allure-results 2>/dev/null)" ]; then | |
| echo "Copying from workspace allure-results" | |
| cp -r ${{ github.workspace }}/allure-results/* allure-results/ 2>/dev/null || true | |
| fi | |
| find ./tests -path "*/bin/*" -name "allure-results" -type d -exec sh -c 'echo "Found: $1"; cp -r "$1"/* allure-results/ 2>/dev/null || true' _ {} \; | |
| echo "Total: $(ls -1 allure-results 2>/dev/null | wc -l) files" | |
| - name: Download previous Allure history from GitHub Pages | |
| if: always() | |
| run: | | |
| echo "Downloading Allure history from GitHub Pages..." | |
| mkdir -p allure-history | |
| # Try to download history from GitHub Pages (integration tests) | |
| HISTORY_URL="https://fszymaniak.github.io/TheOfficeAPI/allure/integration/history" | |
| # Download history files if they exist | |
| if curl -f -s "${HISTORY_URL}/history.json" -o allure-history/history.json 2>/dev/null; then | |
| echo "✓ Downloaded history.json" | |
| # Download other history files | |
| curl -f -s "${HISTORY_URL}/history-trend.json" -o allure-history/history-trend.json 2>/dev/null || true | |
| curl -f -s "${HISTORY_URL}/duration-trend.json" -o allure-history/duration-trend.json 2>/dev/null || true | |
| curl -f -s "${HISTORY_URL}/retry-trend.json" -o allure-history/retry-trend.json 2>/dev/null || true | |
| curl -f -s "${HISTORY_URL}/categories-trend.json" -o allure-history/categories-trend.json 2>/dev/null || true | |
| echo "✓ Allure history downloaded successfully from GitHub Pages" | |
| ls -la allure-history/ | |
| else | |
| echo "ℹ No previous Allure history found (first run or GitHub Pages not yet deployed)" | |
| echo "This is expected for the first run - history will be created after this build" | |
| fi | |
| continue-on-error: true | |
| - name: Install Allure CLI | |
| if: always() | |
| run: | | |
| curl -o allure-2.32.0.tgz -Ls https://github.com/allure-framework/allure2/releases/download/2.32.0/allure-2.32.0.tgz | |
| tar -zxvf allure-2.32.0.tgz | |
| - name: Generate Allure Report for Integration Tests | |
| if: always() | |
| run: | | |
| if [ -d "allure-history" ]; then | |
| cp -r allure-history allure-results/history || true | |
| fi | |
| allure-2.32.0/bin/allure generate allure-results -o allure-report-integration --clean | |
| - name: Upload Integration Tests Allure Report | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: allure-report-integration | |
| path: allure-report-integration | |
| retention-days: 30 | |
| - name: Publish mocked integration test results | |
| uses: dorny/test-reporter@v1 | |
| if: success() || failure() | |
| with: | |
| name: Mocked Integration Test Results | |
| path: '**/*.trx' | |
| reporter: dotnet-trx | |
| # Job 3: Mutation Testing | |
| mutation-testing: | |
| runs-on: ubuntu-latest | |
| name: Mutation Testing | |
| needs: build-and-unit-tests | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Restore dotnet tools | |
| run: dotnet tool restore | |
| - name: Restore dependencies | |
| run: dotnet restore TheOfficeAPI.sln | |
| - name: Build solution | |
| run: dotnet build TheOfficeAPI.sln --configuration ${{ env.BUILD_CONFIGURATION }} --no-restore | |
| - name: Run Stryker mutation tests | |
| id: stryker-run | |
| run: | | |
| echo "Running mutation tests with Stryker.NET..." | |
| echo "Stryker version:" | |
| dotnet stryker --version || echo "Could not get version" | |
| echo "" | |
| echo "Current directory: $(pwd)" | |
| echo "Checking for source and test projects:" | |
| ls -la src/TheOfficeAPI/TheOfficeAPI.csproj || echo "Source project not found" | |
| ls -la tests/TheOfficeAPI.*.Tests.Unit/*.csproj || echo "Test projects not found" | |
| echo "" | |
| echo "Starting mutation testing with detailed logging..." | |
| set +e | |
| dotnet stryker --config-file stryker-config.ci.json --verbosity debug --log-to-file 2>&1 | tee stryker-console.log | |
| STRYKER_EXIT_CODE=$? | |
| set -e | |
| echo "" | |
| echo "Stryker exit code: $STRYKER_EXIT_CODE" | |
| echo "" | |
| echo "Checking for Stryker log files:" | |
| find . -name "*.log" -type f 2>/dev/null || echo "No log files found" | |
| echo "" | |
| if [ $STRYKER_EXIT_CODE -ne 0 ]; then | |
| echo "::warning::Stryker mutation testing failed with exit code $STRYKER_EXIT_CODE" | |
| echo "Last 100 lines of Stryker console output:" | |
| tail -100 stryker-console.log || true | |
| else | |
| echo "Stryker completed successfully. Showing last 50 lines of output:" | |
| tail -50 stryker-console.log || true | |
| fi | |
| echo "" | |
| echo "Checking StrykerOutput directory:" | |
| if [ -d "StrykerOutput" ]; then | |
| echo "StrykerOutput exists. Contents:" | |
| find StrykerOutput -type f 2>/dev/null | head -30 || echo "No files found" | |
| else | |
| echo "StrykerOutput directory not found!" | |
| fi | |
| echo "stryker_exit_code=$STRYKER_EXIT_CODE" >> $GITHUB_OUTPUT | |
| timeout-minutes: 30 | |
| continue-on-error: true | |
| - name: Prepare Stryker Report for upload | |
| if: always() | |
| run: | | |
| echo "=== Stryker Report Preparation ===" | |
| echo "" | |
| echo "Step 1: Checking StrykerOutput directory structure..." | |
| if [ -d "StrykerOutput" ]; then | |
| echo "StrykerOutput directory exists:" | |
| echo "All files in StrykerOutput:" | |
| find StrykerOutput -type f 2>/dev/null | sort || echo "No files found" | |
| echo "" | |
| echo "HTML files found:" | |
| find StrykerOutput -type f -name "*.html" 2>/dev/null | sort || echo "No HTML files found" | |
| echo "" | |
| echo "JSON files found:" | |
| find StrykerOutput -type f -name "*.json" 2>/dev/null | sort || echo "No JSON files found" | |
| echo "" | |
| echo "Directory tree (first 100 lines):" | |
| ls -laR StrykerOutput 2>/dev/null | head -100 || echo "Could not list directory" | |
| else | |
| echo "StrykerOutput directory does NOT exist" | |
| fi | |
| echo "" | |
| echo "Step 2: Finding Stryker reports..." | |
| # Stryker.NET creates reports in: StrykerOutput/reports/ (newer versions) | |
| # or StrykerOutput/<timestamp>/reports/ (older versions) | |
| mkdir -p stryker-reports | |
| # Find and copy HTML reports (look for both index.html and mutation-report.html) | |
| REPORT_FOUND=false | |
| # First, try to find the most recent reports directory | |
| REPORTS_DIR=$(find StrykerOutput -type d -name "reports" 2>/dev/null | sort -r | head -1) | |
| if [ -n "$REPORTS_DIR" ] && [ -d "$REPORTS_DIR" ]; then | |
| echo "Found reports directory: $REPORTS_DIR" | |
| ls -la "$REPORTS_DIR" | |
| # Copy ALL files from the reports directory to preserve complete structure | |
| echo "Copying all files from reports directory..." | |
| cp -r "$REPORTS_DIR"/* stryker-reports/ 2>/dev/null || cp -r "$REPORTS_DIR"/. stryker-reports/ 2>/dev/null | |
| # Check if mutation-report.html exists | |
| if [ -f "stryker-reports/mutation-report.html" ]; then | |
| echo "✓ Found and copied mutation-report.html" | |
| REPORT_FOUND=true | |
| elif [ -f "stryker-reports/index.html" ]; then | |
| echo "✓ Found index.html" | |
| # Create a copy as mutation-report.html for consistency | |
| cp "stryker-reports/index.html" "stryker-reports/mutation-report.html" | |
| echo "✓ Created mutation-report.html from index.html" | |
| REPORT_FOUND=true | |
| fi | |
| # Verify JSON report exists | |
| if [ -f "stryker-reports/mutation-report.json" ]; then | |
| echo "✓ Found mutation-report.json" | |
| else | |
| echo "⚠ Warning: mutation-report.json not found" | |
| fi | |
| # List all copied files for debugging | |
| echo "Files copied to stryker-reports:" | |
| ls -la stryker-reports/ 2>/dev/null || echo "No files" | |
| else | |
| echo "No reports directory found, searching for HTML files recursively..." | |
| # Fallback: search for any HTML report files | |
| if find StrykerOutput -name "mutation-report.html" -exec cp {} stryker-reports/ \; 2>/dev/null; then | |
| if [ -f "stryker-reports/mutation-report.html" ]; then | |
| echo "✓ Found and copied mutation-report.html" | |
| REPORT_FOUND=true | |
| fi | |
| fi | |
| # Also look for index.html as fallback | |
| if [ "$REPORT_FOUND" = false ]; then | |
| if find StrykerOutput -name "index.html" -exec cp {} stryker-reports/mutation-report.html \; 2>/dev/null; then | |
| if [ -f "stryker-reports/mutation-report.html" ]; then | |
| echo "✓ Found and copied index.html as mutation-report.html" | |
| REPORT_FOUND=true | |
| fi | |
| fi | |
| fi | |
| # Also copy JSON file in fallback mode | |
| if find StrykerOutput -name "mutation-report.json" -exec cp {} stryker-reports/ \; 2>/dev/null; then | |
| echo "✓ Found and copied mutation-report.json" | |
| fi | |
| fi | |
| # Copy all Stryker logs for debugging | |
| if [ -f "stryker-console.log" ]; then | |
| cp stryker-console.log stryker-reports/ 2>/dev/null || true | |
| echo "✓ Copied Stryker console log" | |
| fi | |
| # Copy any log files created by --log-to-file | |
| find . -maxdepth 2 -name "*.log" -type f -exec cp {} stryker-reports/ \; 2>/dev/null || true | |
| echo "✓ Copied all log files to reports directory" | |
| echo "" | |
| echo "Step 3: Verifying report status..." | |
| # If no reports found, create a placeholder with debugging info | |
| if [ ! -f "stryker-reports/mutation-report.html" ]; then | |
| STRYKER_EXIT="${{ steps.stryker-run.outputs.stryker_exit_code }}" | |
| echo "❌ No mutation report found (Stryker exit code: $STRYKER_EXIT)" | |
| echo "Creating placeholder with debugging information..." | |
| # Include directory listing and log excerpt in placeholder for debugging | |
| DIR_LISTING=$(find StrykerOutput -type f 2>/dev/null | head -20 || echo "No files found") | |
| # Get last 30 lines of console log if available | |
| if [ -f "stryker-console.log" ]; then | |
| LOG_EXCERPT=$(tail -30 stryker-console.log 2>/dev/null | sed 's/</\</g; s/>/\>/g' || echo "Could not read log") | |
| else | |
| LOG_EXCERPT="Log file not found" | |
| fi | |
| cat > stryker-reports/mutation-report.html << PLACEHOLDER | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Stryker Report - Not Generated</title> | |
| <style> | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; } | |
| h1 { color: #666; } | |
| p { color: #888; } | |
| .info { background: #f5f5f5; padding: 15px; border-radius: 8px; margin: 20px 0; text-align: left; } | |
| .info code { background: #e0e0e0; padding: 2px 6px; border-radius: 4px; } | |
| .debug { background: #fff3cd; border: 1px solid #ffc107; padding: 10px; margin: 20px 0; font-family: monospace; font-size: 12px; overflow-x: auto; } | |
| a { color: #0066cc; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>Stryker Mutation Report</h1> | |
| <p>The mutation testing report was not generated for this build.</p> | |
| <div class="info"> | |
| <p><strong>Build Information:</strong></p> | |
| <p>Stryker Exit Code: <code>$STRYKER_EXIT</code></p> | |
| <p>Workflow Run: <code>${GITHUB_RUN_ID:-unknown}</code></p> | |
| <p>Commit: <code>${GITHUB_SHA:-unknown}</code></p> | |
| </div> | |
| <div class="info"> | |
| <p><strong>Possible reasons:</strong></p> | |
| <ul style="margin-left: 20px;"> | |
| <li>Mutation testing timed out (30 min limit)</li> | |
| <li>Build or test failures prevented Stryker from running</li> | |
| <li>Insufficient memory or resources</li> | |
| <li>Stryker HTML reporter not configured correctly</li> | |
| </ul> | |
| </div> | |
| <div class="debug"> | |
| <strong>Debug Info - Files found in StrykerOutput:</strong><br> | |
| <pre>$DIR_LISTING</pre> | |
| </div> | |
| <div class="debug"> | |
| <strong>Last 30 lines of Stryker console output:</strong><br> | |
| <pre>$LOG_EXCERPT</pre> | |
| </div> | |
| <p><a href="../index.html">← Back to All Reports</a></p> | |
| </body> | |
| </html> | |
| PLACEHOLDER | |
| else | |
| echo "✓ Mutation report found successfully!" | |
| # Verify it's a real report | |
| if grep -qi "stryker" stryker-reports/mutation-report.html 2>/dev/null; then | |
| echo "✓ Verified: This appears to be a genuine Stryker report" | |
| else | |
| echo "⚠ Warning: mutation-report.html exists but may not be a genuine Stryker report" | |
| fi | |
| fi | |
| echo "" | |
| echo "Step 4: Final report contents:" | |
| ls -la stryker-reports/ | |
| - name: Upload Stryker Report | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: stryker-report | |
| path: stryker-reports | |
| retention-days: 30 | |
| if-no-files-found: warn | |
| - name: Upload Stryker Logs | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: stryker-logs | |
| path: | | |
| stryker-console.log | |
| *.log | |
| StrykerOutput/**/*.log | |
| retention-days: 7 | |
| if-no-files-found: ignore | |
| # Job 4: Code Quality Checks (optional) | |
| code-quality: | |
| runs-on: ubuntu-latest | |
| name: Code Quality Checks | |
| needs: build-and-unit-tests | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Shallow clones should be disabled for better SonarCloud analysis | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Restore dependencies | |
| run: dotnet restore TheOfficeAPI.sln | |
| - name: Check code formatting | |
| run: | | |
| echo "Checking code formatting..." | |
| if ! dotnet format TheOfficeAPI.sln --verify-no-changes --verbosity minimal; then | |
| echo "⚠️ Code formatting issues detected. Run 'dotnet format' locally to fix." | |
| exit 0 | |
| fi | |
| echo "✓ Code formatting is correct" | |
| - name: Run security scan | |
| run: | | |
| dotnet list TheOfficeAPI.sln package --vulnerable --include-transitive 2>&1 | tee vulnerability-report.txt | |
| if grep -q "has the following vulnerable packages" vulnerability-report.txt; then | |
| echo "WARNING: Vulnerable packages found!" | |
| cat vulnerability-report.txt | |
| else | |
| echo "SUCCESS: No vulnerable packages found" | |
| fi | |
| continue-on-error: true | |
| - name: Cache SonarCloud packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.sonar/cache | |
| key: ${{ runner.os }}-sonar | |
| restore-keys: ${{ runner.os }}-sonar | |
| - name: Install SonarCloud scanner | |
| run: dotnet tool install --global dotnet-sonarscanner | |
| - name: Build and analyze with SonarCloud | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| PR_HEAD_REF: ${{ github.head_ref }} | |
| PR_BASE_REF: ${{ github.base_ref }} | |
| BRANCH_NAME: ${{ github.ref_name }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| run: | | |
| # Build SonarScanner command with PR-specific parameters | |
| SONAR_PARAMS="/k:\"fszymaniak_TheOfficeAPI\" \ | |
| /o:\"fszymaniak\" \ | |
| /n:\"The Office API\" \ | |
| /v:\"1.0\" \ | |
| /d:sonar.token=\"${SONAR_TOKEN}\" \ | |
| /d:sonar.host.url=\"https://sonarcloud.io\"" | |
| # Add PR-specific parameters for pull requests | |
| if [ "$EVENT_NAME" == "pull_request" ]; then | |
| SONAR_PARAMS="$SONAR_PARAMS \ | |
| /d:sonar.pullrequest.key=\"${PR_NUMBER}\" \ | |
| /d:sonar.pullrequest.branch=\"${PR_HEAD_REF}\" \ | |
| /d:sonar.pullrequest.base=\"${PR_BASE_REF}\"" | |
| echo "Running SonarCloud analysis for PR #${PR_NUMBER}" | |
| else | |
| SONAR_PARAMS="$SONAR_PARAMS /d:sonar.branch.name=\"${BRANCH_NAME}\"" | |
| echo "Running SonarCloud analysis for branch ${BRANCH_NAME}" | |
| fi | |
| # Run analysis | |
| eval dotnet sonarscanner begin $SONAR_PARAMS | |
| dotnet build TheOfficeAPI.sln --configuration ${{ env.BUILD_CONFIGURATION }} --no-restore | |
| dotnet sonarscanner end /d:sonar.token="${SONAR_TOKEN}" | |
| - name: SonarCloud Quality Gate check | |
| uses: sonarsource/sonarqube-quality-gate-action@master | |
| timeout-minutes: 5 | |
| with: | |
| scanMetadataReportFile: .sonarqube/out/.sonar/report-task.txt | |
| env: | |
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | |
| continue-on-error: true | |
| # Job 5: Deploy Test Reports to GitHub Pages | |
| deploy-test-reports: | |
| runs-on: ubuntu-latest | |
| name: Deploy Test Reports | |
| needs: [build-and-unit-tests, mocked-integration-tests, mutation-testing] | |
| if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' | |
| permissions: | |
| pages: write | |
| id-token: write | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| steps: | |
| - name: Create deploy directory | |
| run: mkdir -p deploy/allure deploy/stryker | |
| - name: Download Unit Test Allure Report | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: allure-report | |
| path: deploy/allure/unit | |
| - name: Download Integration Test Allure Report | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: allure-report-integration | |
| path: deploy/allure/integration | |
| - name: Download Stryker Mutation Report | |
| uses: actions/download-artifact@v4 | |
| id: download-stryker | |
| with: | |
| name: stryker-report | |
| path: deploy/stryker | |
| continue-on-error: true | |
| - name: Check Stryker artifact download | |
| run: | | |
| mkdir -p deploy/stryker | |
| if [ "${{ steps.download-stryker.outcome }}" == "success" ]; then | |
| echo "Stryker report artifact downloaded successfully" | |
| else | |
| echo "Stryker report artifact not found - this is expected if mutation testing failed or was skipped" | |
| fi | |
| - name: Verify and prepare Stryker reports | |
| run: | | |
| echo "Checking Stryker reports in deploy/stryker:" | |
| ls -la deploy/stryker/ 2>/dev/null || echo "Directory is empty or doesn't exist" | |
| # List all files for debugging | |
| echo "All files in deploy/stryker:" | |
| find deploy/stryker -type f 2>/dev/null || echo "No files found" | |
| # Check for HTML and JSON files specifically | |
| if [ -f "deploy/stryker/mutation-report.html" ]; then | |
| echo "✓ mutation-report.html exists" | |
| fi | |
| if [ -f "deploy/stryker/mutation-report.json" ]; then | |
| echo "✓ mutation-report.json exists" | |
| fi | |
| # Create index.html that redirects to mutation-report.html or shows error | |
| if [ -f "deploy/stryker/mutation-report.html" ]; then | |
| echo "Found mutation-report.html, creating redirect index" | |
| cat > deploy/stryker/index.html << 'STRYKER_INDEX' | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta http-equiv="refresh" content="0; url=mutation-report.html"> | |
| <title>Redirecting to Stryker Report</title> | |
| </head> | |
| <body> | |
| <p>Redirecting to <a href="mutation-report.html">Stryker Mutation Report</a>...</p> | |
| </body> | |
| </html> | |
| STRYKER_INDEX | |
| else | |
| echo "No mutation-report.html found, creating placeholder" | |
| cat > deploy/stryker/index.html << 'STRYKER_PLACEHOLDER' | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Stryker Report - Not Available</title> | |
| <style> | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; text-align: center; } | |
| h1 { color: #666; } | |
| p { color: #888; } | |
| a { color: #0066cc; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>Stryker Mutation Report</h1> | |
| <p>The mutation testing report is not available for this build.</p> | |
| <p>This can happen if mutation testing was skipped or failed to generate reports.</p> | |
| <p><a href="../index.html">← Back to All Reports</a></p> | |
| </body> | |
| </html> | |
| STRYKER_PLACEHOLDER | |
| # Also create mutation-report.html pointing to index for direct links | |
| cp deploy/stryker/index.html deploy/stryker/mutation-report.html | |
| fi | |
| - name: Create main index page | |
| run: | | |
| cat > deploy/index.html << 'EOF' | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>TheOfficeAPI - Test Reports</title> | |
| <style> | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 900px; margin: 50px auto; padding: 20px; } | |
| h1 { color: #333; margin-bottom: 10px; } | |
| .subtitle { color: #666; margin-bottom: 40px; } | |
| .report-section { margin-bottom: 40px; } | |
| .report-section h2 { color: #444; border-bottom: 2px solid #0066cc; padding-bottom: 10px; } | |
| .report-link { display: block; padding: 20px; margin: 10px 0; background: #f5f5f5; border-radius: 8px; text-decoration: none; color: #333; transition: background 0.2s; } | |
| .report-link:hover { background: #e0e0e0; } | |
| .report-link h3 { margin: 0 0 10px 0; color: #0066cc; } | |
| .report-link p { margin: 0; color: #666; } | |
| .updated { color: #999; font-size: 0.9em; margin-top: 50px; text-align: center; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>TheOfficeAPI - Test Reports Dashboard</h1> | |
| <p class="subtitle">Comprehensive test coverage and quality metrics</p> | |
| <div class="report-section"> | |
| <h2>📊 Test Execution Reports (Allure)</h2> | |
| <a class="report-link" href="allure/unit/index.html"> | |
| <h3>Unit Test Report</h3> | |
| <p>Detailed Allure report for unit tests across all API levels (Level 0-3)</p> | |
| </a> | |
| <a class="report-link" href="allure/integration/index.html"> | |
| <h3>Integration Test Report</h3> | |
| <p>Allure report for mocked integration tests</p> | |
| </a> | |
| </div> | |
| <div class="report-section"> | |
| <h2>🧬 Mutation Testing Report (Stryker)</h2> | |
| <a class="report-link" href="stryker/mutation-report.html"> | |
| <h3>Mutation Test Report</h3> | |
| <p>Stryker.NET mutation testing results - measures test suite effectiveness by introducing code mutations</p> | |
| </a> | |
| </div> | |
| <p class="updated">Last updated: $(date -u '+%Y-%m-%d %H:%M:%S UTC')</p> | |
| </body> | |
| </html> | |
| EOF | |
| - name: Create Allure index page | |
| run: | | |
| CURRENT_DATE=$(date -u '+%Y-%m-%d %H:%M:%S UTC') | |
| cat > deploy/allure/index.html << EOF | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>TheOfficeAPI - Allure Test Reports</title> | |
| <style> | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; } | |
| h1 { color: #333; } | |
| .back-link { color: #0066cc; text-decoration: none; margin-bottom: 20px; display: inline-block; } | |
| .back-link:hover { text-decoration: underline; } | |
| .report-link { display: block; padding: 20px; margin: 10px 0; background: #f5f5f5; border-radius: 8px; text-decoration: none; color: #333; } | |
| .report-link:hover { background: #e0e0e0; } | |
| .report-link h2 { margin: 0 0 10px 0; color: #0066cc; } | |
| .report-link p { margin: 0; color: #666; } | |
| .updated { color: #999; font-size: 0.9em; margin-top: 30px; } | |
| </style> | |
| </head> | |
| <body> | |
| <a class="back-link" href="../index.html">← Back to All Reports</a> | |
| <h1>TheOfficeAPI - Allure Test Reports</h1> | |
| <a class="report-link" href="unit/index.html"> | |
| <h2>Unit Test Report</h2> | |
| <p>Allure report for unit tests across all API levels</p> | |
| </a> | |
| <a class="report-link" href="integration/index.html"> | |
| <h2>Integration Test Report</h2> | |
| <p>Allure report for mocked integration tests</p> | |
| </a> | |
| <p class="updated">Last updated: ${CURRENT_DATE}</p> | |
| </body> | |
| </html> | |
| EOF | |
| - name: Create .nojekyll file | |
| run: | | |
| echo "Creating .nojekyll file to disable Jekyll processing" | |
| touch deploy/.nojekyll | |
| echo "✓ .nojekyll file created" | |
| - name: Setup Pages | |
| uses: actions/configure-pages@v4 | |
| - name: Upload Pages artifact | |
| uses: actions/upload-pages-artifact@v3 | |
| with: | |
| path: deploy | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v4 | |
| # Job 6: CI Summary | |
| ci-summary: | |
| runs-on: ubuntu-latest | |
| name: CI Summary | |
| needs: [build-and-unit-tests, mocked-integration-tests, mutation-testing, code-quality, deploy-test-reports] | |
| if: always() | |
| steps: | |
| - name: CI Success | |
| if: needs.build-and-unit-tests.result == 'success' && needs.mocked-integration-tests.result == 'success' | |
| run: | | |
| echo "========================================" | |
| echo "CI Pipeline - All Checks Passed!" | |
| echo "========================================" | |
| echo "" | |
| echo "Build: SUCCESS" | |
| echo "Unit Tests: PASSED" | |
| echo "Mocked Integration Tests: PASSED" | |
| echo "Mutation Testing: ${{ needs.mutation-testing.result }}" | |
| echo "Code Quality: ${{ needs.code-quality.result }}" | |
| echo "Test Reports: ${{ needs.deploy-test-reports.result }}" | |
| echo "" | |
| if [ "${{ github.ref }}" == "refs/heads/main" ] || [ "${{ github.ref }}" == "refs/heads/develop" ]; then | |
| echo "📊 Test Reports Dashboard: https://fszymaniak.github.io/TheOfficeAPI/" | |
| echo " - Allure Reports: https://fszymaniak.github.io/TheOfficeAPI/allure/" | |
| echo " - Stryker Mutation Report: https://fszymaniak.github.io/TheOfficeAPI/stryker/" | |
| echo "" | |
| echo "Ready for deployment - CD pipeline will start automatically" | |
| echo "E2E tests will run after deployment completes" | |
| fi | |
| - name: CI Failure | |
| if: needs.build-and-unit-tests.result == 'failure' || needs.mocked-integration-tests.result == 'failure' | |
| run: | | |
| echo "========================================" | |
| echo "CI Pipeline Failed!" | |
| echo "========================================" | |
| echo "" | |
| [ "${{ needs.build-and-unit-tests.result }}" == "failure" ] && echo "FAILED: Build or Unit Tests" | |
| [ "${{ needs.mocked-integration-tests.result }}" == "failure" ] && echo "FAILED: Mocked Integration Tests" | |
| echo "" | |
| exit 1 |