Skip to content

Commit ff1a575

Browse files
Enhance README with detailed action description
Expanded the README to provide a comprehensive overview of the CPython Patch PR Action, including features, usage patterns, and configuration options.
1 parent 92cad5e commit ff1a575

File tree

1 file changed

+94
-101
lines changed

1 file changed

+94
-101
lines changed

README.md

Lines changed: 94 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,36 @@
11
# CPython Patch PR Action
22

3-
CPython Patch PR Action is a GitHub Action that automatically scans your repository for pinned CPython patch versions (e.g. `3.12.4`) and opens an evergreen pull request whenever a new patch release is available. It keeps Dockerfiles, GitHub workflows, `.python-version`, `pyproject.toml`, `runtime.txt`, `Pipfile`, Conda environment files, and more aligned with the latest stable runtime—helping teams maintain secure, up-to-date Python environments without custom automation.
3+
Automate CPython patch updates across every Python version reference in your repo. This GitHub Action handles security maintenance, Python version management, and CI/CD automation without custom scripts.
44

5-
---
5+
> Star and watch to get updates. Try the quick start below.
6+
7+
## Why this Action
8+
9+
DevOps, SRE, platform, and Python maintainers need consistent runtimes without manual patching. This action:
10+
11+
* Finds pinned CPython versions everywhere you declare them.
12+
* Resolves the latest stable patch and opens an evergreen PR.
13+
* Minimizes diffs and noise. Adds auditability and easy rollbacks.
14+
* Plays well with Renovate and Dependabot.
15+
16+
Keywords: GitHub Action, CPython patch updates, Python version management, automated dependency updates, CI/CD automation, security maintenance.
17+
18+
## Feature overview
19+
20+
* Cross-file detection: Dockerfiles, GitHub workflows, `.python-version`, `.tool-versions`, `runtime.txt`, `tox.ini`, `pyproject.toml`, `Pipfile`, Conda `environment.yml`, and more.
21+
* Smart discovery: Pulls CPython tags from GitHub with python.org fallback. Checks GitHub runner availability. Pre-release guard on by default.
22+
* Minimal rewrites: Targeted replacements that preserve image suffixes like `-slim` and `-alpine`. Dry-run summary before writes.
23+
* Idempotent: Skips if already on latest and sets `skipped_reason=already_latest`.
24+
* Branch and PR automation: Predictable branch name. Updates an existing PR or opens a new one via Octokit.
25+
* External PR support: Emits outputs for `peter-evans/create-pull-request` when preferred.
26+
* Automerge ready: Hook for label or merge after checks pass.
27+
* Security keyword gate: Only upgrade if release notes include keywords such as `CVE` or `security`.
28+
* Offline snapshots: Run without network using provided tag, runner, and release notes snapshots.
29+
* CI matrix fan-out: Output a change matrix to scope targeted jobs.
630

731
## Quick start
832

9-
1. **Add the workflow**
33+
1. Add a scheduled workflow.
1034

1135
```yaml
1236
name: CPython Patch Bot
@@ -34,34 +58,28 @@ CPython Patch PR Action is a GitHub Action that automatically scans your reposit
3458
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3559
```
3660
37-
2. **Review the pull request** – When a patch release appears, the action creates (or updates) `chore/bump-python-<track>` with all replacements and opens a PR against your default branch.
61+
2. Review the PR. The action creates or updates `chore/bump-python-<track>` and opens a PR against the default branch.
3862

39-
3. **Merge or enable automerge** – Set `automerge: true` if you want the action (or a follow-up workflow) to merge after checks succeed.
63+
3. Merge or enable automerge. Set `automerge: true` or wire your own automerge job.
4064

41-
---
65+
## How it works
4266

