Skip to content

[ANALYSIS] Code Quality Analysis #32

[ANALYSIS] Code Quality Analysis

[ANALYSIS] Code Quality Analysis #32

Workflow file for this run

name: "[ANALYSIS] Code Quality Analysis"
on:
pull_request:
branches: [ main, develop ]
push:
branches: [ main, develop ]
schedule:
# Run weekly code quality analysis
- cron: '0 6 * * 0'
workflow_dispatch:
permissions:
contents: read
pull-requests: write
issues: write
env:
PYTHON_VERSION: '3.9'
jobs:
# Code Quality Metrics
code-quality:
name: "[ANALYSIS] Code Quality Metrics"
runs-on: ubuntu-latest
steps:
- name: "[CHECKOUT] Checkout Code"
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: "[PYTHON] Set up Python"
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: "[INSTALL] Install Dependencies"
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
# Install Node.js tools separately
sudo apt-get update
sudo apt-get install -y nodejs npm
npm install -g markdownlint-cli2
# Install system tools for license checking
sudo apt-get install -y licensecheck
- name: "[ANALYSIS] Code Complexity Analysis (Radon)"
run: |
echo "## Code Complexity Report" > complexity-report.md
echo "### Cyclomatic Complexity" >> complexity-report.md
radon cc syspilot/ --average --show-complexity | tee -a complexity-report.md || echo "Radon CC analysis failed" >> complexity-report.md
echo "" >> complexity-report.md
echo "### Maintainability Index" >> complexity-report.md
radon mi syspilot/ --show --sort | tee -a complexity-report.md || echo "Radon MI analysis failed" >> complexity-report.md
echo "" >> complexity-report.md
echo "### Raw Metrics" >> complexity-report.md
radon raw syspilot/ | tee -a complexity-report.md || echo "Radon raw analysis failed" >> complexity-report.md
- name: "[ANALYSIS] Code Quality Score (Xenon)"
run: |
echo "## Code Quality Score" >> complexity-report.md
xenon --max-absolute A --max-modules A --max-average A syspilot/ | tee -a complexity-report.md || echo "Xenon analysis failed" >> complexity-report.md
- name: "[ANALYSIS] License Check"
run: |
echo "## License Compliance" > license-report.md
if command -v licensecheck >/dev/null 2>&1; then
licensecheck --zero-projects-is-okay syspilot/ | tee -a license-report.md || true
else
echo "License check tool not available" >> license-report.md
fi
- name: "[ANALYSIS] Code Duplication Check"
run: |
echo "## Code Duplication Analysis" > duplication-report.md
# Using pylint for duplicate code detection
pylint syspilot/ --disable=all --enable=duplicate-code --reports=yes | tee -a duplication-report.md || true
- name: "[UPLOAD] Upload Quality Reports"
uses: actions/upload-artifact@v4
with:
name: code-quality-reports
path: |
complexity-report.md
license-report.md
duplication-report.md
# Performance Analysis
performance-analysis:
name: "[PERFORMANCE] Performance Analysis"
runs-on: ubuntu-latest
steps:
- name: "[CHECKOUT] Checkout Code"
uses: actions/checkout@v4
- name: "[PYTHON] Set up Python"
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: "[DISPLAY] Setup Display"
run: |
sudo apt-get update
sudo apt-get install -y xvfb libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0
export DISPLAY=:99
Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
- name: "[INSTALL] Install Dependencies"
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: "[PERFORMANCE] Memory Profiling"
env:
DISPLAY: :99
QT_QPA_PLATFORM: offscreen
run: |
echo "## Memory Profile Report" > performance-report.md
echo "### Application Startup Memory Usage" >> performance-report.md
mprof run python -c "
import syspilot
from syspilot.platforms import get_platform
from syspilot.platforms.factory import PlatformFactory
platform_name = get_platform()
print(f'Platform: {platform_name}')
print(f'Platform supported: {PlatformFactory.is_current_platform_supported()}')
" || true
mprof plot --output=memory-profile.png || true
echo "Memory profile completed" >> performance-report.md
- name: "[PERFORMANCE] Performance Benchmarks"
env:
DISPLAY: :99
QT_QPA_PLATFORM: offscreen
run: |
echo "### Import Time Analysis" >> performance-report.md
python -c "
import time
start = time.time()
import syspilot
import_time = time.time() - start
print(f'Import time: {import_time:.4f} seconds')
print(f'Import time: {import_time:.4f} seconds' >> 'performance-report.md')
" || true
- name: "[UPLOAD] Upload Performance Reports"
uses: actions/upload-artifact@v4
with:
name: performance-reports
path: |
performance-report.md
memory-profile.png
mprofile_*.dat
# Documentation Quality Check
docs-quality:
name: "[DOCS] Documentation Quality"
runs-on: ubuntu-latest
steps:
- name: "[CHECKOUT] Checkout Code"
uses: actions/checkout@v4
- name: "[PYTHON] Set up Python"
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- name: "[INSTALL] Install Dependencies"
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-dev.txt
- name: "[DOCS] Docstring Coverage"
run: |
echo "## Documentation Coverage Report" > docs-report.md
echo "### Docstring Coverage" >> docs-report.md
python -c "
import ast
import os
def count_docstrings(directory):
total_functions = 0
documented_functions = 0
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith('.py'):
filepath = os.path.join(root, file)
try:
with open(filepath, 'r', encoding='utf-8') as f:
tree = ast.parse(f.read())
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
total_functions += 1
if ast.get_docstring(node):
documented_functions += 1
except:
continue
return total_functions, documented_functions
total, documented = count_docstrings('syspilot')
coverage = (documented / total * 100) if total > 0 else 0
print(f'Total functions/classes: {total}')
print(f'Documented: {documented}')
print(f'Coverage: {coverage:.1f}%')
with open('docs-report.md', 'a') as f:
f.write(f'- Total functions/classes: {total}\n')
f.write(f'- Documented: {documented}\n')
f.write(f'- Coverage: {coverage:.1f}%\n\n')
" || true
- name: "[DOCS] README Quality Check"
run: |
echo "### README Quality" >> docs-report.md
if [ -f README.md ]; then
# Count lines in README.md
lines=$(wc -l < README.md)
echo "- Lines: $lines" >> docs-report.md
# Count sections (lines starting with #)
sections=$(grep -c '^#' README.md || echo "0")
echo "- Sections: $sections" >> docs-report.md
echo "[SUCCESS] README.md exists" >> docs-report.md
else
echo "[FAILED] README.md missing" >> docs-report.md
fi
- name: "[UPLOAD] Upload Documentation Reports"
uses: actions/upload-artifact@v4
with:
name: documentation-reports
path: docs-report.md
# Quality Summary
quality-summary:
name: "[CHECK] Quality Summary"
runs-on: ubuntu-latest
needs: [code-quality, performance-analysis, docs-quality]
if: always()
steps:
- name: "[CHECKOUT] Download All Reports"
uses: actions/download-artifact@v4
with:
path: reports/
- name: "[CHECK] Generate Quality Summary"
run: |
echo "# [ANALYSIS] Code Quality Summary" > quality-summary.md
echo "" >> quality-summary.md
echo "Generated on: $(date)" >> quality-summary.md
echo "" >> quality-summary.md
# Combine all reports
if [ -d "reports" ]; then
for report_dir in reports/*/; do
echo "## $(basename $report_dir | sed 's/-/ /g' | sed 's/\b\w/\U&/g')" >> quality-summary.md
for file in $report_dir*.md; do
if [ -f "$file" ]; then
cat "$file" >> quality-summary.md
echo "" >> quality-summary.md
fi
done
done
fi
echo "## Job Status" >> quality-summary.md
echo "- Code Quality: ${{ needs.code-quality.result }}" >> quality-summary.md
echo "- Performance Analysis: ${{ needs.performance-analysis.result }}" >> quality-summary.md
echo "- Documentation Quality: ${{ needs.docs-quality.result }}" >> quality-summary.md
- name: "[UPLOAD] Upload Quality Summary"
uses: actions/upload-artifact@v4
with:
name: quality-summary
path: quality-summary.md
- name: "[COMMENT] Comment on PR"
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
if (fs.existsSync('quality-summary.md')) {
const summary = fs.readFileSync('quality-summary.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
});
}
# Pre-commit Hook Updates
pre-commit-autoupdate:
name: "[UPDATE] Update Pre-commit Hooks"
runs-on: ubuntu-latest
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
steps:
- name: "[CHECKOUT] Checkout Code"
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: "[PYTHON] Set up Python"
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: "[INSTALL] Install pre-commit"
run: |
python -m pip install --upgrade pip
pip install pre-commit
- name: "[UPDATE] Update pre-commit hooks"
run: |
pre-commit autoupdate
- name: "[TEST] Test updated hooks"
run: |
pre-commit run --all-files || echo "Some hooks failed but that's expected"
- name: "[CREATE] Create Pull Request"
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore(hooks): update pre-commit hooks"
title: "[UPDATE] Update pre-commit hooks"
body: |
## Pre-commit Hook Updates
This PR updates pre-commit hooks to their latest versions.
### Changes
- Updated hook versions in `.pre-commit-config.yaml`
### Testing
- [ ] All updated hooks have been tested
- [ ] Code quality checks pass
**Auto-generated by GitHub Actions**
branch: update/pre-commit-hooks
labels: |
dependencies
pre-commit
automated
delete-branch: true