diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index 56a1133..0000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1,109 +0,0 @@ -# cpp-linter-hooks AI Coding Guide - -## Project Overview -Pre-commit hooks wrapper that auto-installs and runs clang-format and clang-tidy from Python wheels. Supports Python 3.9-3.14 across Windows, Linux, and macOS. - -## Architecture - -### Entry Points & Flow -- **Entry scripts**: `clang-format-hook` and `clang-tidy-hook` (defined in `pyproject.toml`) -- **Hook definitions**: `.pre-commit-hooks.yaml` configures both hooks with `types_or: [c++, c]` -- **Execution pattern**: Parse args → resolve/install tool version → subprocess.run → return (exit_code, output) - -### Core Modules -- **`clang_format.py`**: Wraps clang-format with `-i` (in-place), supports `--verbose` and `--dry-run` modes - - Returns `-1` for dry-run to distinguish from actual failures -- **`clang_tidy.py`**: Wraps clang-tidy, forces exit code 1 if "warning:" or "error:" in output -- **`util.py`**: Dynamic version resolution via PyPI JSON API + pip-based tool installation - - `_resolve_version_from_pypi()`: Supports partial matches (e.g., "20" → "20.1.8"), resolves against PyPI in real time - - No hardcoded version lists — versions are always up-to-date from PyPI - -### Version Management Pattern -```python -# Users can specify partial versions ---version=21 # Resolves to latest 21.x.x ---version=21.1 # Resolves to latest 21.1.x ---version=21.1.8 # Exact version -``` - -## Development Workflows - -### Local Testing -```bash -# Test hooks locally without installing -pre-commit try-repo ./.. clang-format --verbose --all-files -pre-commit try-repo ./.. clang-tidy --verbose --all-files - -# Run test suite -uv run pytest -vv # All tests -uv run coverage run -m pytest # With coverage -uv run pytest -m benchmark # Performance tests only -``` - -### Adding/Modifying Features -1. **Update hook logic** in `cpp_linter_hooks/{clang_format,clang_tidy}.py` -2. **Add tests** in `tests/test_*.py` with `@pytest.mark.benchmark` for performance tracking -3. **Test with sample files** in `testing/` directory (use `good.c` as expected output) -4. **Update README.md** if user-facing behavior changes - -### Dependency Management -- **Uses `uv`** for all dev operations (not pip directly) -- **Tool versions**: Resolved dynamically from PyPI at hook runtime — no manual updates needed -- **Version caching**: `_get_pypi_versions()` uses `lru_cache` to avoid repeated PyPI requests within a single run - -## Project-Specific Conventions - -### Return Value Pattern -All hook functions return `Tuple[int, str]`: -- `(0, "")` → Success -- `(1, output)` → Failure (print output) -- `(-1, output)` → Dry-run mode (clang-format only, convert to success in main) - -### Testing Conventions -- Use `tmp_path` fixture to avoid modifying repo files -- Parametrize version tests: `@pytest.mark.parametrize` with versions 16-21 -- Mark performance-sensitive tests with `@pytest.mark.benchmark` -- Compare formatted output against `testing/good.c` for correctness - -### Argument Handling -```python -# Standard pattern in both hooks -parser = ArgumentParser() -parser.add_argument("--version", default=DEFAULT_VERSION) -hook_args, other_args = parser.parse_known_args(args) -# ... install tool if needed ... -command = ["tool-name"] + other_args # Pass through unknown args -``` - -## Critical Files - -- **`pyproject.toml`**: Defines entry points and dependencies -- **`util.py`**: Core version resolution + tool installation logic -- **`.pre-commit-hooks.yaml`**: Hook metadata for pre-commit framework -- **`testing/run.sh`**: Integration test script used in CI - -## Integration Points - -### PyPI Dependencies -- Fetches available versions from `https://pypi.org/pypi/{package}/json` -- Filters out pre-release versions using regex pattern `(alpha|beta|rc|dev|a\d+|b\d+)` -- Installs via `subprocess.run([sys.executable, "-m", "pip", "install", f"{tool}=={version}"])` - -### Pre-commit Framework -- Hooks run in parallel (`require_serial: false`) for performance -- File type filtering via `types_or: [c++, c]` -- Users configure via `.pre-commit-config.yaml` with `args:` list - -## Common Tasks - -**Add support for a new argument:** -1. Add to ArgumentParser in hook module -2. Pass to subprocess command or handle in Python -3. Add test case in `tests/test_*.py` - -**No manual version updates needed:** Tool versions are resolved dynamically from PyPI at runtime. When new versions are published to PyPI, hooks automatically discover them — no code changes required. - -**Debug hook failures:** -- Add `--verbose` to clang-format args for detailed output -- Check `testing/run.sh` for integration test patterns -- Use `pre-commit run --verbose` for detailed pre-commit logs diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 7cd66f5..d9ad1db 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -23,12 +23,9 @@ jobs: run: | echo "## 💡 Default Clang Tool Versions" > release_notes.md echo "" >> release_notes.md - echo "Versions are resolved **dynamically from PyPI** at hook runtime. " >> release_notes.md - echo "The latest stable versions are always used by default — " >> release_notes.md - echo "no manual updates required." >> release_notes.md - echo "" >> release_notes.md - echo "You can pin a specific version by adding the \`--version\` argument " >> release_notes.md - echo "under \`args\` in your pre-commit config. " >> release_notes.md + echo "Versions are resolved dynamically from PyPI at hook runtime. " >> release_notes.md + echo "The latest stable versions are always used by default — no manual updates required." >> release_notes.md + echo "You can pin a specific version by adding the \`--version\` argument under \`args\` in your pre-commit config." >> release_notes.md echo "See [Custom Clang Tool Version](https://github.com/cpp-linter/cpp-linter-hooks?tab=readme-ov-file#custom-clang-tool-version) for details." >> release_notes.md echo "" >> release_notes.md cat release_notes.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..c737811 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,53 @@ +# AGENTS.md + +> **IMPORTANT**: When you modify any code in this project, also update this file if the change affects agent behavior, project structure, dependencies, git workflow, or any guidance documented here. + +## Git Rules (MUST FOLLOW) + +- **Never** commit directly to `main` branch. +- **Never** run `git push --force` on `main` branch. +- All code changes **must** go through a Pull Request (create a feature branch, push, open PR). +- Use conventional branch names: `feature/`, `bugfix/`, `hotfix/`, `chore/`, `release/`. + +## Project in a Nutshell + +A pre-commit hook repo that auto-installs and runs `clang-format` and `clang-tidy` from Python wheels. Supports Python 3.10+ (tested 3.9–3.14) on Windows, Linux, macOS. + +**Entry points** (defined in `pyproject.toml`): +- `clang-format-hook` → `cpp_linter_hooks/clang_format.py:main` +- `clang-tidy-hook` → `cpp_linter_hooks/clang_tidy.py:main` + +**Hook definitions**: `.pre-commit-hooks.yaml` + +## Key Files + +| File | Purpose | +|------|---------| +| `pyproject.toml` | Build config, deps (`pip>=26.1`, `tomli`), dev deps, entry points | +| `cpp_linter_hooks/util.py` | PyPI version resolution + pip install (prefix matching, offline fallback) | +| `cpp_linter_hooks/clang_format.py` | clang-format wrapper (`--verbose`, `--dry-run`) | +| `cpp_linter_hooks/clang_tidy.py` | clang-tidy wrapper (`--compile-commands`, `--jobs`, `--fix`, error hints) | +| `.pre-commit-hooks.yaml` | Hook metadata for pre-commit framework | +| `testing/` | Test fixtures (`main.c`, `good.c`, `.clang-format`, `.clang-tidy`, CMakeLists) | +| `examples/` | Example configs (CMake, large-project scoping) | + +## Development + +```bash +uv sync --dev # Install dev deps +uv run pytest -vv # Run tests +uv run coverage run --source=tests,cpp_linter_hooks -m pytest -vv # With coverage +bash testing/run.sh # Integration tests (full pre-commit pipeline) +``` + +## Core Patterns + +- **Version resolution**: Dynamic from PyPI at runtime. No hardcoded version lists. Prefix match supported (`--version=20` → `20.1.8`). +- **Return values**: All hooks return `Tuple[int, str]` — `(0, "")` success, `(1, output)` failure, `(-1, output)` dry-run. +- **clang-tidy compile DB**: Auto-detected from `build/`, `out/`, `cmake-build-debug/`, `_build/`. Override with `--compile-commands=