Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
## What does this PR do?

<!-- One paragraph. What problem does it solve? -->

## Why?

<!-- Why is this change needed? Link the issue. -->
<!-- Closes #ISSUE_NUMBER -->

## 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 knows its own structure. Tick what you touched. -->
- [ ] `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

<!-- saar dogfoods itself. Run these before opening the PR. -->

```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)
8 changes: 6 additions & 2 deletions .github/workflows/auto-release.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
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
# 3. Builds and publishes to PyPI
# If the version already has a tag, it does nothing.

on:
push:
workflow_run:
workflows: [CI]
types: [completed]
branches: [main]

permissions:
contents: write

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:
Expand Down
44 changes: 25 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Loading