diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..8f0f569 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,56 @@ +## What does this PR do? + + + +## Why? + + + + +## Type of change + +- [ ] Bug fix +- [ ] New feature / command +- [ ] Refactor (no behavior change) +- [ ] Docs / chore +- [ ] New extraction pattern (saar/extractors/) +- [ ] Formatter change (saar/formatters/) + +## Module affected + + +- [ ] `saar/commands/` — CLI command logic +- [ ] `saar/extractors/` — Pattern extraction +- [ ] `saar/formatters/` — Output generation +- [ ] `saar/linter.py` — AGENTS.md quality rules +- [ ] `saar/scorer.py` — Quality scoring +- [ ] `saar/models.py` — ⚠️ Core data contract (discuss before touching) + +## Verification + + + +```bash +source venv/bin/activate + +# 1. Lint +ruff check saar/ tests/ + +# 2. Tests — 548 must pass +pytest tests/ -q + +# 3. Dogfood — saar must extract itself cleanly with no stale warnings +saar extract . --no-interview + +# 4. If you changed a formatter, regenerate all context files +saar extract . --force --no-interview +``` + +## Checklist + +- [ ] `ruff check saar/ tests/` passes (no E/F violations) +- [ ] `pytest tests/ -q` → 548 passed +- [ ] `saar extract . --no-interview` runs clean (no stale fact warnings) +- [ ] Did NOT modify `saar/models.py` without discussion +- [ ] Did NOT add external dependencies (no Supabase, Redis, network calls in core path) +- [ ] Version bumped in `pyproject.toml` + `saar/__init__.py` (if shipping a release) diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index 4e8c50d..8424a77 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -1,6 +1,6 @@ name: Auto Release + Publish -# Triggers on every push to main. +# Triggers AFTER CI passes on main -- never release broken code. # If the version in pyproject.toml has no git tag yet, it: # 1. Creates the git tag (v0.x.y) # 2. Creates a GitHub Release @@ -8,7 +8,9 @@ name: Auto Release + Publish # If the version already has a tag, it does nothing. on: - push: + workflow_run: + workflows: [CI] + types: [completed] branches: [main] permissions: @@ -16,6 +18,8 @@ permissions: jobs: release: + # Only run if CI actually passed -- not on failure or cancellation + if: ${{ github.event.workflow_run.conclusion == 'success' }} runs-on: ubuntu-latest steps: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4d689c0..c89181f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,55 +7,61 @@ on: branches: [main] jobs: + # Lint runs once -- no point running ruff 12 times across the matrix + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Install dependencies + run: pip install -e ".[dev]" + - name: Lint + run: ruff check saar/ tests/ + + # Tests run across all supported Python versions and OS test: + needs: lint runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ["3.10", "3.11", "3.12", "3.13"] fail-fast: false - steps: - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies run: pip install -e ".[dev]" - - name: Show tree-sitter version run: pip show tree-sitter tree-sitter-python tree-sitter-javascript - - - name: Lint - run: ruff check saar/ tests/ - - name: Test - run: pytest tests/ -v --tb=long 2>&1 + run: pytest tests/ -q --tb=short - # Quick smoke test: install from built wheel and run CLI + # Install from wheel + dogfood: saar must extract itself cleanly install-test: - runs-on: ubuntu-latest needs: test + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 + - uses: actions/setup-python@v5 with: python-version: "3.12" - - name: Build wheel run: | pip install build python -m build - - name: Install from wheel run: pip install dist/*.whl - - name: Smoke test CLI run: | saar --version saar extract . --format markdown --no-interview + - name: Dogfood -- saar must extract itself with no stale warnings + run: | + saar extract . --no-interview + saar lint . && echo "lint clean" || echo "lint violations found (non-blocking)" + saar stats . 2>&1 | grep -E "100/100|No improvements"