## 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.
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
-
Clone the repository (if you haven't already):
git clone https://github.com/Reithan/negative_rejection_steering.git cd negative_rejection_steering -
Create virtual environment with uv:
uv venv -
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 -
Install development dependencies:
uv pip install -e ".[dev]" -
Install git hooks:
pre-commit install pre-commit install --hook-type pre-pushThe 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
uvinstalled — ifuvisn't found, the check is skipped with a warning — andorigin/mainfetched locally so there's something to diff against. -
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
mainare blocked by git hooks - Direct pushes to
mainare blocked by git hooks - All changes must go through feature branches and pull requests
Recommended Workflow
-
Create a feature branch:
git checkout -b feature/your-feature-nameOr for bug fixes:
git checkout -b fix/bug-description -
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.
-
Push your branch:
git push origin feature/your-feature-nameThe pre-push hook will:
- Run tests (if pytest is available)
- Block the push if you're on the main branch
-
Create a pull request on GitHub
-
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_TYPESmethod andsparameter 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:
- Keep PRs focused: One feature or fix per PR
- Update documentation: If you add features, update README.md
- Test your changes: Ensure the extension works in ComfyUI/reForge
- Run pre-commit hooks: Make sure all checks pass
- 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!