Skip to content

Comprehensive pre-commit hooks for Frappe Framework projects to enforce coding standards, security practices, and best practices automatically.

License

Notifications You must be signed in to change notification settings

dhwani-ris/frappe-pre-commit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🎯 Frappe Pre-commit

License: MIT Python 3.8+ Pre-commit

Comprehensive pre-commit hooks for Frappe Framework projects to enforce coding standards, security practices, and best practices automatically.

✨ Features

  • πŸ›‘οΈ SQL Injection Prevention - Detect and prevent SQL injection vulnerabilities
  • πŸ“ Coding Standards - Enforce Frappe-specific coding conventions and best practices
  • πŸ“ DocType Naming - Validate DocType and field naming conventions
  • ⚑ Fast Execution - Lightweight checks with minimal dependencies
  • 🎯 Customizable - Pick and choose hooks based on your project needs

πŸš€ Quick Start

System Requirements

  • Python: 3.8 or higher
  • pip: Latest version
  • pre-commit: Will be installed automatically
  • Git: For version control

Python Path Setup

If you encounter "Executable python not found" errors, ensure Python is properly configured:

# Check Python installation
python3 --version

# Create python symlink if needed (Linux/macOS)
sudo ln -s /usr/bin/python3 /usr/bin/python

# Or add alias to your shell profile (~/.bashrc, ~/.zshrc)
echo 'alias python=python3' >> ~/.bashrc
source ~/.bashrc

For New Frappe Projects

# 1. Initialize new Frappe app
bench new-app my_custom_app
cd apps/my_custom_app

# 2. Create .pre-commit-config.yaml
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/dhwani-ris/frappe-pre-commit/main/examples/.pre-commit-config.yaml

# 3. Install and run
pip install pre-commit
pre-commit install
pre-commit run --all-files

For Existing Frappe Projects

# 1. Navigate to your app directory
cd apps/your_app

# 2. Add .pre-commit-config.yaml (see configuration below)
# 3. Install pre-commit
pip install pre-commit
pre-commit install

# 4. Run on existing code
pre-commit run --all-files

πŸ“‹ Available Hooks

Hook ID Description Files Dependencies
frappe-coding-standards General coding standards and best practices *.py None
frappe-sql-security SQL injection and security checks *.py None
frappe-doctype-naming DocType and field naming conventions *.py, *.js, *.json pyyaml

βš™οΈ Configuration

Basic Configuration

Create .pre-commit-config.yaml in your project root:

repos:
  # Frappe-specific hooks
  - repo: https://github.com/dhwani-ris/frappe-pre-commit
    rev: v1.0.0  # Use latest tag
    hooks:
      - id: frappe-translation-check
      - id: frappe-sql-security
      - id: frappe-coding-standards

  # Code formatting (recommended)
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.8.1
    hooks:
      - id: ruff
        args: ["--select=I", "--fix"]  # Import sorting
      - id: ruff-format  # Code formatting

  # Additional quality checks
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-json

Complete Configuration

repos:
  # Python formatting and linting
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.8.1
    hooks:
      - id: ruff
        name: "Ruff import sorter"
        args: ["--select=I", "--fix"]
      - id: ruff
        name: "Ruff linter"
        args: ["--extend-ignore=E501"]
      - id: ruff-format
        name: "Ruff formatter"

  # JavaScript/CSS/JSON formatting
  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v4.0.0-alpha.8
    hooks:
      - id: prettier
        files: \.(js|jsx|ts|tsx|css|scss|json|md|yml|yaml)$
        exclude: |
          (?x)^(
              .*\.min\.(js|css)$|
              node_modules/.*|
              .*/static/.*
          )$

  # Basic file checks
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
        exclude: \.(md|rst)$
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-json
      - id: check-merge-conflict
      - id: debug-statements

  # Frappe-specific coding standards
  - repo: https://github.com/dhwani-ris/frappe-pre-commit
    rev: v1.0.0
    hooks:
      - id: frappe-coding-standards 

# Exclude patterns
exclude: |
  (?x)^(
      .*/migrations/.*|
      .*/patches/.*|
      .*\.min\.(js|css)$|
      node_modules/.*|
      __pycache__/.*
  )$

Selective Hook Usage

