Files
Reithan e0e48d12c8 Enforce branch-coverage gate on pre-push (mirror CI locally) (#40)
## What
Makes the local **pre-push** git hook enforce the same branch-coverage
gate as CI, so contributors catch coverage regressions before they push
(not just in CI). Two files change: the hook (`.pre-commit-config.yaml`)
and a doc note (`CONTRIBUTING.md`).

## The hook (`.pre-commit-config.yaml`, `run-tests` pre-push hook)
Mirrors `.github/workflows/test.yml`:
1. Runs the full suite with **real torch** + branch coverage: `pytest
--cov=NRS --cov-branch --cov-report=xml`.
2. Then the diff gate: `diff-cover coverage.xml
--compare-branch=origin/main --branch-coverage --fail-under=90` —
**blocks the push if changed code drops below 90% branch coverage**.
3. **Graceful skip** with a warning if `uv` isn't installed (unchanged
behavior); **fails loudly** if `origin/main` can't be resolved (nothing
to diff against).
4. Cleans up `coverage.xml`/`.coverage` on both success and failure
paths, while preserving the exit code so a failing gate still blocks.

All existing hooks are untouched: `prevent-push-to-main`,
`prevent-commit-to-main`, ruff, and the standard hooks. Only the
`run-tests` entry/name changed. Coverage stays on the **pre-push** stage
only — commits remain fast.

### Uses `uvx`, not `uv run` (important)
The invocations use `uvx --with torch --with pytest-cov --with
diff-cover ...`. An earlier `uv run` version was verified to **break the
push**: `uv run` syncs the project env and mutates `uv.lock` mid-hook,
which conflicts with pre-commit's stash/restore and aborts the push
(`Stashed changes conflicted with hook auto-fixes... Rolling back`).
`uvx` runs in an ephemeral env and never touches `uv.lock` — matching
how the project runs tests locally everywhere else.

## Docs (`CONTRIBUTING.md`)
Added a short note right after the `pre-commit install --hook-type
pre-push` instruction explaining the gate, the `uv` requirement (skips
with a warning otherwise), and that `origin/main` must be fetched for
the diff.

