Skip to content

MarDuer/uvx-pre-commit-hooks-poc

Repository files navigation

Custom Pre-commit Hooks with uvx

Blueprint for creating and distributing custom pre-commit hooks using uvx.

🎯 What's This?

This repository demonstrates how to:

  • Build a central repository of custom pre-commit hooks
  • Distribute hooks as a Python package
  • Consume hooks in target projects via pre-commit
  • Version and evolve hooks over time

📦 What's Included

Hooks Repository (hooks-repo/)

A Python package with 4 custom hooks:

  • no-print-statements: Detect print() in Python code
  • check-yaml-syntax: Validate YAML files
  • check-secrets: Detect potential secrets/credentials
  • check-markdown-links: Validate Markdown links

Target Project (target-project/)

Example project showing how to consume the hooks with intentional violations for testing.

🚀 Quick Start

Try the Example

# 1. Navigate to target project
cd target-project

# 2. Run hooks (using uvx - no installation needed!)
uvx pre-commit run --all-files

# You'll see:
# ❌ Print statements detected in src/app.py
# ❌ Invalid YAML in config/invalid.yaml
# ❌ Secrets detected in src/config.py
# ❌ Broken links in docs/README.md

Use in Your Project

# 1. Add to your .pre-commit-config.yaml
cat > .pre-commit-config.yaml << 'EOF'
repos:
  - repo: https://github.com/MarDuer/uvx-pre-commit-hooks-poc.git
    rev: v0.2.0
    hooks:
      - id: no-print-statements
      - id: check-yaml-syntax
      - id: check-secrets
      - id: check-markdown-links
EOF

# 2. Install hooks
uvx pre-commit install

# 3. Run manually (optional)
uvx pre-commit run --all-files

📖 Documentation

🏗️ Architecture

┌─────────────────────────────────────────────────────────┐
│                   Hooks Repository                       │
│  (Python package with CLI entry points)                 │
│                                                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐ │
│  │ check_no_    │  │ check_yaml   │  │ check_       │ │
│  │ print.py     │  │ .py          │  │ secrets.py   │ │
│  └──────────────┘  └──────────────┘  └──────────────┘ │
│                                                          │
│  pyproject.toml: Defines entry points                   │
│  .pre-commit-hooks.yaml: Hook metadata                  │
└─────────────────────────────────────────────────────────┘
                           │
                           │ Referenced by
                           ▼
┌─────────────────────────────────────────────────────────┐
│                   Target Project                         │
│                                                          │
│  .pre-commit-config.yaml:                               │
│    repos:                                                │
│      - repo: /path/to/hooks-repo                        │
│        rev: v0.2.0                                       │
│        hooks:                                            │
│          - id: no-print-statements                       │
│                                                          │
│  pyproject.toml:                                         │
│    [tool.custom-hooks.no-print]                         │
│    exclude_patterns = ["# debug"]                       │
└─────────────────────────────────────────────────────────┘

🎓 Key Concepts

1. Entry Points

Python packages can define CLI commands via [project.scripts]:

[project.scripts]
my-command = "package.module:main"

2. Pre-commit Integration

Pre-commit discovers hooks via .pre-commit-hooks.yaml:

- id: my-hook
  entry: my-command
  language: python

3. Configuration

Hooks support both CLI args and config files:

# CLI args
hooks:
  - id: my-hook
    args: [--option, value]
# Config file
[tool.custom-hooks.my-hook]
option = "value"

🔄 Version Evolution

This blueprint shows two versions:

v0.1.0: Basic hooks (no-print, yaml) v0.2.0: Added security (secrets) and docs (markdown-links)

See git tags:

cd hooks-repo
git tag -l
# v0.1.0
# v0.2.0

🛠️ Creating Your Own Hook

# 1. Create hook module
cat > hooks-repo/src/custom_hooks/my_hook.py << 'EOF'
import sys
def main():
    print("My hook!")
    return 0
if __name__ == "__main__":
    sys.exit(main())
EOF

# 2. Add entry point
# Edit hooks-repo/pyproject.toml:
# [project.scripts]
# my-hook = "custom_hooks.my_hook:main"

# 3. Add hook definition
# Edit hooks-repo/.pre-commit-hooks.yaml:
# - id: my-hook
#   name: My Hook
#   entry: my-hook
#   language: python

# 4. Version and tag
cd hooks-repo
git add .
git commit -m "Add my-hook"
git tag v0.3.0

💡 Use Cases

  • Team Standards: Enforce coding conventions
  • Security: Detect secrets, unsafe patterns
  • Documentation: Validate links, check formatting
  • Quality: Check test coverage, docstrings
  • Compliance: Ensure license headers, file naming

🤔 Why This Approach?

Centralized: One repo for all team hooks ✅ Versioned: Use git tags for releases ✅ Flexible: CLI args + config file support ✅ Fast: uvx caches installations ✅ Isolated: Each hook runs in its own environment ✅ Reusable: Share across multiple projects

📊 Project Status

This is a complete working example demonstrating:

  • ✅ Hook implementation patterns
  • ✅ Configuration support (CLI + file)
  • ✅ Version management (v0.1.0 → v0.2.0)
  • ✅ Multiple hook types (Python, YAML, Markdown, Security)
  • ✅ Target project integration
  • ✅ Comprehensive documentation

🤝 Contributing

This is a blueprint/template. Fork and adapt for your needs!

Ideas for additional hooks:

  • check-docstrings
  • check-imports
  • check-file-size
  • check-branch-name
  • check-commit-message
  • check-license-headers

📄 License

MIT - Use freely!


Ready to dive deeper? Read BLUEPRINT.md for the complete guide.

About

Central repository with uvx pre-commit hooks - proof of concept

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors