pull-request-fixer 0.1.0__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/.gitignore +1 -0
- pull_request_fixer-0.1.4/PKG-INFO +686 -0
- pull_request_fixer-0.1.4/README.md +644 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/pyproject.toml +102 -22
- pull_request_fixer-0.1.4/src/pull_request_fixer/_version.py +24 -0
- pull_request_fixer-0.1.4/src/pull_request_fixer/blocked_pr_scanner.py +216 -0
- pull_request_fixer-0.1.4/src/pull_request_fixer/cli.py +1858 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/src/pull_request_fixer/exceptions.py +6 -0
- pull_request_fixer-0.1.4/src/pull_request_fixer/file_fixer.py +245 -0
- pull_request_fixer-0.1.4/src/pull_request_fixer/git_config.py +258 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/src/pull_request_fixer/github_client.py +292 -4
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/src/pull_request_fixer/models.py +31 -0
- pull_request_fixer-0.1.4/src/pull_request_fixer/pr_file_fixer.py +896 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/src/pull_request_fixer/pr_scanner.py +128 -7
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/src/pull_request_fixer/progress_tracker.py +8 -8
- pull_request_fixer-0.1.0/PKG-INFO +0 -451
- pull_request_fixer-0.1.0/README.md +0 -411
- pull_request_fixer-0.1.0/src/pull_request_fixer/_version.py +0 -34
- pull_request_fixer-0.1.0/src/pull_request_fixer/cli.py +0 -1059
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/.pre-commit-hooks.yaml +0 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/LICENSE +0 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/LICENSES/Apache-2.0.txt +0 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/scripts/README.md +0 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/src/pull_request_fixer/__init__.py +0 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/src/pull_request_fixer/graphql_queries.py +0 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/src/pull_request_fixer/pr_fixer.py +0 -0
- {pull_request_fixer-0.1.0 → pull_request_fixer-0.1.4}/src/pull_request_fixer/py.typed +0 -0
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pull-request-fixer
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: Pull request formatter and fixer with GitHub integration
|
|
5
|
+
Project-URL: Homepage, https://github.com/lfreleng-actions/pull-request-fixer
|
|
6
|
+
Project-URL: Repository, https://github.com/lfreleng-actions/pull-request-fixer.git
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/lfreleng-actions/pull-request-fixer/issues
|
|
8
|
+
Author-email: The Linux Foundation <releng@linuxfoundation.org>
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: formatter,github,pr,pre-commit,pull-request
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Requires-Dist: aiolimiter>=1.2.1
|
|
27
|
+
Requires-Dist: dependamerge>=0.1.19
|
|
28
|
+
Requires-Dist: httpx[http2]>=0.28.1
|
|
29
|
+
Requires-Dist: pydantic>=2.12.5
|
|
30
|
+
Requires-Dist: rich>=14.2.0
|
|
31
|
+
Requires-Dist: tenacity>=9.1.2
|
|
32
|
+
Requires-Dist: typer>=0.20.0
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: mypy>=1.19.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: pre-commit>=4.5.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest-asyncio>=1.3.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest-mock>=3.15.1; extra == 'dev'
|
|
39
|
+
Requires-Dist: pytest>=9.0.2; extra == 'dev'
|
|
40
|
+
Requires-Dist: ruff>=0.14.8; extra == 'dev'
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
<!--
|
|
44
|
+
SPDX-License-Identifier: Apache-2.0
|
|
45
|
+
SPDX-FileCopyrightText: 2025 The Linux Foundation
|
|
46
|
+
-->
|
|
47
|
+
|
|
48
|
+
# 🛠️ Pull Request Fixer
|
|
49
|
+
|
|
50
|
+
A modern Python tool for automatically fixing pull request titles and bodies
|
|
51
|
+
across GitHub organizations. Scans for blocked PRs and updates them based on
|
|
52
|
+
commit messages.
|
|
53
|
+
|
|
54
|
+
## Features
|
|
55
|
+
|
|
56
|
+
- **🔍 Organization Scanning**: Scan entire GitHub organizations for blocked
|
|
57
|
+
pull requests
|
|
58
|
+
- **✍️ Title Fixing**: Set PR titles to match the first commit's subject line
|
|
59
|
+
- **📝 Body Fixing**: Set PR descriptions to match commit message bodies
|
|
60
|
+
(excluding trailers)
|
|
61
|
+
- **📄 File Fixing**: Apply regex-based search/replace to files in PRs (clones,
|
|
62
|
+
modifies, amends commit, and force-pushes changes)
|
|
63
|
+
- **🚫 Blocked PR Filtering**: Option to process PRs that cannot merge
|
|
64
|
+
(failing checks, conflicts, etc.)
|
|
65
|
+
- **🚀 Parallel Processing**: Process PRs concurrently for
|
|
66
|
+
performance
|
|
67
|
+
- **🔄 Dry Run Mode**: Preview changes before applying them
|
|
68
|
+
- **📊 Progress Tracking**: Real-time progress updates during scanning
|
|
69
|
+
- **🎯 Smart Parsing**: Automatically removes Git trailers (Signed-off-by, etc.)
|
|
70
|
+
- **💬 PR Comments**: Automatically adds a comment to PRs explaining the
|
|
71
|
+
changes made
|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install pull-request-fixer
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Or with uv:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
uv pip install pull-request-fixer
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Quick Start
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Set your GitHub token
|
|
89
|
+
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
|
|
90
|
+
|
|
91
|
+
# Fix PR titles in an organization
|
|
92
|
+
pull-request-fixer lfreleng-actions --fix-title
|
|
93
|
+
|
|
94
|
+
# Fix both titles and bodies
|
|
95
|
+
pull-request-fixer lfreleng-actions --fix-title --fix-body
|
|
96
|
+
|
|
97
|
+
# Show help (includes version)
|
|
98
|
+
pull-request-fixer --help
|
|
99
|
+
|
|
100
|
+
# Fix files in a specific PR using regex
|
|
101
|
+
pull-request-fixer https://github.com/owner/repo/pull/123 \
|
|
102
|
+
--fix-files \
|
|
103
|
+
--file-pattern './action.yaml' \
|
|
104
|
+
--search-pattern '^\s+type:\s+\S' \
|
|
105
|
+
--remove-lines \
|
|
106
|
+
--context-start 'inputs:' \
|
|
107
|
+
--context-end 'runs:' \
|
|
108
|
+
--dry-run \
|
|
109
|
+
--show-diff
|
|
110
|
+
|
|
111
|
+
# Preview changes without applying (dry run)
|
|
112
|
+
pull-request-fixer lfreleng-actions --fix-title --fix-body --dry-run
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Usage
|
|
116
|
+
|
|
117
|
+
### Basic Commands
|
|
118
|
+
|
|
119
|
+
**Scan and fix an organization:**
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
pull-request-fixer ORGANIZATION [OPTIONS]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Fix a specific PR:**
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pull-request-fixer PR_URL [OPTIONS]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
You can specify the target as:
|
|
132
|
+
|
|
133
|
+
- Organization name: `myorg`
|
|
134
|
+
- GitHub URL: `https://github.com/myorg`
|
|
135
|
+
- GitHub URL with path: `https://github.com/myorg/`
|
|
136
|
+
- Specific PR URL: `https://github.com/owner/repo/pull/123`
|
|
137
|
+
|
|
138
|
+
### Fix Options
|
|
139
|
+
|
|
140
|
+
#### `--fix-title`
|
|
141
|
+
|
|
142
|
+
Updates the PR title to match the first line (subject) of the first commit message.
|
|
143
|
+
|
|
144
|
+
**Example:**
|
|
145
|
+
|
|
146
|
+
If the first commit message is:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
Fix authentication bug in login handler
|
|
150
|
+
|
|
151
|
+
This commit addresses an issue where users couldn't
|
|
152
|
+
log in with special characters in passwords.
|
|
153
|
+
|
|
154
|
+
Signed-off-by: John Doe <john@example.com>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This sets the PR title to:
|
|
158
|
+
|
|
159
|
+
```text
|
|
160
|
+
Fix authentication bug in login handler
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
#### `--fix-body`
|
|
164
|
+
|
|
165
|
+
Updates the PR description to match the commit message body, excluding trailers.
|
|
166
|
+
|
|
167
|
+
Using the same commit message above, this sets the PR body to:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
This commit addresses an issue where users couldn't
|
|
171
|
+
log in with special characters in passwords.
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The `Signed-off-by:` trailer is automatically removed.
|
|
175
|
+
|
|
176
|
+
#### `--fix-files`
|
|
177
|
+
|
|
178
|
+
Fixes files in pull requests using regex-based search and replace. This feature:
|
|
179
|
+
|
|
180
|
+
1. Clones the PR branch
|
|
181
|
+
2. Finds files matching `--file-pattern` (regex)
|
|
182
|
+
3. Applies search/replace using `--search-pattern` and `--replacement`
|
|
183
|
+
4. Amends the last commit with the changes
|
|
184
|
+
5. Force-pushes the updated commit back to the PR
|
|
185
|
+
|
|
186
|
+
**Required options when using `--fix-files`:**
|
|
187
|
+
|
|
188
|
+
- `--file-pattern`: Regex to match file paths (e.g., `'./action.yaml'` or
|
|
189
|
+
`'.*\.yaml$'`)
|
|
190
|
+
- `--search-pattern`: Regex pattern to find in matched files
|
|
191
|
+
- Either `--replacement` (text to replace matches) or `--remove-lines` (to
|
|
192
|
+
delete matching lines)
|
|
193
|
+
|
|
194
|
+
**Optional context options (for line removal):**
|
|
195
|
+
|
|
196
|
+
- `--context-start`: Regex to define where the removal context begins (e.g., `'inputs:'`)
|
|
197
|
+
- `--context-end`: Regex to define where the removal context ends (e.g., `'runs:'`)
|
|
198
|
+
|
|
199
|
+
**Optional display options:**
|
|
200
|
+
|
|
201
|
+
- `--show-diff`: Show unified diff output for file changes
|
|
202
|
+
|
|
203
|
+
#### Update Methods (for `--fix-files` only)
|
|
204
|
+
|
|
205
|
+
The tool supports two methods for applying file fixes:
|
|
206
|
+
|
|
207
|
+
**API Method (default)** - Uses GitHub API to create new commits:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
pull-request-fixer https://github.com/owner/repo/pull/123 \
|
|
211
|
+
--fix-files \
|
|
212
|
+
--file-pattern './action.yaml' \
|
|
213
|
+
--search-pattern 'pattern'
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
- Creates new commits via GitHub API
|
|
217
|
+
- Shows as "Verified" by GitHub
|
|
218
|
+
- No Git operations required
|
|
219
|
+
- Faster and simpler
|
|
220
|
+
- Default method for ease of use
|
|
221
|
+
|
|
222
|
+
**Git Method** - Clones repo, amends commit, force-pushes:
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
pull-request-fixer https://github.com/owner/repo/pull/123 \
|
|
226
|
+
--fix-files \
|
|
227
|
+
--update-method git \
|
|
228
|
+
--file-pattern './action.yaml' \
|
|
229
|
+
--search-pattern 'pattern'
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
- Respects your local Git signing configuration
|
|
233
|
+
- Amends the existing commit (preserves commit history)
|
|
234
|
+
- Requires Git operations (clone, amend, push)
|
|
235
|
+
- Use when you need to amend commits or use your own signature
|
|
236
|
+
|
|
237
|
+
**Example - Remove type definitions from GitHub Actions:**
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
pull-request-fixer https://github.com/owner/repo/pull/123 \
|
|
241
|
+
--fix-files \
|
|
242
|
+
--file-pattern './action.yaml' \
|
|
243
|
+
--search-pattern '^\s+type:\s+\S' \
|
|
244
|
+
--remove-lines \
|
|
245
|
+
--context-start 'inputs:' \
|
|
246
|
+
--context-end 'runs:' \
|
|
247
|
+
--dry-run \
|
|
248
|
+
--show-diff
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
This will remove lines containing `type:` that appear between `inputs:` and `runs:`
|
|
252
|
+
sections in `action.yaml` files.
|
|
253
|
+
|
|
254
|
+
**Example - Replace text with regex:**
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
pull-request-fixer https://github.com/owner/repo/pull/456 \
|
|
258
|
+
--fix-files \
|
|
259
|
+
--file-pattern '.*\.py$' \
|
|
260
|
+
--search-pattern 'old_function_name' \
|
|
261
|
+
--replacement 'new_function_name'
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Common Usage Patterns
|
|
265
|
+
|
|
266
|
+
**Fix titles:**
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
pull-request-fixer myorg --fix-title
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Fix both titles and bodies:**
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
pull-request-fixer myorg --fix-title --fix-body
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Preview changes (dry run):**
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
pull-request-fixer myorg --fix-title --fix-body --dry-run
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Include draft PRs:**
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
pull-request-fixer myorg --fix-title --include-drafts
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Use more workers for large organizations:**
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
pull-request-fixer myorg --fix-title --workers 16
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Quiet mode for automation:**
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
pull-request-fixer myorg --fix-title --quiet
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
**Verbose mode for debugging:**
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
pull-request-fixer myorg --fix-files --file-pattern '*.yaml' \
|
|
306
|
+
--search-pattern '^\s+type:\s+\S' --remove-lines \
|
|
307
|
+
--verbose # Shows detailed DEBUG logs including file operations
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Process blocked PRs:**
|
|
311
|
+
|
|
312
|
+
<!-- write-good-disable -->
|
|
313
|
+
```bash
|
|
314
|
+
pull-request-fixer myorg --fix-title --blocked-only
|
|
315
|
+
```
|
|
316
|
+
<!-- write-good-enable -->
|
|
317
|
+
|
|
318
|
+
**Fix files across PRs:**
|
|
319
|
+
|
|
320
|
+
<!-- write-good-disable -->
|
|
321
|
+
```bash
|
|
322
|
+
pull-request-fixer myorg \
|
|
323
|
+
--fix-files \
|
|
324
|
+
--file-pattern './action.yaml' \
|
|
325
|
+
--search-pattern '^\s+type:\s+\S' \
|
|
326
|
+
--remove-lines \
|
|
327
|
+
--context-start 'inputs:' \
|
|
328
|
+
--context-end 'runs:' \
|
|
329
|
+
--blocked-only \
|
|
330
|
+
--dry-run
|
|
331
|
+
```
|
|
332
|
+
<!-- write-good-enable -->
|
|
333
|
+
|
|
334
|
+
## PR Comments
|
|
335
|
+
|
|
336
|
+
When the tool applies fixes (not in dry-run mode), it automatically adds a
|
|
337
|
+
comment to the PR explaining the changes. This provides transparency and
|
|
338
|
+
helps PR authors understand the automated modifications.
|
|
339
|
+
|
|
340
|
+
**Example comment:**
|
|
341
|
+
|
|
342
|
+
```markdown
|
|
343
|
+
## 🛠️ Pull Request Fixer
|
|
344
|
+
|
|
345
|
+
Automatically fixed pull request metadata:
|
|
346
|
+
- **Pull request title** updated to match first commit
|
|
347
|
+
- **Pull request body** updated to match commit message
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
*This fix was automatically applied by [pull-request-fixer](https://github.com/lfreleng-actions/pull-request-fixer)*
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
The comment includes the items that changed. For
|
|
354
|
+
example, if the title changed, that line will appear in the
|
|
355
|
+
comment.
|
|
356
|
+
|
|
357
|
+
## Options
|
|
358
|
+
|
|
359
|
+
<!-- markdownlint-disable MD013 -->
|
|
360
|
+
<!-- write-good-disable -->
|
|
361
|
+
|
|
362
|
+
| Flag | Short | Default | Description |
|
|
363
|
+
| ------------------ | ----- | --------------- | ----------------------------------------------------- |
|
|
364
|
+
| `--help` | `-h` | | Show help message and exit (displays version) |
|
|
365
|
+
| `--token` | `-t` | `$GITHUB_TOKEN` | GitHub personal access token |
|
|
366
|
+
| `--fix-title` | | `false` | Fix PR title to match first commit subject |
|
|
367
|
+
| `--fix-body` | | `false` | Fix PR body to match commit message body |
|
|
368
|
+
| `--fix-files` | | `false` | Fix files in PR using regex search/replace |
|
|
369
|
+
| `--file-pattern` | | | Regex to match file paths (required w/ `--fix-files`) |
|
|
370
|
+
| `--search-pattern` | | | Regex to search in files (required w/ `--fix-files`) |
|
|
371
|
+
| `--replacement` | | | Replacement string for matched patterns |
|
|
372
|
+
| `--remove-lines` | | `false` | Remove matching lines instead of replacing |
|
|
373
|
+
| `--context-start` | | | Regex pattern for context start (for line removal) |
|
|
374
|
+
| `--context-end` | | | Regex pattern for context end (for line removal) |
|
|
375
|
+
| `--show-diff` | | `false` | Show unified diff output for file changes |
|
|
376
|
+
| `--include-drafts` | | `false` | Include draft PRs in scan |
|
|
377
|
+
| `--blocked-only` | | `false` | Process PRs that cannot merge |
|
|
378
|
+
| `--dry-run` | | `false` | Preview changes without applying them |
|
|
379
|
+
| `--workers` | `-j` | `4` | Number of parallel workers (1-32) |
|
|
380
|
+
| `--verbose` | `-v` | `false` | Enable verbose output (DEBUG logs) |
|
|
381
|
+
| `--quiet` | `-q` | `false` | Suppress output except errors |
|
|
382
|
+
| `--log-level` | | `INFO` | Set logging level |
|
|
383
|
+
| `--version` | | | Show version and exit |
|
|
384
|
+
|
|
385
|
+
<!-- write-good-enable -->
|
|
386
|
+
<!-- markdownlint-enable MD013 -->
|
|
387
|
+
|
|
388
|
+
## How It Works
|
|
389
|
+
|
|
390
|
+
1. **Scan Organization**: Uses GitHub's GraphQL API to efficiently find
|
|
391
|
+
blocked pull requests
|
|
392
|
+
2. **Fetch Commits**: Retrieves the first commit from each PR using the REST
|
|
393
|
+
API
|
|
394
|
+
3. **Parse Messages**: Extracts commit subject and body, removing trailers
|
|
395
|
+
4. **Apply Changes**: Updates PR titles and/or bodies in parallel
|
|
396
|
+
5. **Report Results**: Shows summary of changes made
|
|
397
|
+
|
|
398
|
+
### Trailers Removed
|
|
399
|
+
|
|
400
|
+
The following Git trailer patterns are automatically removed from PR bodies:
|
|
401
|
+
|
|
402
|
+
- `Signed-off-by:`
|
|
403
|
+
- `Co-authored-by:`
|
|
404
|
+
- `Reviewed-by:`
|
|
405
|
+
- `Tested-by:`
|
|
406
|
+
- `Acked-by:`
|
|
407
|
+
- `Cc:`
|
|
408
|
+
- `Reported-by:`
|
|
409
|
+
- `Suggested-by:`
|
|
410
|
+
- `Fixes:`
|
|
411
|
+
- `See-also:`
|
|
412
|
+
- `Link:`
|
|
413
|
+
- `Bug:`
|
|
414
|
+
- `Change-Id:`
|
|
415
|
+
|
|
416
|
+
## Authentication
|
|
417
|
+
|
|
418
|
+
You need a GitHub personal access token with appropriate permissions:
|
|
419
|
+
|
|
420
|
+
1. Go to GitHub Settings → Developer settings → Personal access tokens
|
|
421
|
+
2. Generate a new token with `repo` scope (or `public_repo` for public repos)
|
|
422
|
+
3. Set the token as an environment variable:
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxx
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Or pass it via the `--token` flag:
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
pull-request-fixer myorg --fix-title --token ghp_xxxxxxxxxxxxx
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
## Examples
|
|
435
|
+
|
|
436
|
+
### Example 1: Fix Titles in Organization
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
pull-request-fixer lfreleng-actions --fix-title
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
Output:
|
|
443
|
+
|
|
444
|
+
```text
|
|
445
|
+
🔍 Scanning organization: lfreleng-actions
|
|
446
|
+
🔧 Will fix: titles
|
|
447
|
+
|
|
448
|
+
📊 Found 15 blocked PRs to process
|
|
449
|
+
|
|
450
|
+
🔍 Blocked PRs:
|
|
451
|
+
• lfreleng-actions/repo1#123: Update docs
|
|
452
|
+
• lfreleng-actions/repo2#456: Fix bug
|
|
453
|
+
...
|
|
454
|
+
|
|
455
|
+
🔄 Processing: lfreleng-actions/repo1#123
|
|
456
|
+
✅ Updated title: docs: Add usage examples for CLI
|
|
457
|
+
|
|
458
|
+
🔄 Processing: lfreleng-actions/repo2#456
|
|
459
|
+
✅ Updated title: fix: Resolve authentication timeout issue
|
|
460
|
+
|
|
461
|
+
✅ Fixed 15 PR(s)
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Example 2: Dry Run with Both Fixes
|
|
465
|
+
|
|
466
|
+
```bash
|
|
467
|
+
pull-request-fixer myorg --fix-title --fix-body --dry-run
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Output:
|
|
471
|
+
|
|
472
|
+
```text
|
|
473
|
+
🔍 Scanning organization: myorg
|
|
474
|
+
🔧 Will fix: titles, bodies
|
|
475
|
+
🏃 Dry run mode: no changes made
|
|
476
|
+
|
|
477
|
+
📊 Found 5 blocked PRs to process
|
|
478
|
+
|
|
479
|
+
🔄 Processing: myorg/repo#123
|
|
480
|
+
Would update title:
|
|
481
|
+
From: Update documentation
|
|
482
|
+
To: docs: Add usage examples for CLI
|
|
483
|
+
Would update body
|
|
484
|
+
Length: 245 chars
|
|
485
|
+
|
|
486
|
+
✅ [DRY RUN] Would fix 5 PR(s)
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Example 3: High Performance Mode
|
|
490
|
+
|
|
491
|
+
For large organizations, use more workers:
|
|
492
|
+
|
|
493
|
+
```bash
|
|
494
|
+
pull-request-fixer bigorg --fix-title --fix-body --workers 16 --verbose
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Performance
|
|
498
|
+
|
|
499
|
+
- **Parallel Processing**: PRs processed concurrently for speed
|
|
500
|
+
- **Efficient Queries**: GraphQL for scanning, REST for updates
|
|
501
|
+
- **Memory Efficient**: Streaming results, no need to load all PRs
|
|
502
|
+
- **Typical Speed**: 2-5 seconds per repository
|
|
503
|
+
|
|
504
|
+
Example timing for 100 repositories with 50 blocked PRs using 8 workers:
|
|
505
|
+
|
|
506
|
+
- Organization scan: ~30-60 seconds
|
|
507
|
+
- PR processing: ~20-30 seconds
|
|
508
|
+
- **Total: ~50-90 seconds**
|
|
509
|
+
|
|
510
|
+
### Example 4: Fix Files in a Blocked PR
|
|
511
|
+
|
|
512
|
+
This example removes invalid `type:` definitions from a GitHub composite action:
|
|
513
|
+
|
|
514
|
+
```bash
|
|
515
|
+
pull-request-fixer https://github.com/lfreleng-actions/make-action/pull/40 \
|
|
516
|
+
--fix-files \
|
|
517
|
+
--file-pattern './action.yaml' \
|
|
518
|
+
--search-pattern '^\s+type:\s+\S' \
|
|
519
|
+
--remove-lines \
|
|
520
|
+
--context-start 'inputs:' \
|
|
521
|
+
--context-end 'runs:' \
|
|
522
|
+
--dry-run \
|
|
523
|
+
--show-diff
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Output:
|
|
527
|
+
|
|
528
|
+
```text
|
|
529
|
+
🔍 Processing PR: https://github.com/lfreleng-actions/make-action/pull/40
|
|
530
|
+
🔧 Will fix: files
|
|
531
|
+
🏃 Dry run mode: the tool will not apply changes
|
|
532
|
+
|
|
533
|
+
📝 Fixing files in PR...
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
✅ Would fix 1 file
|
|
537
|
+
📂 action.yaml
|
|
538
|
+
--- action.yaml
|
|
539
|
+
+++ action.yaml
|
|
540
|
+
@@ -10,7 +10,6 @@
|
|
541
|
+
repository:
|
|
542
|
+
description: 'Remote Git repository URL'
|
|
543
|
+
required: false
|
|
544
|
+
|
|
545
|
+
- type: 'string'
|
|
546
|
+
debug:
|
|
547
|
+
description: 'Enable debug mode'
|
|
548
|
+
required: false
|
|
549
|
+
- type: 'boolean'
|
|
550
|
+
|
|
551
|
+
Dry-run completed!
|
|
552
|
+
|
|
553
|
+
```text
|
|
554
|
+
|
|
555
|
+
Without `--dry-run`, the output would show:
|
|
556
|
+
|
|
557
|
+
```text
|
|
558
|
+
✅ Updated 1 file
|
|
559
|
+
🔀 action.yaml
|
|
560
|
+
--- action.yaml
|
|
561
|
+
+++ action.yaml
|
|
562
|
+
@@ -10,7 +10,6 @@
|
|
563
|
+
repository:
|
|
564
|
+
description: 'Remote Git repository URL'
|
|
565
|
+
required: false
|
|
566
|
+
- type: 'string'
|
|
567
|
+
debug:
|
|
568
|
+
description: 'Enable debug mode'
|
|
569
|
+
required: false
|
|
570
|
+
- type: 'boolean'
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
This would:
|
|
574
|
+
|
|
575
|
+
1. Clone the PR branch
|
|
576
|
+
2. Remove all lines containing `type:` from the `inputs:` section of `action.yaml`
|
|
577
|
+
3. Amend the last commit with the changes
|
|
578
|
+
4. Force-push the updated commit
|
|
579
|
+
5. Add a comment to the PR explaining the fix
|
|
580
|
+
|
|
581
|
+
## Troubleshooting
|
|
582
|
+
|
|
583
|
+
### No PRs Found
|
|
584
|
+
|
|
585
|
+
If the tool reports "No blocked PRs found", this could mean:
|
|
586
|
+
|
|
587
|
+
- The organization truly has no blocked PRs
|
|
588
|
+
- You may need to adjust the scanner's definition of "blocked"
|
|
589
|
+
|
|
590
|
+
### Authentication Errors
|
|
591
|
+
|
|
592
|
+
If you see authentication errors:
|
|
593
|
+
|
|
594
|
+
Make sure your `GITHUB_TOKEN` environment variable contains a valid token
|
|
595
|
+
|
|
596
|
+
- Verify the token has `repo` or `public_repo` scope
|
|
597
|
+
- Check that the token hasn't expired
|
|
598
|
+
|
|
599
|
+
### Rate Limiting
|
|
600
|
+
|
|
601
|
+
If you hit rate limits:
|
|
602
|
+
|
|
603
|
+
- Reduce the number of workers: `--workers 2`
|
|
604
|
+
- Wait for the rate limit to reset (shown in error message)
|
|
605
|
+
- Use a token with higher rate limits
|
|
606
|
+
|
|
607
|
+
### Permission Errors
|
|
608
|
+
|
|
609
|
+
If updates fail:
|
|
610
|
+
|
|
611
|
+
- Ensure your token has write access to the repositories
|
|
612
|
+
- Check that you're not trying to update PRs in archived repos
|
|
613
|
+
- Verify the PRs are not locked
|
|
614
|
+
|
|
615
|
+
## Development
|
|
616
|
+
|
|
617
|
+
### Setup
|
|
618
|
+
|
|
619
|
+
```bash
|
|
620
|
+
git clone https://github.com/lfreleng-actions/pull-request-fixer.git
|
|
621
|
+
cd pull-request-fixer
|
|
622
|
+
uv venv
|
|
623
|
+
source .venv/bin/activate
|
|
624
|
+
uv pip install -e ".[dev]"
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### Running Tests
|
|
628
|
+
|
|
629
|
+
```bash
|
|
630
|
+
pytest
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Running Pre-commit Hooks
|
|
634
|
+
|
|
635
|
+
```bash
|
|
636
|
+
pre-commit install
|
|
637
|
+
pre-commit run --all-files
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
### Code Style
|
|
641
|
+
|
|
642
|
+
The project uses:
|
|
643
|
+
|
|
644
|
+
- `ruff` for linting and formatting
|
|
645
|
+
- `mypy` for type checking
|
|
646
|
+
- `pytest` for testing
|
|
647
|
+
|
|
648
|
+
## Contributing
|
|
649
|
+
|
|
650
|
+
Contributions are welcome! Please:
|
|
651
|
+
|
|
652
|
+
1. Fork the repository
|
|
653
|
+
2. Create a feature branch
|
|
654
|
+
3. Make your changes
|
|
655
|
+
4. Add tests for new functionality
|
|
656
|
+
5. Ensure all tests pass
|
|
657
|
+
6. Submit a pull request
|
|
658
|
+
|
|
659
|
+
## License
|
|
660
|
+
|
|
661
|
+
Apache-2.0
|
|
662
|
+
|
|
663
|
+
## Support
|
|
664
|
+
|
|
665
|
+
- **Issues**:
|
|
666
|
+
<https://github.com/lfreleng-actions/pull-request-fixer/issues>
|
|
667
|
+
- **Documentation**:
|
|
668
|
+
<https://github.com/lfreleng-actions/pull-request-fixer/blob/main/IMPLEMENTATION.md>
|
|
669
|
+
- **Changelog**:
|
|
670
|
+
<https://github.com/lfreleng-actions/pull-request-fixer/blob/main/CHANGELOG.md>
|
|
671
|
+
|
|
672
|
+
## Related Projects
|
|
673
|
+
|
|
674
|
+
- [dependamerge](https://github.com/lfit/dependamerge) - Automatically merge
|
|
675
|
+
automation PRs
|
|
676
|
+
- [markdown-table-fixer][mtf-repo] - Fix markdown table formatting
|
|
677
|
+
|
|
678
|
+
## Acknowledgments
|
|
679
|
+
|
|
680
|
+
This project uses patterns from:
|
|
681
|
+
|
|
682
|
+
- [dependamerge](https://github.com/lfit/dependamerge) for efficient
|
|
683
|
+
GitHub organization scanning
|
|
684
|
+
- [markdown-table-fixer][mtf-repo] for the initial codebase structure
|
|
685
|
+
|
|
686
|
+
[mtf-repo]: https://github.com/lfreleng-actions/markdown-table-fixer
|