43-
## Highlights
44-
45-
- 🔍 **Cross-file detection:** Finds pinned CPython versions in Dockerfiles, GitHub Actions workflows, `.python-version`, `.tool-versions`, `runtime.txt`, `tox.ini`, `pyproject.toml`, `Pipfile`, Conda `environment.yml`, and more.
46-
- 🧠 **Smart discovery:** Pulls CPython tags from GitHub, falls back to python.org, checks GitHub runner availability, and enforces a pre-release guard by default.
47-
- ✏️ **Minimal rewrites:** Calculates targeted replacements, preserves suffixes (e.g. `-slim`, `-alpine`), and emits a dry-run summary before writing.
48-
- 🔁 **Idempotent runs:** Detects when everything is already on the latest patch and sets `skipped_reason=already_latest` to avoid noisy PRs.
49-
- 🌿 **Branch + PR automation:** Creates a consistent branch name, commits changes, and either updates an existing PR or opens a new one via Octokit.
50-
- 🔌 **External PR support:** Optionally emit metadata for `peter-evans/create-pull-request` if you prefer that workflow.
51-
- 🤖 **Automerge ready:** Honor the `automerge` flag by labeling or merging once checks pass (implementation hook provided).
52-
53-
---
67+
1. Scan repository for pinned CPython patch versions like `3.12.4` across supported files.
68+
2. Discover latest patch for the selected `track` using GitHub tags with python.org fallback.
69+
3. Enforce pre-release guard unless `include_prerelease: true`.
70+
4. Compute minimal diffs and generate a branch and PR body.
71+
5. If no change is needed, exit with `skipped_reason=already_latest`.
5472

5573
## Inputs
5674

5775
| Input | Required | Default | Description |
5876
| ------------------------ | -------- | --------------------- | --------------------------------------------------------------------------------------- |
59-
| `track` | false | `3.13` | CPython minor series to monitor (e.g. `3.12`). |
77+
| `track` | false | `3.13` | CPython minor series to monitor (for example `3.12`). |
6078
| `include_prerelease` | false | `false` | Allow `rc`, `a`, or `b` releases when determining the latest patch. |
61-
| `paths` | false | _(see default globs)_ | Newline-separated glob patterns to scan. |
79+
| `paths` | false | *(see default globs)* | Newline-separated glob patterns to scan. |
6280
| `automerge` | false | `false` | Label or merge the bump PR once checks pass. |
6381
| `dry_run` | false | `false` | Skip file writes and emit a change summary instead. |
64-
| `security_keywords` | false | _(empty)_ | Require the release notes to contain at least one of the provided keywords before upgrading. |
82+
| `security_keywords` | false | *(empty)* | Require at least one keyword to appear in release notes before upgrading. |
6583
| `use_external_pr_action` | false | `false` | Emit outputs for `peter-evans/create-pull-request` instead of using Octokit internally. |
6684

6785
**Default globs**
@@ -75,22 +93,18 @@ Dockerfile
7593
**/pyproject.toml
7694
```
7795
78-
---
79-
8096
## Outputs
8197
8298
| Output | Description |
8399
| ---------------- | -------------------------------------------------------------------------------------------------------------------------- |
84100
| `new_version` | Highest CPython patch identified during the run. |
85101
| `files_changed` | JSON array of files rewritten. |
86-
| `change_matrix` | JSON object suitable for `strategy.matrix` fan-out (entries contain `file` and `new_version`). |
102+
| `change_matrix` | JSON object for `strategy.matrix` fan-out with entries `{ file, new_version }`. |
87103
| `skipped_reason` | Machine-readable reason when no PR is created (`already_latest`, `multiple_tracks_detected`, `pre_release_guarded`, etc.). |
88104
89-
---
105+
## Usage patterns
90106
91-
## Advanced configuration
92-
93-
### Dry-run previews
107+
### Dry-run preview
94108
95109
```yaml
96110
- name: CPython bump preview
@@ -100,18 +114,29 @@ Dockerfile
100114
dry_run: true
101115
```
102116

103-
The action prints a summary listing file paths, line numbers, and `old -> new` replacements so you can see the impact before committing.
117+
Prints file paths, line numbers, and `old -> new` replacements before committing.
104118

105119
### Pre-release guard override
106120

107-
Keep release candidates out of production by default. Opt in when you intentionally want `rc`/alpha/beta builds:
108-
109121
```yaml
110122
with:
111123
include_prerelease: true
112124
```
113125
114-
### External PR workflow
126+
### Security keyword gate
127+
128+
Only roll forward when release notes match keywords.
129+
130+
```yaml
131+
with:
132+
security_keywords: |
133+
CVE
134+
security
135+
```
136+
137+
When set, the action fetches GitHub release notes for the resolved tag (or uses `RELEASE_NOTES_SNAPSHOT`) and skips unless a keyword matches.
138+
139+
### External PR workflow (peter-evans)
115140

116141
```yaml
117142
- name: Bump CPython patch versions
@@ -131,24 +156,11 @@ with:
131156

