Skip to main content

CLI tool for enforcing development guidelines

Project description

DevRules Logo

DevRules

Automate your internal rules. Reduce errors. Accelerate onboarding.

PyPI version Python Versions License: BSL 1.1 Documentation Status

📜 License

DevRules is licensed under the Business Source License 1.1 (BSL).

What this means:

  • Free for small companies - Organizations with < 100 employees can use in production
  • Free for non-production - Anyone can use for development, testing, and evaluation
  • Source available - Full source code is visible and modifiable
  • Becomes open source - Converts to Apache 2.0 license on 2029-12-06 (4 years)
  • 💼 Commercial license available - For larger organizations or production use beyond the grant

Need a commercial license? Contact pedroifgonzalez@gmail.com

See LICENSE for full details.


🎬 Demo

Branch Name Validation

Branch Name Validation

Run Custom Rules

Run Custom Rules

Custom Rules with Lifecycle Hooks

Custom Rules with Lifecycle Hooks

🚀 Features

  • Branch naming validation - Enforce consistent branch naming conventions
  • Commit message format checking - Validate commit message structure with GPG signing support
  • Pull Request validation - Check PR size and title format
  • Deployment workflow - Manage deployments across environments with Jenkins integration
  • ⚙️ Configurable via TOML - Customize all rules to match your workflow
  • 🔌 Git hooks integration - Automatic validation with pre-commit support
  • 🎨 Interactive mode with Gum - Beautiful terminal UI with arrow-key selection and styled prompts
  • 🌐 GitHub API integration - Manage issues, projects, and PRs directly
  • 📊 TUI Dashboard - Interactive terminal dashboard for metrics and issue tracking
  • 🏢 Enterprise builds - Create custom packages with embedded corporate configuration
  • 🛠️ Custom Rules Engine - Define and run your own validation functions
  • 🪝 Lifecycle Hooks - Attach custom rules to events (pre-commit, pre-deploy, etc.)

📦 Installation

pip install devrules

Optional: Install Gum for Enhanced UI

DevRules integrates with Gum for a beautiful interactive terminal experience. Install it for:

  • Arrow-key selection menus
  • Styled input prompts
  • Formatted tables
  • Colorful output
# macOS
brew install gum

# Linux (Debian/Ubuntu)
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg
echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list
sudo apt update && sudo apt install gum

# Windows (Scoop)
scoop install charm-gum

Note: Gum is optional. DevRules falls back to standard prompts if Gum is not installed.

🎯 Quick Start

  1. Initialize configuration:
devrules init-config
  1. Create a branch interactively:
devrules create-branch
  1. Validate a branch name:
devrules check-branch feature/123-new-feature
  1. Validate a commit message:
devrules check-commit .git/COMMIT_EDITMSG
  1. Validate a Pull Request:
export GH_TOKEN=your_github_token
devrules check-pr 42 --owner your-org --repo your-repo
# Or configure owner/repo in .devrules.toml and just run:
devrules check-pr 42
  1. Deploy to an environment:
# Configure deployment settings in .devrules.toml first
devrules deploy dev --branch feature/123-new-feature

# Or check deployment readiness without deploying
devrules check-deployment staging
  1. Launch the TUI Dashboard:
# Install with TUI support first
pip install "devrules[tui]"

# Run the dashboard
devrules dashboard
  1. Manage GitHub Issues:
# List issues from a project
devrules list-issues --project 6

# View issue details
devrules describe-issue 123

# Update issue status
devrules update-issue-status 123 --status "In Progress" --project 6
  1. Commit with validation:
devrules commit "[FTR] Add new feature"

⚙️ Configuration

Create a .devrules.toml file in your project root:

[branch]
pattern = "^(feature|bugfix|hotfix|release|docs)/(\\d+-)?[a-z0-9-]+"
prefixes = ["feature", "bugfix", "hotfix", "release", "docs"]

[commit]
tags = ["WIP", "FTR", "FIX", "DOCS", "TST"]
pattern = "^\\[({tags})\\].+"
min_length = 10
max_length = 100
gpg_sign = false  # Sign commits with GPG
protected_branch_prefixes = ["staging-"]  # Block direct commits to these branches
enable_ai_suggestions = false  # Generate AI-powered commit message suggestions (requires diny)

[pr]
max_loc = 400
max_files = 20
require_title_tag = true

[github]
owner = "your-org"
repo = "your-repo"

For a complete configuration example, run devrules init-config.

AI-Powered Commit Messages

