Skip to content

chore: Bump dotnet-stryker from 4.12.0 to 4.13.0 #215

chore: Bump dotnet-stryker from 4.12.0 to 4.13.0

chore: Bump dotnet-stryker from 4.12.0 to 4.13.0 #215

Workflow file for this run

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/</\&lt;/g; s/>/\&gt;/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