Skip to content

Commit 75a7198

Browse files
authored
docs: add a Python API page (#47)
This adds a Python API page. `commit_check.api` had no page on the site. The core README used to document it, until the README pass (commit-check/commit-check#587) cut that section down to one example on the understanding that the site would take it over. This is that page. ## `guides/python-api.md` - **Functions.** It covers all six, in one table: `validate_message`, `validate_branch`, `validate_author`, `validate_tag`, `validate_push` and `validate_all`. The old README never listed `validate_tag` or `validate_push`. For each function the table says what it checks and what it reads from git when a value is left out. `validate_all` reads nothing from git. - **Result.** The shape is the same as `--format json`. The page explains what `pass`, `fail`, `skip` and `warn` mean, and when `fix` is filled in. - **Configuration.** The API does **not** read `cchk.toml`. `config` is a dict merged over the built-in defaults. To use a repository's own policy, load the file with `tomllib` and pass it in. On Python 3.10, commit-check already depends on `tomli`. `inherit_from` is not followed this way, and the page says so. - **Fixing until it passes.** A short example applies `fix` and validates again, which is the same loop the MCP server teaches. ## Links to the page - The nav, under *Guides*, after *MCP server*. - *Where to run it*: a row in the table and a short section. - The end of *Reading the JSON* in *Command-line recipes*. ## Checks - I ran every Python sample on the page against the released commit-check **2.18.1** and pasted the output as printed. A script re-ran each block and diffed it against the page, and all of them match. I also checked that `validate_tag()` returns `skip` on a commit that has no tag, as the table says. - `mkdocs build --strict` passes (with `SOCIAL_CARDS=false`). - `python -m pytest tests/ -q` passes with the released package installed (10 tests). The pins and the changelog were already at 2.18.1. ## Follow-up Once this deploys, the core README's *AI-native usage* section can link here. That section currently names only three of the other five functions. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Added a Python API guide covering how to run commit checks in-process, configure checks, interpret results, and apply suggested fixes. * Added the Python API to the integrations comparison and documentation navigation. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 425fa24 commit 75a7198

4 files changed

Lines changed: 176 additions & 0 deletions

File tree

‎docs/example.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,3 +317,6 @@ $ commit-check -m -b --format json | jq '{status, warnings}'
317317
"warnings": 1
318318
}
319319
```
320+
321+
From Python, [`commit_check.api`](guides/python-api.md) returns the same
322+
result as a `dict`, without a subprocess.

‎docs/guides/integrations.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ developer sees locally and what is enforced on the pull request.
1111
| [GitHub App](github-app.md) | On every push and pull request, hosted | No | Install once for the organization |
1212
| [Command line](../example.md) | Wherever you call it: a range of commits, a CI you write yourself | — | `pip install commit-check` |
1313
| [MCP server](mcp.md) | Before the commit exists, inside an AI coding agent | — | One entry in the agent's MCP config |
14+
| [Python API](python-api.md) | Wherever your own code runs: a bot, a server-side hook, an agent you build | — | `pip install commit-check`, then `import commit_check.api` |
1415
| [Organization config](organization.md) | Everywhere at once | — | One shared `cchk.toml`, whichever of the above runs it |
1516

1617
## Which one
@@ -68,6 +69,11 @@ push and pull request, with no workflow file and no CI minutes.
6869
The same rules as tools for an AI coding agent, so the message is right before
6970
the commit exists. One entry in the agent's MCP settings. [Set it up →](mcp.md)
7071

72+
## Python API
73+
74+
The same checks from your own code, with no subprocess: each call returns the
75+
JSON result as a `dict`. [Read the API →](python-api.md)
76+
7177
## Across an organization { #across-an-organization }
7278

7379
One `cchk.toml` in the organization's `.github` repository; each repository

‎docs/guides/python-api.md‎

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# Python API
2+
3+
`commit_check.api` runs the same checks as the command line from Python code —
4+
a bot, a server-side hook, an agent you are building — without starting a
5+
subprocess. Each function takes the value to check and returns a plain `dict`
6+
in the shape `commit-check --format json` prints, ready to branch on, log or
7+
hand to a model. It ships with the package: `pip install commit-check` is all
8+
it needs.
9+
10+
```python
11+
from commit_check.api import validate_message
12+
13+
result = validate_message("Fix: add streaming support")
14+
for check in result["checks"]:
15+
if check["status"] == "fail":
16+
print(check["rule_id"], check["suggest"])
17+
print("fix:", check["fix"])
18+
```
19+
20+
```text
21+
CC001 Use "fix: add streaming support"
22+
fix: fix: add streaming support
23+
```
24+
25+
## Functions
26+
27+
| Function | Checks | When the value is left out |
28+
|---|---|---|
29+
| `validate_message(message, *, config=None)` | The commit message: Conventional Commits, subject length, case and mood, body, sign-off, AI attribution — whichever rules the config enables | Required |
30+
| `validate_branch(branch=None, *, config=None)` | The branch name, and its rebase target when one is configured | The current branch, from `git branch --show-current` |
31+
| `validate_author(name=None, email=None, *, config=None)` | The author's name and email | Both come from `git config` |
32+
| `validate_tag(tag=None, *, config=None)` | Tag names, one per line | The tags pointing at `HEAD`; with none, the result is `skip` |
33+
| `validate_push(push_refs=None, *, config=None)` | That a push is not a force push; the check is always on here | Pass the pre-push lines, `<local ref> <local sha> <remote ref> <remote sha>`, one per line — without them there is nothing to compare |
34+
| `validate_all(message=None, branch=None, author_name=None, author_email=None, *, config=None)` | Message, branch and author together, in one result | Whatever is left out is not checked, and nothing is read from git |
35+
36+
The git lookups run in the current working directory, as the CLI's do.
37+
38+
```python
39+
from commit_check.api import validate_all
40+
41+
result = validate_all(message="feat: implement new feature", branch="user-login")
42+
print(result["status"])
43+
for check in result["checks"]:
44+
print(check["rule_id"], check["check"], check["status"])
45+
```
46+
47+
```text
48+
fail
49+
CC001 message pass
50+
CC004 subject_max_length pass
51+
CC005 subject_min_length pass
52+
CC201 branch fail
53+
```
54+
55+
## The result
56+
57+
Every function returns the same shape:
58+
59+
```python
60+
{
61+
"status": "pass" | "fail" | "skip",
62+
"warnings": 0, # how many checks have status "warn"
63+
"checks": [
64+
{
65+
"rule_id": "CC001",
66+
"check": "message",
67+
"status": "pass" | "fail" | "warn" | "skip",
68+
"value": "...", # what was checked
69+
"error": "...", # why it failed
70+
"suggest": "...", # advice for a person
71+
"fix": "...", # the corrected value, or "" when it takes judgment
72+
"docs_url": "https://commit-check.com/rules/#cc001",
73+
},
74+
],
75+
}
76+
```
77+
78+
- **Only `fail` is a rejection.** Code that branches on `status == "fail"`
79+
keeps working whatever else the result holds.
80+
- **`skip` is not `pass`.** A check skips when it never ran — the author is in
81+
`ignore_authors`, or there was nothing to check — and the top-level `status`
82+
is `skip` only when every check skipped. A skipped run validated nothing, so
83+
do not read it as approval.
84+
- **`warn`** is a rule listed under the config's `warn`: reported in full,
85+
never a failure. The top-level `status` stays `pass`, and `warnings` counts
86+
them.
87+
- **`fix`** is non-empty only when the correction is mechanical, so it can be
88+
applied as it stands; otherwise follow `suggest`.
89+
[Reading the JSON](../example.md#reading-the-json) lists the cases.
90+
91+
## Configuration
92+
93+
The API does not read `cchk.toml`. It starts from the built-in defaults and
94+
merges the `config` you pass, a `dict` shaped like the TOML file:
95+
96+
```python
97+
from commit_check.api import validate_message
98+
99+
result = validate_message(
100+
"docs: update readme",
101+
config={"commit": {"allow_commit_types": ["feat", "fix"]}},
102+
)
103+
print(result["status"])
104+
print(result["checks"][0]["suggest"])
105+
```
106+
107+
```text
108+
fail
109+
Use <type>(<scope>): <description>, where <type> is one of: feat, fix
110+
```
111+
112+
A top-level `warn` works as it does in the file:
113+
114+
```python
115+
from commit_check.api import validate_message
116+
117+
result = validate_message("add streaming support", config={"warn": ["message"]})
118+
print(result["status"], result["warnings"])
119+
```
120+
121+
```text
122+
pass 1
123+
```
124+
125+
To apply a repository's own policy, load its file and pass it along:
126+
127+
```python
128+
import tomllib # on Python 3.10: import tomli as tomllib
129+
130+
from commit_check.api import validate_message
131+
132+
with open("cchk.toml", "rb") as f:
133+
config = tomllib.load(f)
134+
135+
result = validate_message("feat: add streaming support", config=config)
136+
```
137+
138+
On Python 3.10, `tomli` is already installed: commit-check depends on it
139+
there. `inherit_from` is not followed this way; only the file's own keys
140+
apply. Every key is in the [configuration reference](../configuration.md).
141+
142+
## Fixing until it passes
143+
144+
An agent can apply `fix` and check again — the loop the
145+
[MCP server](mcp.md) teaches its clients:
146+
147+
```python
148+
from commit_check.api import validate_message
149+
150+
message = "Fix: add streaming support"
151+
for _ in range(3):
152+
result = validate_message(message)
153+
fixes = [c["fix"] for c in result["checks"] if c["status"] == "fail" and c["fix"]]
154+
if result["status"] != "fail" or not fixes:
155+
break
156+
message = fixes[0]
157+
158+
print(result["status"], message)
159+
```
160+
161+
```text
162+
pass fix: add streaming support
163+
```
164+
165+
When `fix` is empty the correction takes judgment — choosing a type for a bare
166+
subject, shortening a long one — and `suggest` says what is needed.

‎mkdocs.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ nav:
175175
- GitHub App: guides/github-app.md
176176
- Across an organization: guides/organization.md
177177
- MCP server: guides/mcp.md
178+
- Python API: guides/python-api.md
178179
- Policy guides: guides/policies.md
179180
- Command-line recipes: example.md
180181
- Troubleshooting: troubleshoot.md

0 commit comments

Comments
 (0)