# Use only specific hooks you need
repos:
  - repo: https://github.com/dhwani-ris/frappe-pre-commit
    rev: v1.0.0
    hooks:
      - id: frappe-sql-security     # Only SQL security checks
      - id: frappe-translation-check # Only translation checks

πŸ” What Gets Checked

πŸ›‘οΈ SQL Security Checks

Detects:

  • SQL injection vulnerabilities using .format() or f-strings
  • String concatenation in SQL queries
  • Unencrypted storage of sensitive data (passwords, API keys)
# ❌ Will be flagged
frappe.db.sql("SELECT * FROM tabUser WHERE name = '{}'".format(user_name))
frappe.db.set_value("User", user, "password", plain_password)

# βœ… Correct approach
frappe.db.sql("SELECT * FROM tabUser WHERE name = %s", user_name)
frappe.db.set_value("User", user, "password", frappe.utils.password.encrypt(plain_password))

πŸ“ Coding Standards

Enforces:

  • Function length (≀20 lines recommended)
  • Proper indentation (tabs, not spaces)
  • Naming conventions (snake_case for functions, PascalCase for classes)
  • Import organization
  • Complexity limits (max nesting depth)

πŸ“ DocType Naming Conventions

Validates:

  • DocType names: Title Case with spaces ("Sales Order")
  • Field names: snake_case ("customer_name")
  • Field labels: Title Case ("Customer Name")

πŸ—οΈ Integration Examples

Integration with Bench

# For bench-managed projects
cd frappe-bench/apps/your_app

# Add pre-commit config
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/dhwani-ris/frappe-pre-commit/main/examples/.pre-commit-config.yaml

# Install globally in bench environment
~/frappe-bench/env/bin/pip install pre-commit
~/frappe-bench/env/bin/pre-commit install

Integration with GitHub Actions

Create .github/workflows/code-quality.yml:

name: Code Quality

on: [push, pull_request]

jobs:
  pre-commit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v4
        with:
          python-version: '3.10'
      - name: Install pre-commit
        run: pip install pre-commit
      - name: Run pre-commit
        run: pre-commit run --all-files

Integration with VS Code

Add to .vscode/settings.json:

{
  "python.linting.enabled": true,
  "python.linting.flake8Enabled": true,
  "python.formatting.provider": "black",
  "editor.formatOnSave": true,
  "python.sortImports.args": ["--profile", "black"],
  "[python]": {
    "editor.codeActionsOnSave": {
      "source.organizeImports": true
    }
  }
}

πŸ§ͺ Development and Testing

Setting Up Development Environment

# Clone the repository
git clone https://github.com/dhwani-ris/frappe-pre-commit.git
cd frappe-pre-commit

# Create virtual environment
python -m venv dev_env
source dev_env/bin/activate  # On Windows: dev_env\Scripts\activate

# Install development dependencies
pip install -r requirements-dev.txt
pip install pre-commit

# Install pre-commit hooks for this repository
pre-commit install

Running Tests

# Test individual scripts
python scripts/check_coding_standards.py test_files/sample.py
python scripts/check_sql_security.py test_files/sample.py
python scripts/check_translations.py test_files/sample.py

# Test all hooks
python test_scripts/test_all_hooks.py

# Test with pre-commit
pre-commit run --all-files

Creating Test Files

# Create test files with issues
mkdir test_project && cd test_project

# Create Python file with intentional issues
cat > bad_example.py << 'EOF'
import frappe

def very_long_function_that_violates_standards():
    frappe.msgprint("Missing translation wrapper")
    result = frappe.db.sql("SELECT * FROM tabUser WHERE name = '{}'".format("test"))
    return result
EOF

# Test your hooks
cd ../
python scripts/check_translations.py test_project/bad_example.py
python scripts/check_sql_security.py test_project/bad_example.py

Testing with Different Frappe Projects

# Test with ERPNext
cd path/to/erpnext
git clone https://github.com/dhwani-ris/frappe-pre-commit.git .pre-commit-hooks
cp .pre-commit-hooks/examples/.pre-commit-config.yaml .
pre-commit install
pre-commit run --all-files

# Test with custom app
cd path/to/your_custom_app
# Same process as above

Contributing

  1. Fork the repository
  2. Create feature branch: git checkout -b feature/new-check
  3. Add your hook script in scripts/
  4. Update .pre-commit-hooks.yaml
  5. Add tests in test_scripts/
  6. Update documentation
  7. Submit pull request

