Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,47 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Generate coverage summary
if: matrix.python-version == '3.11'
run: |
# Create coverage summary for job summary
if [ -f .coverage_baseline.json ]; then
python -c "
import json
import subprocess
import re
import os

# Get current coverage
result = subprocess.run(['python', '-m', 'pytest', '--cov=.', '--cov-report=term-missing', '--quiet'], capture_output=True, text=True)
match = re.search(r'TOTAL.*?(\d+)%', result.stdout)
current_cov = float(match.group(1)) if match else 0

# Get baseline
try:
with open('.coverage_baseline.json') as f:
baseline = json.load(f)
baseline_cov = baseline['total_coverage']
except:
baseline_cov = current_cov

diff = current_cov - baseline_cov

with open(os.environ['GITHUB_STEP_SUMMARY'], 'a') as f:
f.write('\n## 📊 Coverage Summary\n\n')
f.write(f'- **Current Coverage**: {current_cov}%\n')
f.write(f'- **Baseline Coverage**: {baseline_cov}%\n')
f.write(f'- **Change**: {diff:+.1f}%\n\n')

if diff >= 0:
f.write('✅ Coverage maintained or improved\n')
elif diff >= -2:
f.write('📊 Coverage within acceptable tolerance (2%)\n')
else:
f.write('⚠️ Significant coverage decline detected\n')
"
fi

- name: Upload coverage to Codecov
if: matrix.python-version == '3.11'
uses: codecov/codecov-action@v4
Expand Down
39 changes: 38 additions & 1 deletion .github/workflows/coverage-guard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Extract coverage data for PR comment
- name: Extract coverage data and create summary
id: coverage
if: github.event_name == 'pull_request'
run: |
Expand All @@ -66,6 +66,43 @@ jobs:

echo "MAIN_COVERAGE=$MAIN_COVERAGE" >> $GITHUB_OUTPUT
echo "CURRENT_COVERAGE=$CURRENT_COVERAGE" >> $GITHUB_OUTPUT

# Create GitHub Job Summary using Python for comparisons
if [ "$MAIN_COVERAGE" != "unknown" ]; then
python -c "
import os

main_cov = float('$MAIN_COVERAGE')
current_cov = float('$CURRENT_COVERAGE')
diff = current_cov - main_cov

with open(os.environ['GITHUB_STEP_SUMMARY'], 'w') as f:
f.write('# 📊 Coverage Report\n\n')
f.write('| Branch | Coverage | Change |\n')
f.write('|--------|----------|--------|\n')
f.write(f'| main | {main_cov}% | baseline |\n')
f.write(f'| ${{ github.head_ref }} | {current_cov}% | {diff:+.1f}% |\n\n')

if diff > 2:
f.write(f'✅ **Coverage improved significantly** by {diff:.1f}%\n')
elif diff > 0:
f.write(f'✅ **Coverage improved** by {diff:.1f}%\n')
elif diff >= -2:
f.write(f'📊 **Coverage maintained** ({diff:+.1f}% change, within 2% tolerance)\n\n')
f.write('> ✅ **Within tolerance** - small coverage changes are acceptable.\n')
else:
f.write(f'⚠️ **Coverage declined significantly** by {abs(diff):.1f}%\n\n')
f.write('> ❌ **Significant regression detected!** This exceeds the 2% tolerance.\n')
"
else
echo "# 📊 Coverage Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "⚠️ **No baseline available** - this may be the first run." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Current Coverage |" >> $GITHUB_STEP_SUMMARY
echo "|------------------|" >> $GITHUB_STEP_SUMMARY
echo "| ${CURRENT_COVERAGE}% |" >> $GITHUB_STEP_SUMMARY
fi

- name: Comment PR with coverage results
if: github.event_name == 'pull_request' && steps.coverage.outputs.MAIN_COVERAGE != 'unknown'
Expand Down
57 changes: 57 additions & 0 deletions generate_coverage_badge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
"""
Generate a simple coverage badge for README
"""
import json
import os
import sys
import subprocess
import re


def get_current_coverage():
"""Get current coverage percentage"""
try:
result = subprocess.run(
["python", "-m", "pytest", "--cov=.", "--cov-report=term-missing", "--quiet"],
capture_output=True,
text=True,
)
match = re.search(r"TOTAL.*?(\d+)%", result.stdout)
return float(match.group(1)) if match else 0
except:
return 0


def generate_badge_url(coverage):
"""Generate shields.io badge URL"""
color = "red"
if coverage >= 90:
color = "brightgreen"
elif coverage >= 80:
color = "green"
elif coverage >= 70:
color = "yellow"
elif coverage >= 60:
color = "orange"

return f"https://img.shields.io/badge/coverage-{coverage}%25-{color}"


def main():
coverage = get_current_coverage()
badge_url = generate_badge_url(coverage)

print(f"Current coverage: {coverage}%")
print(f"Badge URL: {badge_url}")
print(f"Markdown: ![Coverage]({badge_url})")

# Save to file for GitHub Actions
if os.environ.get("GITHUB_ACTIONS"):
with open("coverage_badge.md", "w") as f:
f.write(f"![Coverage]({badge_url})\n")
print("Badge markdown saved to coverage_badge.md")


if __name__ == "__main__":
main()
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ omit = [
"*/venv/*",
"*/test_*",
"coverage_tracker.py",
"integration_tests.py"
"integration_tests.py",
"generate_coverage_badge.py"
]

[tool.coverage.report]
Expand Down
2 changes: 1 addition & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[tool:pytest]
addopts = --cov=. --cov-report=html --cov-report=term-missing
addopts = --cov=. --cov-report=html --cov-report=term-missing --cov-config=pyproject.toml
testpaths = .
python_files = test_*.py
Loading