⚠️ Security Notice: When enable_ai_suggestions = true, your staged changes, diffs, and repository metadata may be sent to an external AI service (diny). Ensure you review the data handling policies and have appropriate consent before enabling this feature. Sensitive content such as credentials, secrets, or PII should not be present in your staged changes when using AI suggestions.

When enable_ai_suggestions = true is set in the [commit] section, DevRules can generate AI-powered commit message suggestions using the diny tool.

How it works:

  • During commits, DevRules automatically generates a commit message suggestion based on your staged changes
  • The AI-generated message appears as a default value that you can edit or replace
  • Requires diny to be installed and available in your PATH
  • Default is disabled for security - you must explicitly enable it

Security Considerations:

  • Review diny's privacy policy and data handling practices
  • Ensure no sensitive information is in staged changes when using AI suggestions
  • Consider using AI suggestions only for non-sensitive repositories
  • The feature is opt-in and disabled by default for your security

🔗 Git Hooks Integration

Automatic Installation

Install git hooks with a single command:

devrules install-hooks

This creates a commit-msg hook that:

  1. Validates commit messages using devrules
  2. Runs any existing pre-commit hooks (if pre-commit is installed)

To uninstall:

devrules uninstall-hooks

Manual Setup

Commit message validation:

# .git/hooks/commit-msg
#!/bin/bash
devrules check-commit "$1" || exit 1

Branch validation before push:

# .git/hooks/pre-push
#!/bin/bash
current_branch=$(git symbolic-ref --short HEAD)
devrules check-branch "$current_branch" || exit 1

⌨️ Command Aliases

Most commands have short aliases for convenience:

Command Alias Description
check-branch cb Validate branch name
check-commit cc Validate commit message
check-pr cpr Validate pull request
create-branch nb Create new branch (interactive with Gum)
commit ci Commit with validation
icommit ic Interactive commit with tag selection
create-pr pr Create pull request
ipr - Interactive PR with target selection
init-config init Generate config file
install-hooks ih Install git hooks
uninstall-hooks uh Remove git hooks
list-issues li List GitHub issues
describe-issue di Show issue details
update-issue-status uis Update issue status
list-owned-branches lob List your branches
delete-branch db Delete a branch
delete-merged dm Delete merged branches
dashboard dash Open TUI dashboard
deploy dep Deploy to environment
check-deployment cd Check deployment status
build-enterprise be Build enterprise package
rules - Manage custom rules

🏢 Enterprise Builds

Create custom packages with embedded corporate configuration:

# Install enterprise dependencies
pip install "devrules[enterprise]"

# Build enterprise package
devrules build-enterprise \
  --config .devrules.enterprise.toml \
  --name devrules-mycompany \
  --sensitive github.api_url,github.owner

See Enterprise Build Guide for more details.

🛠️ Custom Validation Rules

Extend DevRules with your own Python validation logic and attach them to lifecycle events.

Basic Rule Definition

  1. Define a rule:
from devrules.core.rules_engine import rule

@rule(name="check-env", description="Verify .env exists")
def check_env():
    # Return (success, message)
    return True, "Environment valid"
  1. Configure:
[custom_rules]
paths = ["./custom_checks.py"]
  1. Run manually:
devrules list-rules
devrules run-rule (selects rules interactively)
devrules run-rule <rule_name>

Lifecycle Hooks

Attach custom rules to specific lifecycle events for automatic execution:

Available Events

  • PRE_COMMIT - Before committing changes (blocking)
  • POST_COMMIT - After successful commit (non-blocking)
  • PRE_PUSH - Before pushing to remote (blocking)
  • PRE_PR - Before creating a pull request (blocking)
  • PRE_DEPLOY - Before deployment (blocking)
  • POST_DEPLOY - After successful deployment (non-blocking)

Hook Registration

from devrules.core.enum import DevRulesEvent
from devrules.core.rules_engine import rule

@rule(
    name="validate_no_breakpoints",
    description="Ensure no debugging statements in code",
    hooks=[DevRulesEvent.PRE_COMMIT],  # Auto-run before commits
    ignore_defaults=True,  # Skip interactive prompts when run as hook
)
def validate_no_breakpoints() -> tuple[bool, str]:
    """Check for debugging breakpoints in staged changes."""
    # Your validation logic here
    return True, "No breakpoints found"

Example: Multi-Language Breakpoint Detection

import re
import subprocess
from devrules.core.enum import DevRulesEvent
from devrules.core.rules_engine import rule

