[ANALYSIS] Code Quality Analysis #32
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: "[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 |