From d0e92e767a778414b318d5ea20d2c255db48596e 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 22184cf..5acf786 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$