name: Code Quality on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] schedule: # Run weekly code quality checks - cron: '0 2 * * 1' jobs: lint: name: Linting and formatting runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Cache pip dependencies uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-lint-${{ hashFiles('**/pyproject.toml') }} restore-keys: | ${{ runner.os }}-pip-lint- ${{ runner.os }}-pip- - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e . pip install flake8 pylint - name: Run Black formatting check run: | black --check --diff elevator_saga tests - name: Run isort import sorting check run: | isort --check-only --diff elevator_saga tests - name: Run flake8 run: | flake8 elevator_saga tests --count --select=E9,F63,F7,F82 --show-source --statistics flake8 elevator_saga tests --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics - name: Run pylint run: | pylint elevator_saga --exit-zero --output-format=parseable --reports=no | tee pylint-report.txt - name: Upload lint reports uses: actions/upload-artifact@v3 with: name: lint-reports path: | pylint-report.txt if: always() type-check: name: Type checking runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e . - name: Run mypy type checking run: | mypy elevator_saga --html-report mypy-report --txt-report mypy-report - name: Upload type check reports uses: actions/upload-artifact@v3 with: name: type-check-reports path: mypy-report/ if: always() complexity: name: Code complexity analysis runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: | python -m pip install --upgrade pip pip install radon xenon - name: Run cyclomatic complexity check run: | radon cc elevator_saga --min B --total-average - name: Run maintainability index run: | radon mi elevator_saga --min B - name: Run complexity with xenon run: | xenon --max-absolute B --max-modules B --max-average A elevator_saga continue-on-error: true dependencies: name: Dependency analysis runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e . pip install pip-audit pipdeptree - name: Generate dependency tree run: | pipdeptree --freeze > requirements-freeze.txt pipdeptree --graph-output png > dependency-graph.png - name: Check for known vulnerabilities run: | pip-audit --format=json --output=vulnerability-report.json continue-on-error: true - name: Upload dependency reports uses: actions/upload-artifact@v3 with: name: dependency-reports path: | requirements-freeze.txt dependency-graph.png vulnerability-report.json if: always() documentation: name: Documentation quality runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e . pip install pydocstyle interrogate - name: Check docstring style run: | pydocstyle elevator_saga --count --explain --source continue-on-error: true - name: Check docstring coverage run: | interrogate elevator_saga --ignore-init-method --ignore-magic --ignore-module --ignore-nested-functions --fail-under=70 continue-on-error: true pre-commit: name: Pre-commit hooks runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install pre-commit run: | python -m pip install --upgrade pip pip install pre-commit - name: Cache pre-commit uses: actions/cache@v3 with: path: ~/.cache/pre-commit key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} - name: Run pre-commit hooks run: | pre-commit run --all-files --show-diff-on-failure continue-on-error: true summary: name: Quality summary runs-on: ubuntu-latest needs: [lint, type-check, complexity, dependencies, documentation, pre-commit] if: always() steps: - name: Create quality report run: | echo "## 📊 Code Quality Report" >> $GITHUB_STEP_SUMMARY echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY # Format results if [ "${{ needs.lint.result }}" = "success" ]; then echo "| Linting | ✅ Passed |" >> $GITHUB_STEP_SUMMARY else echo "| Linting | ❌ Failed |" >> $GITHUB_STEP_SUMMARY fi if [ "${{ needs.type-check.result }}" = "success" ]; then echo "| Type Check | ✅ Passed |" >> $GITHUB_STEP_SUMMARY else echo "| Type Check | ❌ Failed |" >> $GITHUB_STEP_SUMMARY fi if [ "${{ needs.complexity.result }}" = "success" ]; then echo "| Complexity | ✅ Passed |" >> $GITHUB_STEP_SUMMARY else echo "| Complexity | ⚠️ Warning |" >> $GITHUB_STEP_SUMMARY fi if [ "${{ needs.dependencies.result }}" = "success" ]; then echo "| Dependencies | ✅ Secure |" >> $GITHUB_STEP_SUMMARY else echo "| Dependencies | ⚠️ Check needed |" >> $GITHUB_STEP_SUMMARY fi if [ "${{ needs.documentation.result }}" = "success" ]; then echo "| Documentation | ✅ Good |" >> $GITHUB_STEP_SUMMARY else echo "| Documentation | ⚠️ Needs improvement |" >> $GITHUB_STEP_SUMMARY fi if [ "${{ needs.pre-commit.result }}" = "success" ]; then echo "| Pre-commit | ✅ Passed |" >> $GITHUB_STEP_SUMMARY else echo "| Pre-commit | ⚠️ Some hooks failed |" >> $GITHUB_STEP_SUMMARY fi echo "" >> $GITHUB_STEP_SUMMARY echo "📈 **Overall Quality:** ${{ needs.lint.result == 'success' && needs.type-check.result == 'success' && 'Good' || 'Needs attention' }}" >> $GITHUB_STEP_SUMMARY