Opinionated PR governance checks. Config-driven, no LLM. Runs as pre-commit hook, CLI, or GitHub Action.
Project description
pr-sop
Opinionated PR governance checks. Config-driven, no LLM. Runs as a CLI, pre-commit hook, or GitHub Action.
Built by the author of sql-sop. Same naming, same philosophy: catch real drift fast, skip the ceremony.
Links
- GitHub
- PyPI
- Download stats
- Install:
pip install pr-sop - Profile
- Contributing:
CONTRIBUTING.md·GOVERNANCE.md·CODE_OF_CONDUCT.md·SECURITY.md·NOTICE
Why Does This Exist?
Teams keep shipping PRs with broken CHANGELOG.md, pyproject.toml versions that do not match the __init__.py, or rev: pins in READMEs that still point at a tag three releases behind. Every repo hits these. Every review catches some and misses others.
pr-sop is a tiny, config-driven checker that runs before merge and surfaces the drift that review forgets. No LLM, no opinions beyond what you turn on in .prsop.yml. Three checks today, each optional, each under 100 lines.
Key Numbers
| Checks | 3 (2 errors, 1 warning) |
| Tests | 29 |
| Runtime | under 1 second on a typical PR |
| PyPI downloads | monthly live (new release, stats warming up) |
| Version | 0.1.1 |
What it checks
| ID | Default severity | What it catches |
|---|---|---|
changelog-required |
error | Files matching a glob pattern changed, but CHANGELOG.md was not updated, or the ## [Unreleased] section is missing or empty. |
version-consistency |
error | Version strings extracted from multiple files disagree. Catches the classic "bumped pyproject, forgot the __init__.py" drift. |
precommit-rev-matches-tag |
warning | rev: pins in configured files (README, pre-commit config) do not match the latest git tag. Since v0.1.1, only pins referencing this repo are flagged, so third-party hooks are ignored automatically. |
Every check is optional and configured in .prsop.yml. A missing section means the check is off.
Quick start
pip install pr-sop
Drop a .prsop.yml at the repo root:
checks:
changelog_required:
severity: error
paths:
- "src/**/*.py"
version_consistency:
severity: error
sources:
- file: pyproject.toml
pattern: '^version\s*=\s*"([^"]+)"'
- file: src/mypkg/__init__.py
pattern: '^__version__\s*=\s*"([^"]+)"'
precommit_rev_matches_tag:
severity: warning
files:
- README.md
- .pre-commit-config.yaml
Run:
pr-sop check --base origin/main
Exit code is 1 if any error fired, 0 otherwise. Warnings never fail CI.
Example terminal output:
ERROR changelog-required src/myapp/api.py 3 changed paths match but CHANGELOG.md was not updated.
-> Add a line under `## [Unreleased]` in CHANGELOG.md.
WARNING precommit-rev-matches-tag README.md:134 `rev: v0.3.2` does not match latest git tag `v0.4.1`.
-> Update the rev to `v0.4.1`.
1 error(s), 1 warning(s) across 2 check(s).
GitHub Action
name: pr-sop
on:
pull_request:
branches: [main]
permissions:
contents: read
jobs:
prsop:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- uses: Pawansingh3889/pr-sop@v0.1.1
Findings surface as native ::error:: and ::warning:: workflow commands (visible in the Files tab of the PR) plus a table in the workflow summary. No API calls, no token setup beyond the default GITHUB_TOKEN.
Consumer inputs on the action:
| Input | Default | Description |
|---|---|---|
config |
.prsop.yml |
Path to the config file relative to the repo root. |
base |
auto | Base ref to diff against. Empty defaults to the PR base, or origin/main otherwise. |
Why not Danger?
Danger is great when you want to write repo-specific rules in JavaScript. pr-sop is the opposite: three opinionated rules you turn on with a YAML block, no Dangerfile to maintain. If you need custom logic, reach for Danger. If you keep forgetting to bump the CHANGELOG, reach for pr-sop.
Design
- Checks are plugins (see
pr_sop/checks/base.py). Each has an id, a pydantic config model, and arun(ctx) -> list[Finding]. - No network calls. Reads your files, shells out to
git. - Config validated by pydantic v2. Typos in
.prsop.ymlfail fast at load, not mid-scan. - Output: Rich terminal locally, workflow commands in Actions.
- Single source of version truth via
importlib.metadata, no hardcoded version string to drift.
Used by
- sql-guard (aka
sql-sopon PyPI), as the first external consumer since v0.1.0.
If you wire pr-sop into your repo and want to be listed, open a PR adding a bullet here.
Status
v0.1.1, alpha. The config schema and rule IDs are the parts most likely to stay stable across 0.x. Internal APIs in pr_sop/checks/ may move before v1.0. Check CHANGELOG.md before upgrading between minor versions.
Licence
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pr_sop-0.1.2.tar.gz.
File metadata
- Download URL: pr_sop-0.1.2.tar.gz
- Upload date:
- Size: 21.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c61bf501828d52cf8c21074623e7c5c542c031cb7d99d399ffc4057712050d1
|
|
| MD5 |
596cc5271d82f6c2563df22c1fe6cc6c
|
|
| BLAKE2b-256 |
0e7727e0f773429623bf7bfa59b1e42bf33ef01d253dba79365596b3cd8459c9
|
File details
Details for the file pr_sop-0.1.2-py3-none-any.whl.
File metadata
- Download URL: pr_sop-0.1.2-py3-none-any.whl
- Upload date:
- Size: 15.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6065a27afb433b7667efbf90f56159ffcf7970d8d6412ed0a44148b0005f7160
|
|
| MD5 |
d5966149e4b58e9533f7b0404bac1cad
|
|
| BLAKE2b-256 |
bbf3f60f34142747f80a5d3efe2ac336cd30b2b9d3c37dd61cdc2787eb122cb8
|