Skip to content

better comments

better comments #64

Workflow file for this run

# 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 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
os: [macos-latest] # Specify the OS versions to test against
# python-version: ["3.9", "3.10", "3.11"] # Specify the Python versions to test against
python-version: ["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
# Create a timestamp for the output file, and
# Add variables to the GitHub environment
# For pytest on CD/CD, us --cov=rattlesnake (instead of --cov=src/rattlesnake)
# because pytest gets its coverage data from the site-packages directory
run: |
TIMESTAMP=$(date +"%Y%m%d_%H%M%S_%Z")
pytest -v --cov=rattlesnake --cov-report=html --cov-report=xml --cov-report=term-missing
echo "TIMESTAMP=$TIMESTAMP" >> $GITHUB_ENV
- name: Confirm new environment variables
run: |
echo "TIMESTAMP=${{ env.TIMESTAMP }}"
# Read the pylint output and create a custom HTML report, to be saved to
# https://sandialabs.github.io/rattlesnake-vibration-controller/reports/coverage
- name: Create custom Pytest Report in HTML format (refined version)
run: |
python src/rattlesnake/cicd/report_pytest.py \
--input_file coverage.xml \
--output_file pytest_report.html \
--timestamp ${{ env.TIMESTAMP }} \
--run_id ${{ github.run_id }} \
--ref_name ${{ github.ref_name }} \
--github_sha ${{ github.sha }} \
--github_repo ${{ github.repository }}
- name: Upload Pytest report artifact
if: github.ref == 'refs/heads/dev'
uses: actions/upload-artifact@v4
with:
name: pytest-report
path: pytest_report.html
- name: Upload htmlcov artifact
if: github.ref == 'refs/heads/dev'
uses: actions/upload-artifact@v4
with:
name: htmlcov-report
path: htmlcov/
- 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: Download report artifacts
if: github.ref == 'refs/heads/dev'
uses: actions/download-artifact@v4
with:
name: pytest-report
- name: Download htmlcov artifact
if: github.ref == 'refs/heads/dev'
uses: actions/download-artifact@v4
with:
name: htmlcov-report
path: htmlcov
- name: Assemble pages directory
if: github.ref == 'refs/heads/dev'
run: |
# Create the directory structure
mkdir -p pages/reports/coverage
# Move the downloaded report files into place
mv pytest_report.html pages/reports/coverage/index.html
mv htmlcov pages/reports/coverage/
# Create the root index page
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 Vibration Controller - Reports</title>
<style>
body { font-family: sans-serif; margin: 40px; background-color: #f6f8fa; }
.container { max-width: 800px; margin: 0 auto; background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
h1 { color: #333; }
a { color: #0366d6; text-decoration: none; }
a:hover { text-decoration: underline; }
ul { list-style-type: none; padding: 0; }
li { background-color: #f1f1f1; margin: 10px 0; padding: 15px; border-radius: 4px; }
</style>
</head>
<body>
<div class="container">
<h1>Rattlesnake Vibration Controller - Reports</h1>
<p>This page provides links to the latest reports generated by the CI/CD pipeline.</p>
<ul>
<li><a href="reports/coverage/index.html">View Pytest Coverage Report</a></li>
<li><a href="reports/pylint/index.html">View Pylint Report</a></li>
</ul>
</div>
</body>
</html>
EOF
- name: Generate coverage report
run: pytest --cov=rattlesnake --cov-report=xml
- name: Calculate coverage and color
run: |
python3 -c '''
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 (FileNotFoundError, KeyError, ET.ParseError):
coverage = 0.0
print(f"Coverage: {coverage:.1f}%")
if coverage >= 90:
color = "brightgreen"
elif coverage >= 80:
color = "green"
elif coverage >= 70:
color = "yellow"
elif coverage >= 60:
color = "orange"
else:
color = "red"
with open(os.environ["GITHUB_ENV"], "a") as f:
f.write(f"COVERAGE={coverage:.1f}\n")
f.write(f"BADGE_COLOR={color}\n")
'''
- name: Confirm new environment variables
run: |
echo "COVERAGE=${{ env.COVERAGE}}"
echo "BADGE_COLOR=${{ env.BADGE_COLOR }}"
- name: Generate coverage badge and metadata
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
keep_files: true
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 # avoid race condition with pylint.yml job
git config --local user.email "[email protected]"
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