Pull request formatter and fixer with GitHub integration
Project description
🛠️ Pull Request Fixer
A modern Python tool for automatically fixing pull request titles and bodies across GitHub organizations. Scans for blocked PRs and updates them based on commit messages.
Features
- 🔍 Organization Scanning: Scan entire GitHub organizations for blocked pull requests
- ✍️ Title Fixing: Set PR titles to match the first commit's subject line
- 📝 Body Fixing: Set PR descriptions to match commit message bodies (excluding trailers)
- 🚀 Parallel Processing: Process PRs concurrently for performance
- 🔄 Dry Run Mode: Preview changes before applying them
- 📊 Progress Tracking: Real-time progress updates during scanning
- 🎯 Smart Parsing: Automatically removes Git trailers (Signed-off-by, etc.)
- 💬 PR Comments: Automatically adds a comment to PRs explaining the changes made
Installation
pip install pull-request-fixer
Or with uv:
uv pip install pull-request-fixer
Quick Start
# Set your GitHub token
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
# Fix PR titles in an organization
pull-request-fixer lfreleng-actions --fix-title
# Fix both titles and bodies
pull-request-fixer lfreleng-actions --fix-title --fix-body
# Preview changes without applying (dry run)
pull-request-fixer lfreleng-actions --fix-title --fix-body --dry-run
Usage
Basic Command
pull-request-fixer ORGANIZATION [OPTIONS]
You can specify the organization as:
- Organization name:
myorg - GitHub URL:
https://github.com/myorg - GitHub URL with path:
https://github.com/myorg/
Fix Options
--fix-title
Updates the PR title to match the first line (subject) of the first commit message.
Example:
If the first commit message is:
Fix authentication bug in login handler
This commit addresses an issue where users couldn't
log in with special characters in passwords.
Signed-off-by: John Doe <john@example.com>
This sets the PR title to:
Fix authentication bug in login handler
--fix-body
Updates the PR description to match the commit message body, excluding trailers.
Using the same commit message above, this sets the PR body to:
This commit addresses an issue where users couldn't
log in with special characters in passwords.
The Signed-off-by: trailer is automatically removed.
Common Usage Patterns
Fix titles:
pull-request-fixer myorg --fix-title
Fix both titles and bodies:
pull-request-fixer myorg --fix-title --fix-body
Preview changes (dry run):
pull-request-fixer myorg --fix-title --fix-body --dry-run
Include draft PRs:
pull-request-fixer myorg --fix-title --include-drafts
Use more workers for large organizations:
pull-request-fixer myorg --fix-title --workers 16
Quiet mode for automation:
pull-request-fixer myorg --fix-title --quiet
PR Comments
When the tool applies fixes (not in dry-run mode), it automatically adds a comment to the PR explaining the changes. This provides transparency and helps PR authors understand the automated modifications.
Example comment:
## 🛠️ Pull Request Fixer
Automatically fixed pull request metadata:
- **Pull request title** updated to match first commit
- **Pull request body** updated to match commit message
---
*This fix was automatically applied by [pull-request-fixer](https://github.com/lfit/pull-request-fixer)*
The comment includes the items that changed. For example, if the title changed, that line will appear in the comment.
Options
| Flag | Short | Default | Description |
|---|---|---|---|
--token |
-t |
$GITHUB_TOKEN |
GitHub personal access token |
--fix-title |
false |
Fix PR title to match first commit subject | |
--fix-body |
false |
Fix PR body to match commit message body | |
--include-drafts |
false |
Include draft PRs in scan | |
--dry-run |
false |
Preview changes without applying them | |
--workers |
-j |
4 |
Number of parallel workers (1-32) |
--verbose |
-v |
false |
Enable verbose output |
--quiet |
-q |
false |
Suppress output except errors |
--log-level |
INFO |
Set logging level | |
--version |
Show version and exit | ||
--help |
Show help message |
How It Works
- Scan Organization: Uses GitHub's GraphQL API to efficiently find blocked pull requests
- Fetch Commits: Retrieves the first commit from each PR using the REST API
- Parse Messages: Extracts commit subject and body, removing trailers
- Apply Changes: Updates PR titles and/or bodies in parallel
- Report Results: Shows summary of changes made
Trailers Removed
The following Git trailer patterns are automatically removed from PR bodies:
Signed-off-by:Co-authored-by:Reviewed-by:Tested-by:Acked-by:Cc:Reported-by:Suggested-by:Fixes:See-also:Link:Bug:Change-Id:
Authentication
You need a GitHub personal access token with appropriate permissions:
- Go to GitHub Settings → Developer settings → Personal access tokens
- Generate a new token with
reposcope (orpublic_repofor public repos) - Set the token as an environment variable:
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
Or pass it via the --token flag:
pull-request-fixer myorg --fix-title --token ghp_xxxxxxxxxxxxx
Examples
Example 1: Fix Titles in Organization
pull-request-fixer lfreleng-actions --fix-title
Output:
🔍 Scanning organization: lfreleng-actions
🔧 Will fix: titles
📊 Found 15 blocked PRs to process
🔍 Blocked PRs:
• lfreleng-actions/repo1#123: Update docs
• lfreleng-actions/repo2#456: Fix bug
...
🔄 Processing: lfreleng-actions/repo1#123
✅ Updated title: docs: Add usage examples for CLI
🔄 Processing: lfreleng-actions/repo2#456
✅ Updated title: fix: Resolve authentication timeout issue
✅ Fixed 15 PR(s)
Example 2: Dry Run with Both Fixes
pull-request-fixer myorg --fix-title --fix-body --dry-run
Output:
🔍 Scanning organization: myorg
🔧 Will fix: titles, bodies
🏃 Dry run mode: no changes made
📊 Found 5 blocked PRs to process
🔄 Processing: myorg/repo#123
Would update title:
From: Update documentation
To: docs: Add usage examples for CLI
Would update body
Length: 245 chars
✅ [DRY RUN] Would fix 5 PR(s)
Example 3: High Performance Mode
For large organizations, use more workers:
pull-request-fixer bigorg --fix-title --fix-body --workers 16 --verbose
Performance
- Parallel Processing: PRs processed concurrently for speed
- Efficient Queries: GraphQL for scanning, REST for updates
- Memory Efficient: Streaming results, no need to load all PRs
- Typical Speed: 2-5 seconds per repository
Example timing for 100 repositories with 50 blocked PRs using 8 workers:
- Organization scan: ~30-60 seconds
- PR processing: ~20-30 seconds
- Total: ~50-90 seconds
Troubleshooting
No PRs Found
If the tool reports "No blocked PRs found", this could mean:
- The organization truly has no blocked PRs
- You may need to adjust the scanner's definition of "blocked"
Authentication Errors
If you see authentication errors:
Make sure your GITHUB_TOKEN environment variable contains a valid token
- Verify the token has
repoorpublic_reposcope - Check that the token hasn't expired
Rate Limiting
If you hit rate limits:
- Reduce the number of workers:
--workers 2 - Wait for the rate limit to reset (shown in error message)
- Use a token with higher rate limits
Permission Errors
If updates fail:
- Ensure your token has write access to the repositories
- Check that you're not trying to update PRs in archived repos
- Verify the PRs are not locked
Development
Setup
git clone https://github.com/lfit/pull-request-fixer.git
cd pull-request-fixer
uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"
Running Tests
pytest
Running Pre-commit Hooks
pre-commit install
pre-commit run --all-files
Code Style
The project uses:
rufffor linting and formattingmypyfor type checkingpytestfor testing
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
Apache-2.0
Support
- Issues: https://github.com/lfit/pull-request-fixer/issues
- Documentation: https://github.com/lfit/pull-request-fixer/blob/main/IMPLEMENTATION.md
- Changelog: https://github.com/lfit/pull-request-fixer/blob/main/CHANGELOG.md
Related Projects
- dependamerge - Automatically merge automation PRs
- markdown-table-fixer - Fix markdown table formatting
Acknowledgments
This project uses patterns from:
- dependamerge for efficient GitHub organization scanning
- markdown-table-fixer for the initial codebase structure
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pull_request_fixer-0.1.0.tar.gz.
File metadata
- Download URL: pull_request_fixer-0.1.0.tar.gz
- Upload date:
- Size: 30.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
417363655befd707f8124dc6128e8d71e20286b0ec522995d426c1635c5a09b0
|
|
| MD5 |
26664a54c147ee44727fe2f73253f3c5
|
|
| BLAKE2b-256 |
13f07bf0386537cf4dd96deb3cf42269a2483390616393e025125d850b9af514
|
File details
Details for the file pull_request_fixer-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pull_request_fixer-0.1.0-py3-none-any.whl
- Upload date:
- Size: 32.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3d283e850c2d8d6457b22ef9ab81546c6f96f62e2bbc9443b8388a7e6ac4d0c
|
|
| MD5 |
5b18ed884cf1d51c7614679c412f9ce1
|
|
| BLAKE2b-256 |
5c2e569d3e8306034a59c12b077ba079df70bf39faa95c64c72e61f2b1358938
|