# Git Hooks Setup Guide

## Overview

This project uses **pre-commit** to run automated checks before commits and pushes. This ensures code quality and prevents broken code from being pushed to the repository.

## What Gets Checked

### On Every Commit (pre-commit):
1. **Ruff Linter** - Checks Python code for errors and style issues (with auto-fix)
2. **Ruff Formatter** - Formats Python code automatically
3. **Trailing Whitespace** - Removes trailing whitespace
4. **End of File Fixer** - Ensures files end with a newline
5. **YAML Check** - Validates YAML syntax
6. **JSON Check** - Validates JSON syntax
7. **TOML Check** - Validates TOML syntax (pyproject.toml)
8. **Large Files Check** - Prevents accidentally committing large files (>1MB)
9. **Merge Conflict Check** - Detects merge conflict markers
10. **Private Key Detection** - Prevents committing private keys
11. **Mixed Line Ending** - Ensures consistent line endings

### On Every Push (pre-push):
1. **Pytest** - Runs all tests with verbose output
   - Stops at first failure (`-x` flag)
   - Shows short traceback (`--tb=short`)
   - Tests must pass before push succeeds

## Installation

The hooks are already installed! But if you need to reinstall:

```bash
# Install pre-commit package
pip install pre-commit

# Install git hooks for commits
pre-commit install

# Install git hooks for pushes
pre-commit install --hook-type pre-push
```

## Usage

### Automatic (Recommended)
The hooks run automatically when you:
- **Commit**: Runs formatting and linting
- **Push**: Runs all tests

```bash
git add .
git commit -m "Your commit message"  # Hooks run here automatically
git push origin main                  # Tests run here automatically
```

### Manual Testing
Run hooks manually without committing:

```bash
# Run all hooks on all files
pre-commit run --all-files

# Run all hooks on staged files only
pre-commit run

# Run specific hook
pre-commit run ruff --all-files
pre-commit run pytest-check --all-files

# Run hooks that would run on push
pre-commit run --hook-stage pre-push --all-files
```

## What Happens When Checks Fail

### Formatting/Linting Failures (on commit):
If Ruff or other formatters make changes:
1. The commit is **blocked**
2. Files are **automatically fixed**
3. You need to **stage the fixes** and commit again:

```bash
git add .
git commit -m "Your message"  # Try again with fixed files
```

### Test Failures (on push):
If pytest fails:
1. The push is **blocked**
2. Fix the failing tests
3. Commit the fixes
4. Push again

```bash
# Fix the tests
# ...edit files...

git add .
git commit -m "Fix failing tests"
git push  # Try again
```

## Bypassing Hooks (Emergency Only)

⚠️ **Not recommended!** But if you need to bypass hooks in an emergency:

```bash
# Skip commit hooks
git commit --no-verify -m "Emergency fix"

# Skip push hooks
git push --no-verify
```

**Note**: CI/CD will still run all checks, so bypassing locally doesn't skip the checks entirely.

## Updating Hooks

Update to the latest versions of all hooks:

```bash
pre-commit autoupdate
```

## Configuration

The hooks are configured in `.pre-commit-config.yaml`. You can:

### Disable Specific Hooks Temporarily
```bash
# Skip specific hook
SKIP=pytest-check git push
SKIP=ruff git commit -m "message"

# Skip multiple hooks
SKIP=ruff,pytest-check git push
```

### Modify Hook Behavior
Edit `.pre-commit-config.yaml` to customize:
- Which files to check
- Arguments passed to tools
- When hooks run (commit vs push)

### Example: Skip Tests on Push Temporarily
If tests are taking too long during development:
```bash
SKIP=pytest-check git push
```

## Troubleshooting

### Hooks Not Running
```bash
# Reinstall hooks
pre-commit uninstall
pre-commit install --hook-type pre-commit --hook-type pre-push
```

### Hooks Running But Not Working
```bash
# Clean and reinstall environments
pre-commit clean
pre-commit install-hooks
```

### Tests Failing Locally But Pass in CI
Make sure you're running tests with CI mode:
```bash
CI=true pytest -v
```

### Hook Taking Too Long
You can skip slow hooks temporarily during development:
```bash
SKIP=pytest-check git push
```

Then run tests manually later:
```bash
pytest -v
```

## CI/CD Integration

The same checks run in GitHub Actions:
- `.github/workflows/test-lint.yml` runs on every PR and push
- If hooks pass locally, CI should pass too
- CI is the final gatekeeper (can't be bypassed)

## Best Practices

1. **Let hooks auto-fix**: Don't fight the formatter, let it fix your code
2. **Run tests before committing**: `pytest -v` to catch issues early
3. **Small commits**: Easier to fix if hooks fail
4. **Stage fixes**: After hooks auto-fix, stage changes and commit again
5. **Don't bypass**: Hooks save you from CI failures

## Benefits

✅ **Catch issues early** - Before they reach CI/CD
✅ **Consistent code style** - Automated formatting
✅ **Faster reviews** - Code is pre-formatted
✅ **Fewer CI failures** - Tests run locally first
✅ **Better code quality** - Automated linting
✅ **Time saved** - Auto-fix instead of manual fixes

## Summary

| Stage | What Runs | Purpose |
|-------|-----------|---------|
| **On Commit** | Ruff format + lint, file checks | Code formatting and basic validation |
| **On Push** | Pytest | Ensure tests pass before pushing |
| **In CI** | All checks + multiple Python versions | Final verification |

Your workflow is now protected! 🛡️
