Skip to main content

Opinionated PR governance checks. Config-driven, no LLM. Runs as pre-commit hook, CLI, or GitHub Action.

Project description

pr-sop

PyPI Python License Downloads

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

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 a run(ctx) -> list[Finding].
  • No network calls. Reads your files, shells out to git.
  • Config validated by pydantic v2. Typos in .prsop.yml fail 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-sop on 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

MIT. See LICENSE and NOTICE for the reasoning.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pr_sop-0.1.2.tar.gz (21.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pr_sop-0.1.2-py3-none-any.whl (15.1 kB view details)

Uploaded Python 3

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

Hashes for pr_sop-0.1.2.tar.gz
Algorithm Hash digest
SHA256 0c61bf501828d52cf8c21074623e7c5c542c031cb7d99d399ffc4057712050d1
MD5 596cc5271d82f6c2563df22c1fe6cc6c
BLAKE2b-256 0e7727e0f773429623bf7bfa59b1e42bf33ef01d253dba79365596b3cd8459c9

See more details on using hashes here.

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

Hashes for pr_sop-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6065a27afb433b7667efbf90f56159ffcf7970d8d6412ed0a44148b0005f7160
MD5 d5966149e4b58e9533f7b0404bac1cad
BLAKE2b-256 bbf3f60f34142747f80a5d3efe2ac336cd30b2b9d3c37dd61cdc2787eb122cb8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page