@rule(
    name="validate_no_breakpoints",
    description="Validate that there are no breakpoints in the code.",
    hooks=[DevRulesEvent.PRE_COMMIT],
    ignore_defaults=True,
)
def validate_no_breakpoints() -> tuple[bool, str]:
    """Check for debugging statements in staged changes."""
    
    patterns = [
        r"\bbreakpoint\(\)",           # Python
        r"\bpdb\.set_trace\(\)",       # Python pdb
        r"\bdebugger;",                # JavaScript/TypeScript
        r"\bconsole\.log\(",           # JavaScript console
        r"\bbinding\.pry\b",           # Ruby pry
    ]
    
    combined = re.compile("|".join(patterns))
    
    # Get staged diff
    diff = subprocess.run(
        ["git", "diff", "--cached", "--unified=0"],
        capture_output=True,
        text=True,
        check=True,
    ).stdout
    
    offending = {}
    current_file = None
    
    for line in diff.splitlines():
        if line.startswith("+++ b/"):
            current_file = line[6:]
        elif current_file and line.startswith("+") and not line.startswith("+++"):
            if combined.search(line[1:]):
                offending.setdefault(current_file, []).append(line[1:].strip())
    
    if offending:
        msg = "Debugging statements detected:\n\n"
        for file, lines in offending.items():
            msg += f"{file}\n"
            for line in lines[:5]:
                msg += f"  • {line}\n"
        return False, msg
    
    return True, "No debugging statements found."

Example: Documentation Coverage Check

import subprocess
from devrules.core.enum import DevRulesEvent
from devrules.core.rules_engine import rule

@rule(
    name="validate_docstrings",
    description="Validate docstrings in the code.",
    hooks=[DevRulesEvent.PRE_COMMIT],
    ignore_defaults=True,
)
def check_docstrings(path: str = "src", fail_under: int = 98) -> tuple[bool, str]:
    """Validate docstrings coverage using interrogate."""
    result = subprocess.run(
        ["interrogate", path, "--fail-under", str(fail_under)],
        capture_output=True,
        text=True,
    )
    valid = "PASSED" in result.stdout
    return valid, result.stdout

How Hooks Work

  1. Automatic Execution: When you run devrules icommit or devrules commit, all rules registered with PRE_COMMIT hooks are automatically executed
  2. Blocking Behavior: Pre-hooks (PRE_*) block the operation if validation fails
  3. Non-Interactive: Rules with ignore_defaults=True use default parameter values instead of prompting
  4. Clear Feedback: Hook execution shows which rules are running and their results

Configuration

[custom_rules]
# Paths to Python files or directories containing rules
paths = ["./custom_rules/", "./checks.py"]

# Python packages to import (rules will auto-register)
packages = ["mycompany.devrules"]

Best Practices

  • Use ignore_defaults=True for hook-triggered rules to avoid interactive prompts
  • Return clear messages - Users see these when rules fail
  • Keep rules fast - They run on every commit/deploy
  • Test independently - Use devrules run-rule <rule-name> to test
  • Handle errors gracefully - Return (False, error_message) instead of raising exceptions

📚 Documentation

For full documentation, visit GitHub.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

🙏 Acknowledgments

Built with:

  • Typer - Amazing CLI framework
  • Gum - Glamorous shell scripts and terminal UI

📧 Contact

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

devrules-0.1.9.tar.gz (3.8 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

devrules-0.1.9-py3-none-any.whl (194.6 kB view details)

Uploaded Python 3

File details

Details for the file devrules-0.1.9.tar.gz.

File metadata

  • Download URL: devrules-0.1.9.tar.gz
  • Upload date:
  • Size: 3.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.12

File hashes

Hashes for devrules-0.1.9.tar.gz
Algorithm Hash digest
SHA256 4a96626243a44eda2b130ff64c14414c7f5d749fd4f2ae8d90cd941327dfb8cf
MD5 6b49a2dac555ee7b024288875caafbca
BLAKE2b-256 5f1eaacd158ebe02bebd86458000b88b06dff199abf746ebda30a82c3eaa7fc3

See more details on using hashes here.

File details

Details for the file devrules-0.1.9-py3-none-any.whl.

File metadata

  • Download URL: devrules-0.1.9-py3-none-any.whl
  • Upload date:
  • Size: 194.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.12

File hashes

Hashes for devrules-0.1.9-py3-none-any.whl
Algorithm Hash digest
SHA256 b5c214128ab26f79314ffc63d7cfa86d6ea19aa158823ba34a30f88cb91d432b
MD5 2b24f5db8a8e1a252cb2c88e0a5f4c08
BLAKE2b-256 751b9610b3e8b51c89070359f33b513b406cd2e6fe86c690a584b917217dc25e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page