| name: Code Quality |
|
|
| on: |
| push: |
| branches: |
| - main |
| - dev |
| paths-ignore: |
| - '*.md' |
| - '**/*.md' |
| - 'docs/**' |
| - 'images/**' |
| - '.github/**' |
| - 'agent-skill/**' |
| - '!.github/workflows/code-quality.yml' |
| pull_request: |
| branches: |
| - main |
| - dev |
| paths-ignore: |
| - '*.md' |
| - '**/*.md' |
| - 'docs/**' |
| - 'images/**' |
| - '.github/**' |
| - 'agent-skill/**' |
| - '*.yml' |
| - '*.yaml' |
| - 'ruff.toml' |
| workflow_dispatch: |
|
|
| concurrency: |
| group: ${{ github.workflow }}-${{ github.ref }} |
| cancel-in-progress: true |
|
|
| jobs: |
| code-quality: |
| name: Code Quality Checks |
| runs-on: ubuntu-latest |
| permissions: |
| contents: read |
| pull-requests: write |
|
|
| steps: |
| - name: Checkout code |
| uses: actions/checkout@v6 |
| with: |
| fetch-depth: 0 |
|
|
| - name: Set up Python |
| uses: actions/setup-python@v6 |
| with: |
| python-version: '3.10' |
| cache: 'pip' |
|
|
| - name: Install dependencies |
| run: | |
| python -m pip install --upgrade pip |
| pip install bandit[toml] ruff vermin mypy pyright |
| pip install -e ".[all]" |
| pip install lxml-stubs |
| |
| - name: Run Bandit (Security Linter) |
| id: bandit |
| continue-on-error: true |
| run: | |
| echo "::group::Bandit - Security Linter" |
| bandit -r -c .bandit.yml scrapling/ -f json -o bandit-report.json |
| bandit -r -c .bandit.yml scrapling/ |
| echo "::endgroup::" |
| |
| - name: Run Ruff Linter |
| id: ruff-lint |
| continue-on-error: true |
| run: | |
| echo "::group::Ruff - Linter" |
| ruff check scrapling/ --output-format=github |
| echo "::endgroup::" |
| |
| - name: Run Ruff Formatter Check |
| id: ruff-format |
| continue-on-error: true |
| run: | |
| echo "::group::Ruff - Formatter Check" |
| ruff format --check scrapling/ --diff |
| echo "::endgroup::" |
| |
| - name: Run Vermin (Python Version Compatibility) |
| id: vermin |
| continue-on-error: true |
| run: | |
| echo "::group::Vermin - Python 3.10+ Compatibility Check" |
| vermin -t=3.10- --violations --eval-annotations --no-tips scrapling/ |
| echo "::endgroup::" |
| |
| - name: Run Mypy (Static Type Checker) |
| id: mypy |
| continue-on-error: true |
| run: | |
| echo "::group::Mypy - Static Type Checker" |
| mypy scrapling/ |
| echo "::endgroup::" |
| |
| - name: Run Pyright (Static Type Checker) |
| id: pyright |
| continue-on-error: true |
| run: | |
| echo "::group::Pyright - Static Type Checker" |
| pyright scrapling/ |
| echo "::endgroup::" |
| |
| - name: Check results and create summary |
| if: always() |
| run: | |
| echo "# Code Quality Check Results" >> $GITHUB_STEP_SUMMARY |
| echo "" >> $GITHUB_STEP_SUMMARY |
| |
| |
| all_passed=true |
|
|
| |
| if [ "${{ steps.bandit.outcome }}" == "success" ]; then |
| echo "β
**Bandit (Security)**: Passed" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "β **Bandit (Security)**: Failed" >> $GITHUB_STEP_SUMMARY |
| all_passed=false |
| fi |
|
|
| |
| if [ "${{ steps.ruff-lint.outcome }}" == "success" ]; then |
| echo "β
**Ruff Linter**: Passed" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "β **Ruff Linter**: Failed" >> $GITHUB_STEP_SUMMARY |
| all_passed=false |
| fi |
|
|
| |
| if [ "${{ steps.ruff-format.outcome }}" == "success" ]; then |
| echo "β
**Ruff Formatter**: Passed" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "β **Ruff Formatter**: Failed" >> $GITHUB_STEP_SUMMARY |
| all_passed=false |
| fi |
|
|
| |
| if [ "${{ steps.vermin.outcome }}" == "success" ]; then |
| echo "β
**Vermin (Python 3.10+)**: Passed" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "β **Vermin (Python 3.10+)**: Failed" >> $GITHUB_STEP_SUMMARY |
| all_passed=false |
| fi |
|
|
| |
| if [ "${{ steps.mypy.outcome }}" == "success" ]; then |
| echo "β
**Mypy (Type Checker)**: Passed" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "β **Mypy (Type Checker)**: Failed" >> $GITHUB_STEP_SUMMARY |
| all_passed=false |
| fi |
|
|
| |
| if [ "${{ steps.pyright.outcome }}" == "success" ]; then |
| echo "β
**Pyright (Type Checker)**: Passed" >> $GITHUB_STEP_SUMMARY |
| else |
| echo "β **Pyright (Type Checker)**: Failed" >> $GITHUB_STEP_SUMMARY |
| all_passed=false |
| fi |
|
|
| echo "" >> $GITHUB_STEP_SUMMARY |
|
|
| if [ "$all_passed" == "true" ]; then |
| echo "### π All checks passed!" >> $GITHUB_STEP_SUMMARY |
| echo "" >> $GITHUB_STEP_SUMMARY |
| echo "Your code meets all quality standards." >> $GITHUB_STEP_SUMMARY |
| else |
| echo "### β οΈ Some checks failed" >> $GITHUB_STEP_SUMMARY |
| echo "" >> $GITHUB_STEP_SUMMARY |
| echo "Please review the errors above and fix them." >> $GITHUB_STEP_SUMMARY |
| echo "" >> $GITHUB_STEP_SUMMARY |
| echo "**Tip**: Run \`pre-commit run --all-files\` locally to catch these issues before pushing." >> $GITHUB_STEP_SUMMARY |
| exit 1 |
| fi |
|
|
| - name: Upload Bandit report |
| if: always() && steps.bandit.outcome != 'skipped' |
| uses: actions/upload-artifact@v6 |
| with: |
| name: bandit-security-report |
| path: bandit-report.json |
| retention-days: 30 |
|
|