## Validation
- Ran the hook's exact command: **45 tests pass**, diff-cover passes;
`git status` after confirms `uv.lock` is **not** mutated (the
stash-conflict path can't recur).
- `uvx pre-commit run --hook-stage pre-push` completes with no
stash-conflict rollback.
- **This very PR's push exercised the hook live** — it ran the gate and
pushed cleanly.
- Only `.pre-commit-config.yaml` and `CONTRIBUTING.md` changed;
`pyproject.toml`/`uv.lock`/tests/`NRS/` untouched.

## Out-of-scope observation
The `ruff-format` hook has no `stages:` restriction, so a manual
`--all-files` dry-run reformats files broadly. Pre-existing; not
addressed here.
2026-08-14 02:40:33 -07:00

6.2 KiB

Contributing to Negative Rejection Steering

Thank you for your interest in contributing! This document provides guidelines for setting up your development environment and contributing to the project.

Development Setup

Prerequisites

  • Python 3.10 or higher
  • uv package manager
  • Git

Initial Setup

  1. Clone the repository (if you haven't already):

    git clone https://github.com/Reithan/negative_rejection_steering.git
    cd negative_rejection_steering
    
  2. Create virtual environment with uv:

    uv venv
    
  3. Activate virtual environment:

    # Git Bash (Windows)
    source .venv/Scripts/activate
    
    # Linux/Mac
    source .venv/bin/activate
    
    # Windows CMD
    .venv\Scripts\activate.bat
    
    # Windows PowerShell
    .venv\Scripts\Activate.ps1
    
  4. Install development dependencies:

    uv pip install -e ".[dev]"
    
  5. Install git hooks:

    pre-commit install
    pre-commit install --hook-type pre-push
    

    The pre-push hook runs the full test suite with branch coverage and blocks the push if changed code drops below 90% branch coverage (via pytest-cov + diff-cover, mirroring CI). It needs uv installed — if uv isn't found, the check is skipped with a warning — and origin/main fetched locally so there's something to diff against.

  6. Verify setup:

    # Run hooks manually on all files
    pre-commit run --all-files
    
    # Check that ruff works
    ruff check .
    

Git Workflow

Protected Branches

  • Direct commits to main are blocked by git hooks
  • Direct pushes to main are blocked by git hooks
  • All changes must go through feature branches and pull requests
  1. Create a feature branch:

    git checkout -b feature/your-feature-name
    

    Or for bug fixes:

    git checkout -b fix/bug-description
    
  2. Make your changes and commit:

    git add <files>
    git commit -m "Your commit message"
    

    The pre-commit hook will automatically:

    • Run ruff linting and auto-fix issues
    • Check for trailing whitespace, missing final newlines, etc.
    • Block the commit if you're on the main branch

    If the linter auto-fixes files, you'll need to re-stage and commit again.

  3. Push your branch:

    git push origin feature/your-feature-name
    

    The pre-push hook will:

    • Run tests (if pytest is available)
    • Block the push if you're on the main branch
  4. Create a pull request on GitHub

  5. Merge after review

Bypassing Hooks (Emergency Only)

If you must bypass hooks (NOT recommended):

git commit --no-verify    # Skip pre-commit hooks
git push --no-verify      # Skip pre-push hooks

Warning: Only use --no-verify in emergencies. Bypassing hooks may:

  • Introduce linting issues
  • Break Continuous Integration/Continuous Deployment pipelines
  • Allow untested code to be pushed

Development Commands

Linting

# Check for linting issues
ruff check .

# Auto-fix linting issues
ruff check --fix .

# Format code
ruff format .

# Check a specific file
ruff check NRS/nodes_NRS.py

Testing

# Run all tests
pytest

# Run with verbose output
pytest -v

# Run specific test file
pytest tests/test_smoke.py

# Run specific test function
pytest tests/test_smoke.py::test_file_structure

Note: Tests use mocked versions of torch and gradio (via conftest.py) since these dependencies are provided by ComfyUI/WebUI at runtime.

Pre-commit Hooks

# Run all hooks manually
pre-commit run --all-files

# Run specific hook
pre-commit run ruff --all-files
pre-commit run ruff-format --all-files

# Update hook versions
pre-commit autoupdate

Code Style Guidelines

This project uses ruff for linting and formatting with the following configuration:

  • Line length: 120 characters
  • Target Python version: 3.10+
  • Enabled checks: pycodestyle (E/W), pyflakes (F), isort (I), pep8-naming (N), pyupgrade (UP)

Special Cases

  • ComfyUI API conventions: The INPUT_TYPES method and s parameter naming are required by ComfyUI's API and are exempted from normal naming rules
  • Star imports in __init__.py: Required for ComfyUI node discovery

Commit Message Guidelines

Write clear, concise commit messages:

  • Use imperative mood ("Add feature" not "Added feature")
  • Keep first line under 72 characters
  • Add detailed description in the body if needed

Good examples:

Add support for XYZ model type
Fix crash when prediction type is unknown
Update README with installation instructions

Bad examples:

fixed stuff
WIP
Updated code

Pull Request Guidelines

When submitting a pull request:

  1. Keep PRs focused: One feature or fix per PR
  2. Update documentation: If you add features, update README.md
  3. Test your changes: Ensure the extension works in ComfyUI/reForge
  4. Run pre-commit hooks: Make sure all checks pass
  5. Describe your changes: Explain what and why in the PR description

Project Structure

negative_rejection_steering/
├── NRS/
│   └── nodes_NRS.py          # Main NRS node implementation
├── scripts/
│   └── negative_rejection_steering_script.py  # Gradio UI for reForge
├── tests/
│   └── test_smoke.py         # Smoke tests
├── __init__.py               # ComfyUI node exports
├── pyproject.toml            # Project config, dependencies, tool config
├── .pre-commit-config.yaml   # Git hooks configuration
├── .gitignore
├── README.md
├── LICENSE
└── CONTRIBUTING.md           # This file

Getting Help

  • Issues: Report bugs or request features via GitHub Issues
  • Discussions: For questions or general discussion
  • Pull Requests: Review the PR guidelines above before submitting

License

By contributing to this project, you agree that your contributions will be licensed under the same license as the project (see LICENSE file).


Thank you for contributing to Negative Rejection Steering!