Skip to content

refine api to be more declarative and consistent #64

refine api to be more declarative and consistent

refine api to be more declarative and consistent #64

Workflow file for this run

name: pylint
on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v3
with:
python-version: "3.11"
- 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 (deprecated)
run: |
echo "Deprecated"
## 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, to be saved to
# https://sandialabs.github.io/rattlesnake-vibration-controller/reports/pylint/
python pylint_report.py \
--input_file ${{ env.PYLINT_OUTPUT_FILE }} \
--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