132157
### Automerge guidance
133158

134-
Set `automerge: true` and wire a follow-up job that applies your preferred automerge strategy (label-based, direct merge, etc.) based on the outputs emitted by the action.
159+
Set `automerge: true` and attach your merge strategy in a follow-up job based on the action outputs.
135160

136-
### Security keyword gate
137-
138-
Supply `security_keywords` (one per line) to require matching terms inside the CPython release notes before applying an update. This is useful for only auto-rolling releases that contain security fixes:
139-
140-
```yaml
141-
with:
142-
security_keywords: |
143-
CVE
144-
security
145-
```
146-
147-
When the keywords are provided, the action fetches the GitHub release notes for the resolved tag (or uses the optional `RELEASE_NOTES_SNAPSHOT` offline input) and skips the run unless at least one keyword is present.
148-
149-
### Matrix fan-out for CI
161+
### CI matrix fan-out
150162

151-
Use the `change_matrix` output to drive follow-up jobs that need to iterate over the files touched by the upgrade:
163+
Drive targeted follow-up jobs using the `change_matrix` output.
152164

153165
```yaml
154166
jobs:
@@ -170,89 +182,70 @@ jobs:
170182
- run: npm test -- ${{ matrix.file }}
171183
```
172184

173-
Each matrix entry exposes `matrix.file` and `matrix.new_version`, enabling you to scope lint or test jobs to the files rewritten during the patch.
185+
### Renovate and Dependabot coexistence
174186

175-
### Renovate/Dependabot coexistence
187+
Avoid competing PRs while keeping other automated dependency updates.
176188

177-
If Renovate or Dependabot also try to bump CPython patch versions, they will race with this action
178-
and open competing pull requests. Use the sample configurations below to disable CPython patch bumps
179-
while still allowing those tools to manage other dependencies:
189+
* `examples/coexistence/renovate.json` disables patch updates for the `python` base image and matching regex managers.
190+
* `examples/coexistence/dependabot.yml` ignores semver patch updates for the `python` Docker image.
180191

181-
- `examples/coexistence/renovate.json` disables patch updates for the `python` base image in Dockerfiles
182-
and any custom regex managers that match CPython pins.
183-
- `examples/coexistence/dependabot.yml` ignores semver patch updates for the `python` Docker image
184-
while keeping other ecosystems enabled.
192+
Both samples are validated by tests. Copy and adjust schedules or rules as needed.
185193

186-
Both samples are validated by the test suite so you can copy them verbatim and adjust schedules or
187-
additional dependency rules as needed.
188-
189-
---
190-
191-
## Example consumer repositories
192-
193-
Clone one of the templates in [`examples/`](examples) to see the action running in
194-
the context of a real repository:
195-
196-
- [`examples/minimal`](examples/minimal) – single-job workflow scheduled weekly.
197-
- [`examples/guarded`](examples/guarded) – dry-run preview with release-note
198-
gating and concurrency controls.
194+
### Offline mode
199195

200-
Each template ships with a README snippet and status badge you can adapt when
201-
bootstrapping your own public showcase repository.
196+
Run without network by providing snapshots and setting `NO_NETWORK_FALLBACK=true`.
202197

