dependency on mkdocs #35
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
# This file is a GitHub Actions workflow configuration file that runs Pytest on pushes and pull requests to the main and dev branches. It sets up a matrix of Python versions (3.8 and 3.9) to test against, checks out the code, installs dependencies, and runs the tests using Pytest. | |
name: pytest | |
on: | |
push: | |
branches: | |
- main | |
- dev # for now, suppress run on dev branch | |
pull_request: | |
branches: | |
- main | |
- dev # for now, suppress run on dev branch | |
jobs: | |
test: | |
# runs-on: ubuntu-latest | |
strategy: | |
matrix: | |
os: [macos-latest, ubuntu-latest, windows-latest] # Specify the OS versions to test against | |
python-version: ["3.9", "3.10", "3.11"] # Specify the Python versions to test against | |
runs-on: ${{ matrix.os }} # Use the OS from the matrix | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Set up Python ${{ matrix.python-version }} | |
uses: actions/setup-python@v3 | |
with: | |
python-version: ${{ matrix.python-version }} # Use the version from the matrix | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install .[dev] | |
- name: Run tests with coverage | |
run: | | |
pytest -v --cov=src/rattlesnake --cov-report=xml --cov-report=term-missing --cov-report=html | |
- name: Upload coverage to artifact (Ubuntu + Python 3.9 only) | |
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.9' | |
uses: actions/upload-artifact@v4 | |
with: | |
name: coverage-report | |
path: coverage.xml | |
# retention-days: 7 | |
# Separate job for badge generation (only runs after test passes) | |
coverage-badge: | |
needs: test # Only run if test passes | |
runs-on: ubuntu-latest | |
# if: github.ref == 'refs/heads/main' # Only create badge on main branch | |
if: github.ref == 'refs/heads/dev' # Only create badge on dev branch, update to main branch later | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v4 | |
- name: Set up Python 3.11 | |
uses: actions/setup-python@v3 | |
with: | |
python-version: "3.11" # Use a specific Python version for badge generation | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install .[dev] | |
# pip install pytest-cov coverage-badge # already included in dev dependencies | |
# - name: Generate coverage report and analyze | |
# run: | | |
# pytest --cov=src/rattlesnake --cov-report=xml | |
- name: Generate coverage report and analyze | |
run: | | |
# Create a timestamp for the output file | |
TIMESTAMP=$(date +"%Y%m%d_%H%M%S_%Z") | |
OUTPUT_FILE="coverage_output_${TIMESTAMP}.txt" | |
# Generate coverage reports | |
pytest --cov=src/rattlesnake --cov-report=xml --cov-report=html --cov-report=term-missing > "$OUTPUT_FILE" || true | |
# Extract coverage percentage and determine badge color using Python | |
python3 << EOF | |
import xml.etree.ElementTree as ET | |
import os | |
try: | |
tree = ET.parse('coverage.xml') | |
root = tree.getroot() | |
coverage = float(root.attrib['line-rate']) * 100 | |
except: | |
coverage = 0.0 | |
print(f"Coverage: {coverage:.1f}%") | |
# Determine badge color based on coverage | |
if coverage >= 90: | |
color = "brightgreen" | |
elif coverage >= 80: | |
color = "green" | |
elif coverage >= 70: | |
color = "yellow" | |
elif coverage >= 60: | |
color = "orange" | |
else: | |
color = "red" | |
# Set environment variables | |
with open(os.environ['GITHUB_ENV'], 'a') as f: | |
f.write(f"COVERAGE={coverage:.1f}\n") | |
f.write(f"BADGE_COLOR={color}\n") | |
f.write(f"OUTPUT_FILE=$OUTPUT_FILE\n") | |
EOF | |
- name: Create custom HTML report | |
run: | | |
# Read the coverage output and create a custom HTML report | |
python3 << 'EOF' | |
import os | |
import html | |
import re | |
from datetime import datetime | |
import pytz | |
import xml.etree.ElementTree as ET | |
# Get the current UTC time | |
utc_now = datetime.now(pytz.utc) | |
# Define the time zones | |
est = pytz.timezone('America/New_York') | |
mst = pytz.timezone('America/Denver') | |
# Convert UTC time to EST and MST | |
est_now = utc_now.astimezone(est) | |
mst_now = utc_now.astimezone(mst) | |
# Format the output | |
formatted_time = utc_now.strftime("%Y-%m-%d %H:%M:%S UTC") + f" ({est_now.strftime('%Y-%m-%d %H:%M:%S EST')} / {mst_now.strftime('%Y-%m-%d %H:%M:%S MST')})" | |
# Read coverage XML for detailed info | |
try: | |
tree = ET.parse('coverage.xml') | |
root = tree.getroot() | |
line_rate = float(root.attrib['line-rate']) * 100 | |
branch_rate = float(root.attrib.get('branch-rate', 0)) * 100 | |
lines_covered = int(root.attrib.get('lines-covered', 0)) | |
lines_valid = int(root.attrib.get('lines-valid', 0)) | |
branches_covered = int(root.attrib.get('branches-covered', 0)) | |
branches_valid = int(root.attrib.get('branches-valid', 0)) | |
# Extract missing lines information from XML | |
missing_lines_by_file = {} | |
for package in root.findall('.//package'): | |
for class_elem in package.findall('.//class'): | |
filename = class_elem.get('filename', '') | |
missing_lines = [] | |
for line in class_elem.findall('.//line'): | |
if line.get('hits') == '0': | |
missing_lines.append(int(line.get('number'))) | |
if missing_lines: | |
missing_lines_by_file[filename] = sorted(missing_lines) | |
except: | |
line_rate = 0 | |
branch_rate = 0 | |
lines_covered = 0 | |
lines_valid = 0 | |
branches_covered = 0 | |
branches_valid = 0 | |
missing_lines_by_file = {} | |
# Read pytest output | |
output_file = os.environ.get('OUTPUT_FILE', '') | |
pytest_content = "" | |
missing_lines_info = [] | |
if output_file and os.path.exists(output_file): | |
with open(output_file, 'r') as f: | |
pytest_content = f.read() | |
# Parse missing lines from term-missing output | |
lines = pytest_content.split('\n') | |
in_coverage_section = False | |
for line in lines: | |
if 'Name' in line and 'Stmts' in line and 'Miss' in line and 'Cover' in line and 'Missing' in line: | |
in_coverage_section = True | |
continue | |
elif in_coverage_section and line.strip() and not line.startswith('-'): | |
parts = line.split() | |
if len(parts) >= 5 and parts[-1] != '': | |
filename = parts[0] | |
missing = parts[-1] if parts[-1] != '' else 'None' | |
if missing != 'None' and missing != '': | |
missing_lines_info.append({'file': filename, 'missing': missing}) | |
elif in_coverage_section and (line.startswith('=') or line.strip() == ''): | |
break | |
# Parse test results from pytest output | |
test_results = [] | |
summary_lines = [] | |
collecting_summary = False | |
for line in pytest_content.split('\n'): | |
if '::' in line and any(x in line.upper() for x in ['PASSED', 'FAILED', 'SKIPPED', 'ERROR']): | |
test_results.append(line.strip()) | |
elif 'collected' in line or 'passed' in line or 'failed' in line or 'error' in line: | |
collecting_summary = True | |
if collecting_summary: | |
summary_lines.append(line) | |
# Get environment variables | |
coverage_percent = os.environ.get("COVERAGE", "0") | |
run_id = os.environ.get("GITHUB_RUN_ID", "N/A") | |
ref_name = os.environ.get("GITHUB_REF_NAME", "N/A") | |
github_sha = os.environ.get("GITHUB_SHA", "N/A") | |
github_repo = os.environ.get("GITHUB_REPOSITORY", "") | |
# Determine score color | |
try: | |
coverage_val = float(coverage_percent) | |
if coverage_val >= 90: | |
coverage_color = "#28a745" | |
elif coverage_val >= 80: | |
coverage_color = "#28a745" | |
elif coverage_val >= 70: | |
coverage_color = "#ffc107" | |
elif coverage_val >= 60: | |
coverage_color = "#fd7e14" | |
else: | |
coverage_color = "#dc3545" | |
except: | |
coverage_color = "#6c757d" | |
# Count test results | |
passed_count = len([t for t in test_results if "PASSED" in t.upper()]) | |
failed_count = len([t for t in test_results if "FAILED" in t.upper()]) | |
skipped_count = len([t for t in test_results if "SKIPPED" in t.upper()]) | |
error_count = len([t for t in test_results if "ERROR" in t.upper()]) | |
total_tests = len(test_results) | |
# Generate missing lines HTML | |
missing_lines_html = "" | |
if missing_lines_info: | |
missing_sections = [] | |
for item in missing_lines_info: | |
missing_sections.append(f''' | |
<div class="missing-file"> | |
<h4>{html.escape(item['file'])}</h4> | |
<div class="missing-lines"> | |
<strong>Missing lines:</strong> {html.escape(item['missing'])} | |
</div> | |
</div> | |
''') | |
missing_lines_html = f''' | |
<div class="section"> | |
<h2 id="missing">🚫 Missing Coverage</h2> | |
<p>Lines not covered by tests:</p> | |
<div class="missing-coverage"> | |
{"".join(missing_sections)} | |
</div> | |
</div> | |
''' | |
else: | |
missing_lines_html = ''' | |
<div class="section"> | |
<h2 id="missing">✅ Complete Coverage</h2> | |
<p>All lines are covered by tests! 🎉</p> | |
</div> | |
''' | |
# Generate test results HTML | |
if not test_results: | |
tests_html = "<p>No test results found.</p>" | |
else: | |
tests_list = [] | |
for test in test_results: | |
if "PASSED" in test.upper(): | |
css_class = "passed" | |
elif "FAILED" in test.upper(): | |
css_class = "failed" | |
elif "SKIPPED" in test.upper(): | |
css_class = "skipped" | |
else: | |
css_class = "error" | |
tests_list.append(f'<div class="test-result {css_class}">{html.escape(test)}</div>') | |
tests_html = f'<div class="tests-list">{"".join(tests_list)}</div>' | |
# Create HTML content | |
html_content = f'''<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Coverage Report - Rattlesnake</title> | |
<style> | |
body {{ | |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
margin: 0; padding: 20px; background: #f6f8fa; line-height: 1.6; | |
}} | |
.container {{ | |
max-width: 1200px; margin: 0 auto; | |
}} | |
.header {{ | |
background: white; padding: 30px; border-radius: 8px; | |
box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 20px; | |
}} | |
.coverage {{ | |
font-size: 2.5em; font-weight: bold; color: {coverage_color}; | |
}} | |
.metadata {{ | |
color: #6a737d; font-size: 0.9em; margin-top: 10px; | |
}} | |
.nav {{ | |
background: white; padding: 20px; border-radius: 8px; | |
box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 20px; | |
}} | |
.nav a {{ | |
background: #0366d6; color: white; padding: 10px 20px; | |
text-decoration: none; border-radius: 6px; margin-right: 10px; | |
display: inline-block; margin-bottom: 5px; | |
}} | |
.nav a:hover {{ | |
background: #0256cc; | |
}} | |
.section {{ | |
background: white; padding: 25px; border-radius: 8px; | |
box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 20px; | |
}} | |
.tests-list {{ | |
max-height: 500px; overflow-y: auto; | |
border: 1px solid #e1e4e8; border-radius: 6px; | |
}} | |
.test-result {{ | |
padding: 10px; border-bottom: 1px solid #e1e4e8; | |
font-family: 'SFMono-Regular', 'Consolas', monospace; | |
font-size: 0.9em; | |
}} | |
.test-result:last-child {{ | |
border-bottom: none; | |
}} | |
.test-result.passed {{ background: #e6ffed; }} | |
.test-result.failed {{ background: #ffeef0; }} | |
.test-result.skipped {{ background: #fff8e1; }} | |
.test-result.error {{ background: #ffeaa7; }} | |
.summary {{ | |
background: #f6f8fa; padding: 20px; border-radius: 6px; | |
border-left: 4px solid #0366d6; font-family: monospace; | |
white-space: pre-wrap; | |
}} | |
.stats {{ | |
display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
gap: 15px; margin-top: 20px; | |
}} | |
.stat-card {{ | |
background: #f6f8fa; padding: 15px; border-radius: 6px; text-align: center; | |
}} | |
.stat-number {{ | |
font-size: 1.8em; font-weight: bold; color: #0366d6; | |
}} | |
.coverage-details {{ | |
display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | |
gap: 15px; margin-top: 20px; | |
}} | |
.coverage-card {{ | |
background: #f6f8fa; padding: 20px; border-radius: 6px; | |
}} | |
.coverage-card h4 {{ | |
margin-top: 0; color: #0366d6; | |
}} | |
.progress-bar {{ | |
background: #e1e4e8; height: 20px; border-radius: 10px; overflow: hidden; | |
}} | |
.progress-fill {{ | |
height: 100%; background: {coverage_color}; | |
transition: width 0.3s ease; | |
}} | |
.missing-coverage {{ | |
max-height: 400px; overflow-y: auto; | |
border: 1px solid #e1e4e8; border-radius: 6px; | |
}} | |
.missing-file {{ | |
padding: 15px; border-bottom: 1px solid #e1e4e8; | |
}} | |
.missing-file:last-child {{ | |
border-bottom: none; | |
}} | |
.missing-file h4 {{ | |
margin: 0 0 10px 0; color: #0366d6; | |
font-family: 'SFMono-Regular', 'Consolas', monospace; | |
}} | |
.missing-lines {{ | |
background: #ffeef0; padding: 10px; border-radius: 4px; | |
border-left: 4px solid #dc3545; font-family: monospace; | |
font-size: 0.9em; | |
}} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="header"> | |
<h1>Rattlesnake Coverage Report</h1> | |
<div class="coverage">{coverage_percent}%</div> | |
<div class="metadata"> | |
<div><strong>Generated:</strong> {formatted_time}</div> | |
<div><strong>Run ID:</strong> {run_id}</div> | |
<div><strong>Branch:</strong> {ref_name}</div> | |
<div><strong>Commit:</strong> {github_sha[:8]}</div> | |
</div> | |
</div> | |
<div class="nav"> | |
<a href="#summary">Summary</a> | |
<a href="#tests">Test Results ({total_tests})</a> | |
<a href="#coverage">Coverage Details</a> | |
<a href="#missing">Missing Coverage</a> | |
<a href="#full-report">Full Report</a> | |
<a href="https://github.com/{github_repo}/actions/runs/{run_id}">View Workflow Run</a> | |
<a href="https://github.com/{github_repo}">Repository</a> | |
</div> | |
<div class="section"> | |
<h2 id="summary">📊 Test Summary</h2> | |
<div class="stats"> | |
<div class="stat-card"> | |
<div class="stat-number">{total_tests}</div> | |
<div>Total Tests</div> | |
</div> | |
<div class="stat-card"> | |
<div class="stat-number" style="color: #28a745;">{passed_count}</div> | |
<div>Passed</div> | |
</div> | |
<div class="stat-card"> | |
<div class="stat-number" style="color: #dc3545;">{failed_count}</div> | |
<div>Failed</div> | |
</div> | |
<div class="stat-card"> | |
<div class="stat-number" style="color: #ffc107;">{skipped_count}</div> | |
<div>Skipped</div> | |
</div> | |
</div> | |
</div> | |
<div class="section"> | |
<h2 id="coverage">📈 Coverage Details</h2> | |
<div class="coverage-details"> | |
<div class="coverage-card"> | |
<h4>Line Coverage</h4> | |
<div class="progress-bar"> | |
<div class="progress-fill" style="width: {line_rate}%;"></div> | |
</div> | |
<p><strong>{line_rate:.1f}%</strong> ({lines_covered}/{lines_valid} lines)</p> | |
</div> | |
<div class="coverage-card"> | |
<h4>Branch Coverage</h4> | |
<div class="progress-bar"> | |
<div class="progress-fill" style="width: {branch_rate}%;"></div> | |
</div> | |
<p><strong>{branch_rate:.1f}%</strong> ({branches_covered}/{branches_valid} branches)</p> | |
</div> | |
</div> | |
</div> | |
<div class="section"> | |
<h2 id="missing">🚫 Missing Coverage</h2> | |
<div class="missing-coverage"> | |
<div class="coverage-card"> | |
<h4>Line Coverage</h4> | |
<div class="progress-bar"> | |
<div class="progress-fill" style="width: {line_rate}%;"></div> | |
</div> | |
<p><strong>{line_rate:.1f}%</strong> ({lines_covered}/{lines_valid} lines)</p> | |
</div> | |
<div class="coverage-card"> | |
<h4>Branch Coverage</h4> | |
<div class="progress-bar"> | |
<div class="progress-fill" style="width: {branch_rate}%;"></div> | |
</div> | |
<p><strong>{branch_rate:.1f}%</strong> ({branches_covered}/{branches_valid} branches)</p> | |
</div> | |
</div> | |
</div> | |
<div class="section"> | |
<h2 id="tests">🧪 Test Results Detail</h2> | |
{tests_html} | |
</div> | |
<div class="section"> | |
<h2 id="full-report">📋 Full Report</h2> | |
<details> | |
<summary>Click to view complete pytest output</summary> | |
<pre style="background: #f6f8fa; padding: 20px; border-radius: 6px; overflow-x: auto;">{html.escape(pytest_content)}</pre> | |
</details> | |
</div> | |
</div> | |
<footer style="text-align: center; margin: 40px 0; color: #6a737d;"> | |
<p>Generated by GitHub Actions • <a href="https://github.com/{github_repo}">Rattlesnake Project</a></p> | |
</footer> | |
</body> | |
</html>''' | |
# Write HTML file | |
with open('coverage_enhanced_report.html', 'w') as f: | |
f.write(html_content) | |
EOF | |
- name: Prepare GitHub Pages content | |
if: github.ref == 'refs/heads/dev' # Only deploy on dev branch | |
run: | | |
# Create pages directory structure | |
mkdir -p pages/reports/coverage | |
# Copy the enhanced report as the main report | |
cp coverage_enhanced_report.html pages/reports/coverage/index.html | |
# Copy HTML coverage report if it exists | |
if [ -d "htmlcov" ]; then | |
cp -r htmlcov pages/reports/coverage/htmlcov | |
fi | |
# Update main index page for all reports (or create if it doesn't exist) | |
cat > pages/index.html << 'EOF' | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Rattlesnake Code Quality Reports</title> | |
<style> | |
body { | |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
margin: 0; padding: 20px; background: #f6f8fa; | |
} | |
.container { | |
max-width: 800px; margin: 0 auto; | |
} | |
.header { | |
background: white; padding: 30px; border-radius: 8px; | |
box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 30px; text-align: center; | |
} | |
.report-card { | |
background: white; padding: 20px; border-radius: 8px; | |
box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 20px; | |
} | |
.report-card h3 { | |
margin-top: 0; color: #0366d6; | |
} | |
.report-link { | |
background: #0366d6; color: white; padding: 10px 20px; | |
text-decoration: none; border-radius: 6px; display: inline-block; margin-right: 10px; | |
} | |
.report-link:hover { | |
background: #0256cc; | |
} | |
.badge { | |
margin: 10px 5px; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="header"> | |
<h1>Rattlesnake Code Quality Reports Summary</h1> | |
<p>Automated code quality analysis for the Rattlesnake vibration controller</p> | |
<div class="badge"> | |
<img src="https://github.com/${{ github.repository }}/raw/dev/badges/pylint.svg" alt="Pylint Score"> | |
</div> | |
<div class="badge"> | |
<img src="https://github.com/${{ github.repository }}/raw/dev/badges/coverage.svg" alt="Coverage"> | |
</div> | |
</div> | |
<div class="report-card"> | |
<h3>📊 Coverage Report</h3> | |
<p>Test coverage analysis showing how much of the codebase is covered by tests.</p> | |
<p><strong>Latest Coverage:</strong> ${{ env.COVERAGE }}%</p> | |
<p><strong>Last Updated:</strong> $(date)</p> | |
<a href="./reports/coverage/" class="report-link">Coverage Report</a> | |
<a href="./reports/coverage/htmlcov/" class="report-link">Detailed HTML Coverage</a> | |
</div> | |
<div class="report-card"> | |
<h3>📊 Pylint Report</h3> | |
<p>Static code analysis results showing code quality metrics, style compliance, and potential issues.</p> | |
<p><strong>Last Updated:</strong> Check latest workflow run</p> | |
<a href="./reports/pylint/" class="report-link">Pylint Report</a> | |
</div> | |
<div class="report-card"> | |
<h3>🔗 Quick Links</h3> | |
<p> | |
<a href="https://github.com/${{ github.repository }}" class="report-link">GitHub Repository</a> | |
<a href="https://github.com/${{ github.repository }}/actions" class="report-link">GitHub Actions</a> | |
<a href="https://github.com/${{ github.repository }}/releases" class="report-link">Releases</a> | |
</p> | |
</div> | |
</div> | |
</body> | |
</html> | |
EOF | |
- name: Generate coverage badge | |
run: | | |
# Create badges directory if it doesn't exist | |
mkdir -p badges | |
# Create the badge URL that links to the latest workflow run | |
REPO_URL="${{ github.server_url }}/${{ github.repository }}" | |
WORKFLOW_URL="${REPO_URL}/actions/workflows/pytest.yml" | |
# Download badge using shields.io | |
curl -o badges/coverage.svg "https://img.shields.io/badge/coverage-${{ env.COVERAGE }}%25-${{ env.BADGE_COLOR }}.svg" | |
# Create a JSON file with badge metadata including GitHub Pages link | |
cat > badges/coverage-info.json << EOF | |
{ | |
"coverage": "${{ env.COVERAGE }}", | |
"color": "${{ env.BADGE_COLOR }}", | |
"pages_url": "https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/reports/coverage/", | |
"workflow_url": "${WORKFLOW_URL}", | |
"run_id": "${{ github.run_id }}", | |
"artifact_url": "${REPO_URL}/actions/runs/${{ github.run_id }}", | |
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" | |
} | |
EOF | |
- name: Deploy to GitHub Pages | |
if: github.ref == 'refs/heads/dev' | |
uses: peaceiris/actions-gh-pages@v3 | |
with: | |
github_token: ${{ secrets.GITHUB_TOKEN }} | |
publish_dir: ./pages | |
publish_branch: gh-pages | |
commit_message: 'Deploy coverage report for ${{ github.sha }}' | |
- name: Commit badge to main repository (dev branch for now) | |
# if: github.ref == 'refs/heads/main' # Only create badge on main branch | |
if: github.ref == 'refs/heads/dev' # Only create badge on dev branch, update to main branch later | |
run: | | |
# git fetch | |
git pull | |
git config --local user.email "action@github.com" | |
git config --local user.name "GitHub Action" | |
git add badges/coverage.svg badges/coverage-info.json | |
git diff --staged --quiet || git commit -m "Update coverage badge [skip ci]" | |
git push | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- name: Upload HTML coverage report as artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: coverage-html-report-${{ github.run_id }} | |
path: htmlcov/ | |
retention-days: 7 | |
- name: Upload enhanced coverage report as artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: coverage-enhanced-report-${{ github.run_id }} | |
path: coverage_enhanced_report.html | |
retention-days: 7 |