A Python port of the popular create-pull-request GitHub Action. Automatically creates pull requests for changes made during workflow execution.
- Pure Python - Easy to understand and contribute to
- Feature Parity - All 23 inputs and 6 outputs from the original action
- Docker-based - Consistent environment across all runners
- Well Tested - Comprehensive unit and integration test coverage
- PyGithub - Robust GitHub API integration with retry logic
- Robust - Handles rebasing, cherry-picking, and conflict resolution
This port provides:
- Accessibility - More accessible to data scientists and ML engineers
- Maintainability - Easier to contribute for Python-first organizations
- Learning - Great reference for understanding the original implementation
- Compatibility - Drop-in replacement with identical inputs/outputs
name: Create Pull Request
on:
push:
branches:
- main
jobs:
createPullRequest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Make changes
run: |
echo "Updated content" > file.txt
- name: Create Pull Request
uses: dikshant-devops/create-pull-request@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "Update file.txt"
branch: update-file
title: "Automated update to file.txt"
body: |
This PR was automatically created by the create-pull-request action.
## Changes
- Updated file.txt with new content- name: Create Pull Request
uses: dikshant-devops/create-pull-request@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "Update dependencies"
branch: update-deps
title: "chore: Update dependencies"
body: "Automated dependency updates"
labels: |
dependencies
automated
assignees: username1, username2
reviewers: reviewer1
team-reviewers: team-name
milestone: 1- name: Create Pull Request
uses: dikshant-devops/create-pull-request@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: update-
branch-suffix: timestamp
# Creates branch like: update-1707825600- name: Create Pull Request
uses: dikshant-devops/create-pull-request@v1
with:
token: ${{ secrets.PAT_TOKEN }} # Needs repo scope
push-to-fork: username/repo-fork
branch: feature
title: "Feature from fork"| Input | Description | Default |
|---|---|---|
token |
GitHub token for API operations | ${{ github.token }} |
path |
Repository path relative to $GITHUB_WORKSPACE | . |
add-paths |
Comma/newline-separated list of file paths to commit | `` (all changes) |
commit-message |
Commit message | [create-pull-request] automated change |
committer |
Committer name and email Name <email> |
github-actions[bot] <...> |
author |
Author name and email | ${{ github.actor }} <...> |
signoff |
Add Signed-off-by line | false |
sign-commits |
Sign commits with GitHub | false |
branch |
Pull request branch name | create-pull-request/patch |
delete-branch |
Delete branch when closing PR | false |
branch-suffix |
Branch suffix type: none, random, timestamp, short-commit-hash |
none |
base |
Pull request base branch | (current branch) |
push-to-fork |
Fork to push changes to (owner/repo-fork) |
`` |
title |
Pull request title | Changes by create-pull-request action |
body |
Pull request body | `` |
body-path |
Path to file containing PR body | `` |
labels |
Comma/newline-separated list of labels | `` |
assignees |
Comma/newline-separated list of assignees | `` |
reviewers |
Comma/newline-separated list of reviewers | `` |
team-reviewers |
Comma/newline-separated list of team reviewers | `` |
milestone |
Milestone number | 0 |
draft |
Create as draft PR | false |
maintainer-can-modify |
Allow maintainer modifications | true |
| Output | Description |
|---|---|
pull-request-number |
Pull request number |
pull-request-url |
Pull request URL |
pull-request-operation |
Operation performed: created, updated, or closed |
pull-request-head-sha |
Head commit SHA |
pull-request-branch |
Pull request branch name |
pull-request-commits-verified |
Whether commits are verified |
name: Update Data
on:
schedule:
- cron: '0 0 * * *' # Daily at midnight
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fetch latest data
run: |
curl -o data.json https://api.example.com/data
- name: Create PR if data changed
uses: dikshant-devops/create-pull-request@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "Update data.json"
branch: data-update
title: "chore: Update data.json"
body: |
Automated data update from scheduled workflow.
- Source: https://api.example.com/data
- Date: ${{ github.event.repository.updated_at }}
labels: automated, data-updatename: Format Code
on:
pull_request:
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Format code
run: |
pip install black
black .
- name: Create PR for formatting
uses: dikshant-devops/create-pull-request@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "style: Format code with black"
branch: auto-format-${{ github.head_ref }}
title: "Auto-format code in ${{ github.head_ref }}"
body: |
Automatically formatted code with black.
Base PR: #${{ github.event.pull_request.number }}
labels: formattingname: Update Dependencies
on:
workflow_dispatch:
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Update pip packages
run: |
pip install --upgrade pip
pip list --outdated --format=freeze | cut -d= -f1 | xargs pip install -U
pip freeze > requirements.txt
- name: Create PR
uses: dikshant-devops/create-pull-request@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore: Update dependencies"
branch: deps-update
branch-suffix: timestamp
title: "chore: Update Python dependencies"
body: |
Automated dependency updates.
Please review changes and test before merging.
labels: dependencies
reviewers: maintainer-usernamecreate-pull-request-python/
├── src/create_pull_request/
│ ├── main.py # 10-phase orchestration
│ ├── models.py # Dataclasses for config/state
│ ├── git_command_manager.py # Git CLI wrapper
│ ├── git_config_helper.py # Git config state management
│ ├── github_helper.py # PyGithub API wrapper
│ ├── branch_manager.py # Branch creation/update logic
│ ├── utils.py # Parsing and utilities
│ └── exceptions.py # Custom exceptions
The action executes in 10 phases:
- Parse Inputs - Load configuration from environment
- Initialize Git - Set up git command manager
- Save Config - Backup git configuration
- Configure Git - Set up identity and credentials
- Initialize GitHub API - Connect to GitHub with PyGithub
- Determine Base - Resolve base branch
- Create/Update Branch - Complex branch management logic
- Push Branch - Push to origin or fork
- Create/Update PR - Create or update pull request
- Set Outputs - Write outputs and cleanup
| Aspect | TypeScript Original | Python Port |
|---|---|---|
| Language | TypeScript/Node.js | Python 3.11 |
| GitHub API | Octokit | PyGithub |
| Git Operations | @actions/exec | subprocess wrapper |
| Docker Image | ~100MB (Node Alpine) | ~150MB (Python slim) |
| Startup Time | ~2-3s | ~3-4s |
| Inputs | 23 | 23 (identical) |
| Outputs | 6 | 6 (identical) |
| Test Framework | Jest | pytest |
| Type Safety | TypeScript | Python type hints |
Feature Parity: ✅ All features from TypeScript version are implemented
# Clone repository
git clone https://github.com/dikshant-devops/create-pull-request.git
cd create-pull-request-python
# Install dependencies
pip install -r requirements.txt
# Install dev dependencies
pip install pytest pytest-cov pytest-mock ruff mypy# Unit tests
PYTHONPATH=src pytest tests/unit/ -v
# Integration tests
PYTHONPATH=src pytest tests/integration/ -v
# With coverage
PYTHONPATH=src pytest tests/ -v --cov=src/create_pull_request --cov-report=html
# Linting
ruff check src/
# Type checking
mypy src/create_pull_request# Build
docker build -t create-pull-request-python .
# Test locally (requires git repo)
docker run --rm -v $(pwd):/workspace \
-e INPUT_TOKEN=$GITHUB_TOKEN \
-e GITHUB_REPOSITORY=owner/repo \
create-pull-request-pythonContributions welcome! See CONTRIBUTING.md for setup instructions, how to run the same checks as CI locally, and the pull request process.
For maintainers, enable these required status checks on master:
Unit Tests(all matrix entries)Integration TestsDocker BuildLint and Type CheckAnalyze Python(CodeQL)Trivy Image Scan
The Python port is a drop-in replacement - simply change the action reference:
# Before (TypeScript)
- uses: peter-evans/create-pull-request@v6
# After (Python)
- uses: dikshant-devops/create-pull-request@v1All inputs and outputs are identical. No workflow changes required!
This action is ready for the GitHub Actions Marketplace. The action.yml already includes the required branding configuration.
- The repository must be public
- Enable two-factor authentication on your GitHub account
- Accept the GitHub Marketplace Developer Agreement
- Go to the repository on GitHub
- Click Releases > Draft a new release
- Check the Publish this Action to the GitHub Marketplace checkbox
- GitHub will validate your
action.yml-- fix any reported errors - Choose a tag (e.g.,
v1.0.0) and create the release - Once published, the action will appear at
https://github.com/marketplace/actions/create-pull-request-python
| Field | Value |
|---|---|
| Name | Create Pull Request (Python) |
| Icon | git-pull-request |
| Color | blue |
| Author | Create Pull Request Action |
After publishing, users can find and use your action directly from the marketplace.
This is a Python port of the excellent create-pull-request action by Peter Evans. All credit for the original design and implementation goes to the original project.