Skip to content

Merge pull request #170 from marius-bughiu/feat/issue-22-frozen-celer… #15

Merge pull request #170 from marius-bughiu/feat/issue-22-frozen-celer…

Merge pull request #170 from marius-bughiu/feat/issue-22-frozen-celer… #15

Workflow file for this run

name: Coverage
# Code-coverage reporting and gate (issue #29). Collects line/branch coverage for
# the Celerity library via coverlet, renders an HTML report + badges with
# ReportGenerator, fails the build if coverage drops below the floor, comments the
# summary on PRs, and publishes the HTML report to gh-pages (/coverage) on main.
on:
push:
branches: [ main ]
paths:
- 'src/**'
- '.github/workflows/coverage.yml'
pull_request:
branches: [ main ]
paths:
- 'src/**'
- '.github/workflows/coverage.yml'
# Coverage floor. The suite sits well above this (~99.9% line); the floor is the
# contract that guards against silent regressions, not the target.
env:
MIN_LINE_COVERAGE: '95'
MIN_BRANCH_COVERAGE: '90'
jobs:
coverage:
name: coverage
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
filter: tree:0
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Collect coverage
working-directory: src
run: >
dotnet test Celerity.Tests/Celerity.Tests.csproj
--configuration Release
--collect:"XPlat Code Coverage"
--settings coverage.runsettings
--results-directory ./TestResults/coverage
# Renders the HTML report, badge, and PR summary, writes the run summary,
# and fails the job if coverage is below the floor — all in one script, so
# the report carries the project's own styling and no third-party upsell.
- name: Generate report and enforce floor
run: >
python3 scripts/coverage_report.py
--input "src/TestResults/coverage/**/coverage.cobertura.xml"
--outdir coveragereport
--min-line "$MIN_LINE_COVERAGE"
--min-branch "$MIN_BRANCH_COVERAGE"
- name: Upload coverage artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coveragereport
if-no-files-found: warn
retention-days: 14
- name: Comment coverage on PR
if: always() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const marker = '<!-- celerity-coverage-comment -->';
const summary = fs.readFileSync('coveragereport/summary.md', 'utf8');
const body = `${marker}\n${summary}`;
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(c => c.body && c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
- name: Publish report to gh-pages
# Same gate as the benchmark dashboard sync: main pushes only. Drops the
# HTML report under /coverage, leaving the benchmark data untouched.
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
set -euo pipefail
git fetch origin gh-pages
git worktree add /tmp/gh-pages gh-pages
rm -rf /tmp/gh-pages/coverage
mkdir -p /tmp/gh-pages/coverage
cp -r coveragereport/* /tmp/gh-pages/coverage/
cd /tmp/gh-pages
if git diff --quiet && git diff --cached --quiet; then
echo "No coverage changes to sync"
exit 0
fi
git -c user.name="github-actions" -c user.email="github-actions@github.com" add coverage
git -c user.name="github-actions" -c user.email="github-actions@github.com" \
commit -m "Sync coverage report from ${GITHUB_SHA:0:7}"
git push origin gh-pages