From 30851a48a6f6b520c9acc03e711e4c5407c044b8 Mon Sep 17 00:00:00 2001 From: Joakim Olsson Date: Wed, 28 Jan 2026 13:03:07 +0100 Subject: [PATCH] ci: add code coverage integration Add go-test-coverage for coverage threshold enforcement. Coverage data is uploaded as artifacts on main branch and compared against baseline in PRs using shell script that gracefully handles first run without baseline. PR comments show coverage percentage. Co-Authored-By: Claude Opus 4.5 --- .gitea/workflows/ci.yaml | 55 ++++++++++++++++++++++++++++++++++++++++ .testcoverage.yml | 13 ++++++++++ 2 files changed, 68 insertions(+) create mode 100644 .testcoverage.yml diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 02bd607..800fecf 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -17,6 +17,61 @@ jobs: - name: Run tests run: go test -race -coverprofile=coverage.txt ./... + - name: Check coverage + uses: vladopajic/go-test-coverage@v2 + with: + config: ./.testcoverage.yml + + # Download baseline coverage from main branch (for PRs) + - name: Download baseline coverage + if: gitea.event_name == 'pull_request' + uses: actions/download-artifact@v3 + with: + name: coverage-baseline + path: ./baseline + continue-on-error: true + + # Compare coverage against baseline (for PRs) + - name: Compare coverage + if: gitea.event_name == 'pull_request' + run: | + CURRENT=$(go tool cover -func=coverage.txt | grep "^total:" | awk '{print $NF}' | tr -d '%') + if [ -f ./baseline/coverage.txt ]; then + BASE=$(go tool cover -func=./baseline/coverage.txt | grep "^total:" | awk '{print $NF}' | tr -d '%') + echo "Base coverage: ${BASE}%" + echo "Current coverage: ${CURRENT}%" + if [ "$(echo "$CURRENT < $BASE" | bc -l)" -eq 1 ]; then + echo "::error::Coverage decreased from ${BASE}% to ${CURRENT}%" + exit 1 + fi + echo "Coverage maintained or improved: ${BASE}% -> ${CURRENT}%" + else + echo "No baseline coverage found, skipping comparison" + echo "Current coverage: ${CURRENT}%" + fi + + # Upload coverage as baseline (only on main) + - name: Upload coverage baseline + if: gitea.ref == 'refs/heads/main' + uses: actions/upload-artifact@v3 + with: + name: coverage-baseline + path: coverage.txt + retention-days: 90 + + # Post coverage to PR comment + - name: Post coverage comment + if: gitea.event_name == 'pull_request' + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + GITEA_URL: ${{ gitea.server_url }} + run: | + COVERAGE=$(go tool cover -func=coverage.txt | grep "^total:" | awk '{print $NF}') + curl -X POST "${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/issues/${{ gitea.event.pull_request.number }}/comments" \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"body\": \"## Coverage Report\n\nTotal coverage: **${COVERAGE}**\"}" + vulnerabilities: runs-on: ubuntu-latest steps: diff --git a/.testcoverage.yml b/.testcoverage.yml new file mode 100644 index 0000000..7aec8b6 --- /dev/null +++ b/.testcoverage.yml @@ -0,0 +1,13 @@ +# Coverage configuration for go-test-coverage +# https://github.com/vladopajic/go-test-coverage + +profile: coverage.txt + +threshold: + file: 0 + package: 0 + total: 0 + +exclude: + paths: + - _test\.go$ -- 2.52.0