gray background #55
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: pylint | |
on: | |
push: | |
branches: | |
- main | |
- dev | |
pull_request: | |
branches: | |
- main | |
- dev | |
jobs: | |
build: | |
runs-on: ubuntu-latest | |
strategy: | |
matrix: | |
python-version: ["3.11"] # we only need to lint once, select one Python version | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Python ${{ matrix.python-version }} | |
uses: actions/setup-python@v3 | |
with: | |
python-version: ${{ matrix.python-version }} | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install .[dev] | |
- name: Analyzing the code with pylint | |
run: | | |
# Create a timestamp for the output file | |
TIMESTAMP=$(date +"%Y%m%d_%H%M%S_%Z") | |
PYLINT_OUTPUT_FILE="pylint_output_${TIMESTAMP}.txt" | |
# Generate text report | |
pylint src/rattlesnake/**/*.py --output-format=text --reports=yes > "$PYLINT_OUTPUT_FILE" || true | |
# Extract the score from pylint output | |
SCORE=$(grep "Your code has been rated at" "$PYLINT_OUTPUT_FILE" | awk '{print $7}' | cut -d'/' -f1 || echo "0") | |
# Output the score and file name | |
echo "🏁 Pylint analysis completed. 🏁" | |
echo " 📄 Output file: $PYLINT_OUTPUT_FILE" | |
echo " 🏆 Pylint score: $SCORE out of 10" | |
echo "PYLINT_SCORE=$SCORE" >> $GITHUB_ENV | |
echo "PYLINT_OUTPUT_FILE=$PYLINT_OUTPUT_FILE" >> $GITHUB_ENV | |
# Determine badge color based on score and add it as an environment variable | |
python3 pylint_badge_color.py "$SCORE" | |
- name: Confirm new environment variables | |
run: | | |
echo "PYLINT_OUTPUT_FILE=${{ env.PYLINT_OUTPUT_FILE }}" | |
echo "PYLINT_SCORE=${{ env.PYLINT_SCORE }}" | |
echo "BADGE_COLOR=${{ env.BADGE_COLOR }}" | |
- name: Create custom Pylint Report in HTML format | |
run: | | |
# Read the pylint output and create a custom HTML report | |
# Saved to https://sandialabs.github.io/rattlesnake-vibration-controller/reports/pylint/ | |
python3 << 'EOF' | |
import os | |
import html | |
import re | |
from datetime import datetime | |
import pytz | |
# 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')})" | |
# print(formatted_time) # debugging | |
# Read pylint output | |
pylint_output_file = os.environ['PYLINT_OUTPUT_FILE'] | |
with open(pylint_output_file, 'r') as f: | |
pylint_content = f.read() | |
# Parse pylint output for better formatting | |
lines = pylint_content.split('\n') | |
issues = [] | |
summary_started = False | |
summary_lines = [] | |
for line in lines: | |
if line.startswith('************* Module'): | |
current_module = line.replace('************* Module ', '') | |
elif ':' in line and any(x in line for x in ['error', 'warning', 'convention', 'refactor']): | |
issues.append(line) | |
elif summary_started or 'Your code has been rated at' in line: | |
summary_started = True | |
summary_lines.append(line) | |
# Get environment variables | |
pylint_score = os.environ.get("PYLINT_SCORE", "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: | |
score_val = float(pylint_score) | |
if score_val >= 8: | |
score_color = "#28a745" | |
elif score_val >= 6: | |
score_color = "#ffc107" | |
else: | |
score_color = "#dc3545" | |
except: | |
score_color = "#6c757d" | |
# Count issues by type | |
error_count = len([i for i in issues if "error" in i.lower()]) | |
warning_count = len([i for i in issues if "warning" in i.lower()]) | |
convention_count = len([i for i in issues if "convention" in i.lower()]) | |
# Generate issues HTML | |
if not issues: | |
issues_html = "<p>No issues found! 🎉</p>" | |
else: | |
issues_list = [] | |
for issue in issues: | |
if "error" in issue.lower(): | |
css_class = "error" | |
elif "warning" in issue.lower(): | |
css_class = "warning" | |
elif "convention" in issue.lower(): | |
css_class = "convention" | |
else: | |
css_class = "refactor" | |
issues_list.append(f'<div class="issue {css_class}">{html.escape(issue)}</div>') | |
issues_html = f'<div class="issues-list">{"".join(issues_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>Pylint 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; | |
background: #808080; | |
}} | |
.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; | |
}} | |
.score {{ | |
font-size: 2.5em; font-weight: bold; color: {score_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; | |
}} | |
.issues-list {{ | |
max-height: 500px; overflow-y: auto; | |
border: 1px solid #e1e4e8; border-radius: 6px; | |
}} | |
.issue {{ | |
padding: 10px; border-bottom: 1px solid #e1e4e8; | |
font-family: 'SFMono-Regular', 'Consolas', monospace; | |
font-size: 0.9em; | |
}} | |
.issue:last-child {{ | |
border-bottom: none; | |
}} | |
.issue.error {{ background: #ffeef0; }} | |
.issue.warning {{ background: #fff8e1; }} | |
.issue.convention {{ background: #e8f4fd; }} | |
.issue.refactor {{ background: #f0f9ff; }} | |
.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; | |
}} </style> </head> <body> <div class="container"> | |
<div class="header"> | |
<h1>Rattlesnake Pylint Report</h1> | |
<div class="score">{pylint_score}/10</div> | |
<div class="metadata"> | |
<!--div><strong>Generated:</strong> {datetime.now().strftime("%Y-%m-%d %H:%M:%S UTC")}</div--> | |
<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[:7]}</div> | |
</div> | |
</div> | |
<div class="nav"> | |
<a href="#summary">Summary</a> | |
<a href="#issues">Issues ({len(issues)})</a> | |
<a href="#statistics">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">📊 Summary</h2> | |
<div class="summary">{"".join(summary_lines)}</div> | |
<div class="stats"> | |
<div class="stat-card"> | |
<div class="stat-number">{len(issues)}</div> | |
<div>Total Issues</div> | |
</div> | |
<div class="stat-card"> | |
<div class="stat-number">{error_count}</div> | |
<div>Errors</div> | |
</div> | |
<div class="stat-card"> | |
<div class="stat-number">{warning_count}</div> | |
<div>Warnings</div> | |
</div> | |
<div class="stat-card"> | |
<div class="stat-number">{convention_count}</div> | |
<div>Conventions</div> | |
</div> | |
</div> | |
</div> | |
<div class="section"> | |
<h2 id="issues">🔍 Issues Detail</h2> | |
{issues_html} | |
</div> | |
<div class="section"> | |
<h2 id="statistics">📈 Full Report</h2> | |
<details> | |
<summary>Click to view complete pylint output</summary> | |
<pre style="background: #f6f8fa; padding: 20px; border-radius: 6px; overflow-x: auto;">{html.escape(pylint_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('pylint_enhanced_report.html', 'w') as f: | |
f.write(html_content) | |
EOF | |
- name: Create custom Pylint Report in HTML format (version 2) | |
run: | | |
echo "Work in progress..." | |
# # Read the pylint output and create a custom HTML report | |
# # Saved to https://sandialabs.github.io/rattlesnake-vibration-controller/reports/pylint/ | |
# python pylint_html_report.py \ | |
# --input_file pylint_output_${{ env.TIMESTAMP }}.txt \ | |
# --output_file pylint_enhanced_report.html \ | |
# --pylint_score ${{ env.PYLINT_SCORE }} \ | |
# --run_id ${{ github.run_id }} \ | |
# --ref_name ${{ github.ref_name }} \ | |
# --github_sha ${{ github.sha }} \ | |
# --github_repo ${{ github.repository }} | |
- name: Prepare GitHub Pages main landing page content | |
if: github.ref == 'refs/heads/dev' # Only deploy on dev branch | |
run: | | |
# Create pages directory structure | |
mkdir -p pages/reports/pylint | |
# Copy the enhanced report as the main report | |
cp pylint_enhanced_report.html pages/reports/pylint/index.html | |
# Create a main index page for all reports located at | |
# https://sandialabs.github.io/rattlesnake-vibration-controller/ | |
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; | |
} | |
.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>📊 Pylint Report</h3> | |
<p>Static code analysis results showing code quality metrics, style compliance, and potential issues.</p> | |
<p><strong>Latest Score:</strong> ${{ env.PYLINT_SCORE }}/10</p> | |
<p><strong>Last Updated:</strong> $(formatted_time)</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: Create pylint badge with GitHub Pages link | |
# 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: | | |
# Create badges directory if it doesn't exist | |
mkdir -p badges | |
# Download badge using shields.io | |
curl -o badges/pylint.svg "https://img.shields.io/badge/pylint-${{ env.PYLINT_SCORE }}-${{ env.BADGE_COLOR }}.svg" | |
# Create badge metadata with GitHub Pages link | |
cat > badges/pylint-info.json << EOF | |
{ | |
"score": "${{ env.PYLINT_SCORE }}", | |
"color": "${{ env.BADGE_COLOR }}", | |
"pages_url": "https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/reports/pylint/", | |
"workflow_url": "${{ github.server_url }}/${{ github.repository }}/actions/workflows/pylint.yml", | |
"run_id": "${{ 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 pylint 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 config --local user.email "action@github.com" | |
git config --local user.name "GitHub Action" | |
git add badges/pylint.svg badges/pylint-info.json | |
git diff --staged --quiet || git commit -m "Update pylint badge [skip ci]" | |
git push | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- name: Upload pylint output as artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: pylint-output-${{ github.run_id }} | |
path: pylint_output*.txt | |
retention-days: 7 |