πŸ“š Examples

Example 1: Basic Frappe App Setup

# Create new app
cd frappe-bench
bench new-app inventory_management
cd apps/inventory_management

# Add pre-commit
cat > .pre-commit-config.yaml << 'EOF'
repos:
  - repo: https://github.com/dhwani-ris/frappe-pre-commit
    rev: v1.0.0
    hooks:
      - id: frappe-quick-check
EOF

# Install and test
pip install pre-commit
pre-commit install
pre-commit run --all-files

Example 2: ERPNext Customization

# For ERPNext customizations
cd frappe-bench/apps/erpnext

# Use comprehensive config
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/dhwani-ris/frappe-pre-commit/main/examples/erpnext-config.yaml

pre-commit install
pre-commit run --all-files

Example 3: CI/CD Integration

# .github/workflows/quality-check.yml
name: Quality Check

on:
  pull_request:
    branches: [main, develop]

jobs:
  code-quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.10'
      
      - name: Install dependencies
        run: |
          pip install pre-commit
          pip install -r requirements.txt
      
      - name: Run pre-commit
        run: pre-commit run --all-files
      
      - name: Comment PR
        if: failure()
        uses: actions/github-script@v6
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '❌ Code quality checks failed. Please run `pre-commit run --all-files` locally and fix the issues.'
            })

πŸ”§ Troubleshooting

Common Issues

Pre-commit hooks not running:

pre-commit uninstall
pre-commit install
pre-commit run --all-files

Python executable not found error:

# Error: Executable `python` not found
# Solution: Create a python symlink or alias

# Option 1: Create symlink (Linux/macOS)
sudo ln -s /usr/bin/python3 /usr/bin/python

# Option 2: Create alias (add to ~/.bashrc or ~/.zshrc)
alias python=python3

# Option 3: Use python3 explicitly in PATH
export PATH="/usr/bin:$PATH"

# Option 4: Install python-is-python3 package (Ubuntu/Debian)
sudo apt install python-is-python3

# After fixing, reinstall pre-commit hooks
pre-commit uninstall
pre-commit install

Hooks failing on large files:

# Skip hooks for specific commit
git commit -m "Large file update" --no-verify

# Or exclude large files in config
# Add to .pre-commit-config.yaml:
exclude: |
  (?x)^(
      large_files/.*|
      .*\.min\.js$
  )$

Import errors in scripts:

# Make sure Python can find the scripts
export PYTHONPATH="${PYTHONPATH}:$(pwd)"

Package installation issues:

# If frappe-pre-commit package fails to install automatically
pip install frappe-pre-commit

# Clear pre-commit cache and reinstall
pre-commit clean
pre-commit install

Performance Tips

# Cache pre-commit environments
export PRE_COMMIT_HOME=~/.cache/pre-commit

# Run only on changed files
pre-commit run

# Skip slow hooks during development
PRE_COMMIT_SKIP=frappe-all-checks git commit -m "Quick fix"

🀝 Contributing

We welcome contributions!

Quick Contribution Steps

  1. Fork the repository
  2. Clone your fork: git clone https://github.com/yourusername/frappe-pre-commit.git
  3. Create branch: git checkout -b feature/improvement
  4. Make changes and test thoroughly
  5. Submit pull request

For Developers

If you want to contribute to the package development, testing, or publishing, see DEVELOPER.md for detailed instructions on:

  • Setting up the development environment
  • Testing changes locally
  • Publishing updates to PyPI
  • Version management
  • Troubleshooting

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

🏒 About

Maintained by Dhwani RIS


Ready to improve your Frappe code quality? Get started with Frappe-Pre-commit today! πŸš€

# Install pre-commit
pip install pre-commit

# Download the pre-commit configuration
curl -o .pre-commit-config.yaml https://raw.githubusercontent.com/dhwani-ris/frappe-pre-commit/main/examples/.pre-commit-config.yaml

# Install the pre-commit hooks (frappe-pre-commit package will be installed automatically)
pre-commit install

# Run all checks
pre-commit run --all-files

Note: If you encounter "Executable python not found" errors, see the Python Path Setup section above.

About

Comprehensive pre-commit hooks for Frappe Framework projects to enforce coding standards, security practices, and best practices automatically.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages