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.
Star and watch to get updates. Try the quick start below.
DevOps, SRE, platform, and Python maintainers need consistent runtimes without manual patching. This action:
- Finds pinned CPython versions everywhere you declare them.
- Resolves the latest stable patch and opens an evergreen PR.
- Minimizes diffs and noise. Adds auditability and easy rollbacks.
- Plays well with Renovate and Dependabot.
Keywords: GitHub Action, CPython patch updates, Python version management, automated dependency updates, CI/CD automation, security maintenance.
- Cross-file detection: Dockerfiles, GitHub workflows,
.python-version
,.tool-versions
,runtime.txt
,tox.ini
,pyproject.toml
,Pipfile
, Condaenvironment.yml
, and more. - Smart discovery: Pulls CPython tags from GitHub with python.org fallback. Checks GitHub runner availability. Pre-release guard on by default.
- Minimal rewrites: Targeted replacements that preserve image suffixes like
-slim
and-alpine
. Dry-run summary before writes. - Idempotent: Skips if already on latest and sets
skipped_reason=already_latest
. - Branch and PR automation: Predictable branch name. Updates an existing PR or opens a new one via Octokit.
- External PR support: Emits outputs for
peter-evans/create-pull-request
when preferred. - Automerge ready: Hook for label or merge after checks pass.
- Security keyword gate: Only upgrade if release notes include keywords such as
CVE
orsecurity
. - Offline snapshots: Run without network using provided tag, runner, and release notes snapshots.
- CI matrix fan-out: Output a change matrix to scope targeted jobs.
-
Add a scheduled workflow.
name: CPython Patch Bot on: schedule: - cron: '0 9 * * 1' # every Monday workflow_dispatch: jobs: bump-python: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - uses: actions/checkout@v4 - name: Bump CPython patch versions uses: casperkristiansson/python-version-patch-pr@v1 with: track: '3.12' automerge: false dry_run: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
Review the PR. The action creates or updates
chore/bump-python-<track>
and opens a PR against the default branch. -
Merge or enable automerge. Set
automerge: true
or wire your own automerge job.
- Scan repository for pinned CPython patch versions like
3.12.4
across supported files. - Discover latest patch for the selected
track
using GitHub tags with python.org fallback. - Enforce pre-release guard unless
include_prerelease: true
. - Compute minimal diffs and generate a branch and PR body.
- If no change is needed, exit with
skipped_reason=already_latest
.
Input | Required | Default | Description |
---|---|---|---|
track |
false | 3.13 |
CPython minor series to monitor (for example 3.12 ). |
include_prerelease |
false | false |
Allow rc , a , or b releases when determining the latest patch. |
paths |
false | (see default globs) | Newline-separated glob patterns to scan. |
automerge |
false | false |
Label or merge the bump PR once checks pass. |
dry_run |
false | false |
Skip file writes and emit a change summary instead. |
security_keywords |
false | (empty) | Require at least one keyword to appear in release notes before upgrading. |
use_external_pr_action |
false | false |
Emit outputs for peter-evans/create-pull-request instead of using Octokit internally. |
Default globs
.github/workflows/**/*.yml
Dockerfile
**/Dockerfile
**/*.python-version
**/runtime.txt
**/pyproject.toml
Output | Description |
---|---|
new_version |
Highest CPython patch identified during the run. |
files_changed |
JSON array of files rewritten. |
change_matrix |
JSON object for strategy.matrix fan-out with entries { file, new_version } . |
skipped_reason |
Machine-readable reason when no PR is created (already_latest , multiple_tracks_detected , pre_release_guarded , etc.). |
- name: CPython bump preview
uses: casperkristiansson/python-version-patch-pr@v1
with:
track: '3.13'
dry_run: true
Prints file paths, line numbers, and old -> new
replacements before committing.
with:
include_prerelease: true
Only roll forward when release notes match keywords.
with:
security_keywords: |
CVE
security
When set, the action fetches GitHub release notes for the resolved tag (or uses RELEASE_NOTES_SNAPSHOT
) and skips unless a keyword matches.
- name: Bump CPython patch versions
id: bump_python
uses: casperkristiansson/python-version-patch-pr@v1
with:
use_external_pr_action: true
- name: Create PR with peter-evans
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ steps.bump_python.outputs.branch }}
title: ${{ steps.bump_python.outputs.title }}
body: ${{ steps.bump_python.outputs.body }}
Set automerge: true
and attach your merge strategy in a follow-up job based on the action outputs.
Drive targeted follow-up jobs using the change_matrix
output.
jobs:
bump-python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- id: bump
uses: casperkristiansson/python-version-patch-pr@v1
targeted-tests:
needs: bump-python
if: ${{ needs.bump-python.outputs.skipped_reason == '' }}
strategy:
matrix: ${{ fromJSON(needs.bump-python.outputs.change_matrix) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test -- ${{ matrix.file }}
Avoid competing PRs while keeping other automated dependency updates.
examples/coexistence/renovate.json
disables patch updates for thepython
base image and matching regex managers.examples/coexistence/dependabot.yml
ignores semver patch updates for thepython
Docker image.
Both samples are validated by tests. Copy and adjust schedules or rules as needed.
Run without network by providing snapshots and setting NO_NETWORK_FALLBACK=true
.
CPYTHON_TAGS_SNAPSHOT
: JSON array of CPython tag objects.PYTHON_ORG_HTML_SNAPSHOT
: Raw HTML or path to a saved python.org releases page.RUNNER_MANIFEST_SNAPSHOT
: JSON manifest compatible withactions/python-versions
.RELEASE_NOTES_SNAPSHOT
: Map tags or versions to release note strings.
Each accepts inline data or a file path. Missing snapshots fail fast with a clear message.
See templates in examples/
:
examples/minimal
: single-job workflow scheduled weekly.examples/guarded
: dry-run preview with release-note gating and concurrency controls.
This workflow requires:
permissions:
contents: write
pull-requests: write
In addition to per-job permissions, the repository (or organization) wide setting under Settings → Actions → General → Workflow permissions must grant Read and write permissions and enable “Allow GitHub Actions to create and approve pull requests”. If that toggle cannot be enabled, provide a classic personal access token with repo
scope via a secret (for example PATCH_PR_TOKEN
) and export it as GITHUB_TOKEN
when running the action.
Commits authored by the action default to the current GITHUB_ACTOR
(falling back to github-actions[bot]
). Override this by setting GIT_AUTHOR_NAME
and GIT_AUTHOR_EMAIL
(and matching GIT_COMMITTER_*
) in the workflow environment before invoking the action if you need a custom identity.
Note: The default
GITHUB_TOKEN
cannot push updates to.github/workflows/**
. If the action needs to rewrite workflow files, supply a personal access token that includes theworkflow
scope (often via a secret mapped toGITHUB_TOKEN
). Runs without that scope will skip applying workflow changes and exit withworkflow_permission_required
.
Multiple CPython tracks per run?
No. If multiple X.Y
tracks are detected, the run exits with skipped_reason=multiple_tracks_detected
.
Latest is a pre-release?
Ignored unless include_prerelease: true
.
Updates other dependencies? No. This action focuses on CPython patch updates for predictability and auditability.
Release history?
See CHANGELOG.md
.
- Read
CONTRIBUTING.md
for local setup and standards. - Open issues or PRs for edge cases and roadmap items.
Report security issues privately per SECURITY.md
.
MIT. See LICENSE
.
Like this Action? Star the repo. Adopt it in your org. Share feedback via issues or PRs.
GitHub Action for zero-maintenance CPython patch updates across your repo.