Skip to content

FEAT: Full Code Coverage & Workflow Integration #19

FEAT: Full Code Coverage & Workflow Integration

FEAT: Full Code Coverage & Workflow Integration #19

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
<table>
<tr>
<td align="center" width="100">
### 🎯 Coverage
## **${{ env.COVERAGE_PERCENTAGE }}**
</td>
<td width="20"></td>
<td>
**📈 Lines Covered:** `${{ env.COVERED_LINES }}` out of `${{ env.TOTAL_LINES }}`
**📁 Project:** `mssql-python`
**🔍 Parser:** `Cobertura`
</td>
</tr>
</table>
---
### 📋 Files Needing Attention
<details>
<summary>📉 <strong>Files with lowest coverage</strong> (click to expand)</summary>
<br>
```diff
${{ env.LOW_COVERAGE_FILES }}
```
> 💡 **Tip:** Focus on improving coverage for these files to boost overall project health
</details>
---
<div align="center">
### 🔗 Quick Links
| � **Build Status** | 📊 **Coverage Details** |
|:---:|:---:|
| [View Azure DevOps Build](${{ env.ADO_URL }}) | [Browse Full Coverage Report](${{ env.ADO_URL }}&view=codecoverage-tab) |
</div>
<sub>🤖 This report was automatically generated from Azure DevOps build artifacts</sub>