Create Pull Request (Python)
ActionsA 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.
Create Pull Request (Python) is not certified by GitHub. It is provided by a third-party and is governed by separate terms of service, privacy policy, and support documentation.