FEAT: Full Code Coverage & Workflow Integration #18
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: PR Code Coverage | |
on: | |
pull_request: | |
branches: | |
- main | |
jobs: | |
coverage-report: | |
runs-on: ubuntu-latest | |
permissions: | |
pull-requests: write | |
contents: read | |
steps: | |
- name: Checkout repo | |
uses: actions/checkout@v4 | |
- name: Wait for ADO build to succeed | |
run: | | |
PR_NUMBER=${{ github.event.pull_request.number }} | |
API_URL="https://dev.azure.com/sqlclientdrivers/public/_apis/build/builds?definitions=2128&queryOrder=queueTimeDescending&%24top=10&api-version=7.1-preview.7" | |
echo "Waiting for Azure DevOps build for PR #$PR_NUMBER ..." | |
for i in {1..100}; do | |
BUILD_INFO=$(curl -s "$API_URL" | jq -c --arg PR "$PR_NUMBER" '[.value[] | select(.triggerInfo["pr.number"]==$PR)][0] // empty') | |
if [[ -n "$BUILD_INFO" && "$BUILD_INFO" != "null" ]]; then | |
STATUS=$(echo "$BUILD_INFO" | jq -r .status) | |
RESULT=$(echo "$BUILD_INFO" | jq -r .result) | |
BUILD_ID=$(echo "$BUILD_INFO" | jq -r .id) | |
WEB_URL=$(echo "$BUILD_INFO" | jq -r ._links.web.href) | |
if [[ "$STATUS" == "completed" ]]; then | |
if [[ "$RESULT" == "succeeded" ]]; then | |
echo "✅ Build $BUILD_ID succeeded: $WEB_URL" | |
echo "ADO_URL=$WEB_URL" >> $GITHUB_ENV | |
echo "BUILD_ID=$BUILD_ID" >> $GITHUB_ENV | |
break | |
else | |
echo "❌ Build $BUILD_ID failed" | |
exit 1 | |
fi | |
fi | |
fi | |
echo "⏳ Build not ready yet... retrying in 20s" | |
sleep 20 | |
done | |
- name: Download and parse coverage report | |
run: | | |
BUILD_ID=${{ env.BUILD_ID }} | |
ARTIFACTS_URL="https://dev.azure.com/SqlClientDrivers/public/_apis/build/builds/$BUILD_ID/artifacts?api-version=7.1-preview.5" | |
echo "📥 Fetching artifacts for build $BUILD_ID..." | |
ARTIFACTS=$(curl -s "$ARTIFACTS_URL") | |
# Find the coverage report artifact | |
COVERAGE_ARTIFACT=$(echo "$ARTIFACTS" | jq -r '.value[] | select(.name | test("Code Coverage Report")) | .resource.downloadUrl') | |
if [[ -n "$COVERAGE_ARTIFACT" && "$COVERAGE_ARTIFACT" != "null" ]]; then | |
echo "📊 Downloading coverage report..." | |
curl -L "$COVERAGE_ARTIFACT" -o coverage-report.zip | |
unzip -q coverage-report.zip | |
# Find the main index.html file | |
INDEX_FILE=$(find . -name "index.html" -path "*/Code Coverage Report*" | head -1) | |
if [[ -f "$INDEX_FILE" ]]; then | |
echo "🔍 Parsing coverage data from $INDEX_FILE..." | |
# Debug: Show relevant parts of the HTML | |
echo "Debug: Looking for coverage data..." | |
grep -n "cardpercentagebar\|Covered lines\|Coverable lines" "$INDEX_FILE" | head -10 | |
# Extract coverage metrics using simpler, more reliable patterns | |
OVERALL_PERCENTAGE=$(grep -o 'cardpercentagebar[0-9]*">[0-9]*%' "$INDEX_FILE" | head -1 | grep -o '[0-9]*%') | |
COVERED_LINES=$(grep -A1 "Covered lines:" "$INDEX_FILE" | grep -o 'title="[0-9]*"' | head -1 | grep -o '[0-9]*') | |
TOTAL_LINES=$(grep -A1 "Coverable lines:" "$INDEX_FILE" | grep -o 'title="[0-9]*"' | head -1 | grep -o '[0-9]*') | |
# Fallback method if the above doesn't work | |
if [[ -z "$OVERALL_PERCENTAGE" ]]; then | |
echo "Trying alternative parsing method..." | |
OVERALL_PERCENTAGE=$(grep -o 'large.*">[0-9]*%' "$INDEX_FILE" | head -1 | grep -o '[0-9]*%') | |
fi | |
echo "Extracted values:" | |
echo "OVERALL_PERCENTAGE=$OVERALL_PERCENTAGE" | |
echo "COVERED_LINES=$COVERED_LINES" | |
echo "TOTAL_LINES=$TOTAL_LINES" | |
echo "COVERAGE_PERCENTAGE=$OVERALL_PERCENTAGE" >> $GITHUB_ENV | |
echo "COVERED_LINES=$COVERED_LINES" >> $GITHUB_ENV | |
echo "TOTAL_LINES=$TOTAL_LINES" >> $GITHUB_ENV | |
# Extract top files with low coverage - improved approach | |
echo "📋 Extracting file-level coverage..." | |
# Extract file coverage data more reliably | |
LOW_COVERAGE_FILES=$(grep -o '<td><a href="[^"]*">[^<]*</a></td><td class="right">[0-9]*</td><td class="right">[0-9]*</td><td class="right">[0-9]*</td><td class="right">[0-9]*</td><td title="[^"]*" class="right">[0-9]*\.[0-9]*%' "$INDEX_FILE" | \ | |
sed 's/<td><a href="[^"]*">\([^<]*\)<\/a><\/td>.*class="right">\([0-9]*\.[0-9]*\)%/\1: \2%/' | \ | |
sort -t: -k2 -n | head -5) | |
# Alternative method if above fails | |
if [[ -z "$LOW_COVERAGE_FILES" ]]; then | |
echo "Trying alternative file parsing..." | |
LOW_COVERAGE_FILES=$(grep -E "\.py.*[0-9]+\.[0-9]+%" "$INDEX_FILE" | \ | |
grep -o "[^>]*\.py[^<]*</a>.*[0-9]*\.[0-9]*%" | \ | |
sed 's/\([^<]*\)<\/a>.*\([0-9]*\.[0-9]*\)%/\1: \2%/' | \ | |
sort -t: -k2 -n | head -5) | |
fi | |
echo "LOW_COVERAGE_FILES<<EOF" >> $GITHUB_ENV | |
echo "$LOW_COVERAGE_FILES" >> $GITHUB_ENV | |
echo "EOF" >> $GITHUB_ENV | |
echo "✅ Coverage data extracted successfully" | |
else | |
echo "❌ Could not find index.html in coverage report" | |
exit 1 | |
fi | |
else | |
echo "❌ Could not find coverage report artifact" | |
exit 1 | |
fi | |
- name: Comment coverage summary on PR | |
uses: marocchino/sticky-pull-request-comment@v2 | |
with: | |
header: Code Coverage Report | |
message: | | |
## 📊 Code Coverage Report | |
**Overall Coverage:** ${{ env.COVERAGE_PERCENTAGE }} (${{ env.COVERED_LINES }}/${{ env.TOTAL_LINES }} lines) | |
### Files Needing Attention | |
<details> | |
<summary>Files with lowest coverage (click to expand)</summary> | |
``` | |
${{ env.LOW_COVERAGE_FILES }} | |
``` | |
</details> | |
--- | |
✅ **Azure DevOps Build:** [View Full Report](${{ env.ADO_URL }}&view=codecoverage-tab) | |
📊 **Detailed Coverage:** [Browse Coverage Details](${{ env.ADO_URL }}&view=codecoverage-tab) |