203-
### Offline mode
198+
* `CPYTHON_TAGS_SNAPSHOT`: JSON array of CPython tag objects.
199+
* `PYTHON_ORG_HTML_SNAPSHOT`: Raw HTML or path to a saved python.org releases page.
200+
* `RUNNER_MANIFEST_SNAPSHOT`: JSON manifest compatible with `actions/python-versions`.
201+
* `RELEASE_NOTES_SNAPSHOT`: Map tags or versions to release note strings.
204202

205-
Set `NO_NETWORK_FALLBACK=true` and supply snapshots so the action can run without hitting
206-
external endpoints:
203+
Each accepts inline data or a file path. Missing snapshots fail fast with a clear message.
207204

208-
- `CPYTHON_TAGS_SNAPSHOT` – JSON array of CPython tag objects.
209-
- `PYTHON_ORG_HTML_SNAPSHOT` – Raw HTML or path to a saved python.org releases page.
210-
- `RUNNER_MANIFEST_SNAPSHOT` – JSON manifest compatible with `actions/python-versions`.
211-
- `RELEASE_NOTES_SNAPSHOT` – JSON object mapping tags or versions to release note strings.
205+
## Example consumer repositories
212206

213-
Each variable accepts either the data directly or a path to a file containing the snapshot. When
214-
offline mode is enabled and a snapshot is missing, the run will fail fast with a clear message.
207+
See templates in [`examples/`](examples):
215208

216-
---
209+
* [`examples/minimal`](examples/minimal): single-job workflow scheduled weekly.
210+
* [`examples/guarded`](examples/guarded): dry-run preview with release-note gating and concurrency controls.
217211

218212
## Permissions
219213

220-
The workflow requires:
214+
This workflow requires:
221215

222216
```yaml
223217
permissions:
224218
contents: write
225219
pull-requests: write
226220
```
227221

228-
Without these scopes, the action cannot push branches or manage pull requests.
222+
## FAQ
229223

230-
---
224+
**Multiple CPython tracks per run?**
225+
No. If multiple `X.Y` tracks are detected, the run exits with `skipped_reason=multiple_tracks_detected`.
231226

232-
## Frequently asked questions
227+
**Latest is a pre-release?**
228+
Ignored unless `include_prerelease: true`.
233229

234-
**Does it support multiple CPython tracks per run?**
235-
No. If the scan finds multiple `X.Y` tracks, the run exits with `skipped_reason=multiple_tracks_detected` so you can investigate.
230+
**Updates other dependencies?**
231+
No. This action focuses on CPython patch updates for predictability and auditability.
236232

237-
**What if the latest release is a pre-release?**
238-
Pre-releases are ignored unless you set `include_prerelease: true`. The guard protects production workflows from accidental RC bumps.
233+
**Release history?**
234+
See `CHANGELOG.md`.
239235

240-
**Can it update other dependencies?**
241-
The action is laser-focused on CPython patch updates to stay predictable, fast, and audit-friendly.
236+
## Roadmap and contributions
242237

243-
**How do I see progress?**
244-
Check `CHANGELOG.md` for release history and upcoming highlights.
238+
* Read `CONTRIBUTING.md` for local setup and standards.
239+
* Open issues or PRs for edge cases and roadmap items.
245240

246-
---
241+
## Security
247242

248-
## Getting involved
243+
Report security issues privately per `SECURITY.md`.
249244

250-
- Review `CONTRIBUTING.md` for setup instructions and coding standards.
251-
- Open issues or PRs if you spot edge cases or want to collaborate on roadmap tasks.
252-
- Report security issues privately as described in `SECURITY.md`.
245+
## License
253246

254-
---
247+
MIT. See `LICENSE`.
255248

256-
## License
249+
> Like this Action? Star the repo. Adopt it in your org. Share feedback via issues or PRs.
257250

258-
Released under the MIT License. See `LICENSE` for details.
251+
GitHub Action for zero-maintenance CPython patch updates across your repo.

0 commit comments

Comments
 (0)