Skip to content

Commit 63ca6e8

Browse files
Feat!: Enhance pull request close/reconciliation handling
- Add GitHub PR close handling after Gerrit change is merged - Add CLI ability to accept Gerrit change as input, close PRs - New --force flag will close GitHub PRs for Abandoned changes - Add code to extract GitHub ORG from Gerrit change content - Only display relevant output in GitHub2Gerrit Configuration - Bypass uvx when testing/developing against branches in forks - Improve isolation to address failing pre-commit pytest hook - Add new automation_only input and CLI flag to reject user PRs Signed-off-by: Matthew Watkins <mwatkins@linuxfoundation.org>
1 parent 406fc75 commit 63ca6e8

23 files changed

Lines changed: 3829 additions & 254 deletions

.github/workflows/github2gerrit.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ on:
6868
PRESERVE_GITHUB_PRS:
6969
description: "Do not close GitHub PRs after pushing to Gerrit"
7070
required: false
71-
default: false
71+
default: true
7272
type: boolean
7373
DRY_RUN:
7474
description: "Validate settings and PR metadata; do not write to Gerrit"

.github/workflows/testing.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ jobs:
4040
GERRIT_KNOWN_HOSTS: 'dummy-host ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC...'
4141
GERRIT_SSH_PRIVKEY_G2G: 'dummy-key'
4242
DRY_RUN: 'true'
43+
AUTOMATION_ONLY: 'false'
4344

4445
# yamllint disable-line rule:line-length
4546
- name: "Running local action: ${{ github.repository }} [Failure]"
@@ -53,6 +54,7 @@ jobs:
5354
GERRIT_KNOWN_HOSTS: "dummy-host ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC..."
5455
GERRIT_SSH_PRIVKEY_G2G: ""
5556
DRY_RUN: 'true'
57+
AUTOMATION_ONLY: 'false'
5658

5759
# Failure testing is also important
5860
- name: "Error if step above did NOT fail"

README.md

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,106 @@ Gerrit `Change-Id` trailers to create or update changes.
3232
- Query Gerrit for the resulting URL, change number, and patchset SHA.
3333
- Add a back‑reference comment in Gerrit to the GitHub PR and run URL.
3434
- Comment on the GitHub PR with the Gerrit change URL(s).
35-
- Optionally close the PR (mirrors the shell action policy).
35+
- By default, the tool preserves PRs after submission; set `PRESERVE_GITHUB_PRS=false` to close them.
36+
37+
## Close Merged PRs Feature
38+
39+
GitHub2Gerrit now includes **automatic PR closure** when Gerrit merges changes
40+
and syncs them back to GitHub. This completes the lifecycle for automation PRs
41+
(like Dependabot).
42+
43+
**How it works:**
44+
45+
1. A bot (e.g., Dependabot) creates a GitHub PR
46+
2. GitHub2Gerrit converts it to a Gerrit change with tracking information
47+
3. When the Gerrit change is **merged** and synced to GitHub, the original PR is automatically closed
48+
4. When the Gerrit change is **abandoned**, the tool handles the PR based on `CLOSE_MERGED_PRS`:
49+
- If `CLOSE_MERGED_PRS=true` (default): The tool closes the PR with an abandoned comment ⛔️
50+
- If `CLOSE_MERGED_PRS=false`: PR remains open, but receives an abandoned notification comment ⛔️
51+
52+
**Key characteristics:**
53+
54+
- **Enabled by default** via `CLOSE_MERGED_PRS=true`
55+
- **Non-fatal operation** - the tool logs missing or already-closed PRs as
56+
info, not errors
57+
- Works on `push` events when Gerrit syncs changes to GitHub mirrors
58+
- **Abandoned change handling**: The tool closes PRs or adds comments based on the `CLOSE_MERGED_PRS` setting
59+
60+
**Gerrit change status handling:**
61+
62+
| Scenario | `CLOSE_MERGED_PRS=true` (default) | `CLOSE_MERGED_PRS=false` |
63+
|----------|-----------------------------------|--------------------------|
64+
| Change has MERGED status | ✅ Closes PR with merged comment | ⏭️ No action |
65+
| Change has ABANDONED status | ✅ Closes PR with abandoned comment ⛔️ | 💬 Adds abandoned notification comment (PR stays open) |
66+
| Change is NEW/OPEN | ⚠️ Closes PR with a warning | ⏭️ No action |
67+
| Status UNKNOWN | ⚠️ Closes PR with a warning | ⏭️ No action |
68+
69+
**Status reporting examples:**
70+
71+
```text
72+
No GitHub PR URL found in commit abc123de - skipping
73+
GitHub PR #42 is already closed - nothing to do
74+
Gerrit change confirmed as MERGED
75+
SUCCESS: Closed GitHub PR #42
76+
```
77+
78+
**Abandoned change examples:**
79+
80+
With `CLOSE_MERGED_PRS=true`:
81+
82+
```text
83+
Gerrit change ABANDONED; will close PR with abandoned comment
84+
SUCCESS: Closed GitHub PR #42
85+
```
86+
87+
With `CLOSE_MERGED_PRS=false`:
88+
89+
```text
90+
Gerrit change ABANDONED; will add comment (CLOSE_MERGED_PRS=false)
91+
SUCCESS: Added comment to PR #42 (PR remains open)
92+
```
93+
94+
## Restrict PRs to Automation Tools
95+
96+
GitHub2Gerrit can restrict pull request processing to known automation tools.
97+
Use this for GitHub mirrors where you want contributors to submit changes via
98+
Gerrit, while still accepting automated dependency updates from tools like
99+
Dependabot.
100+
101+
**Configuration:**
102+
103+
Set `AUTOMATION_ONLY=true` (default) to enable, or `AUTOMATION_ONLY=false`
104+
to accept all PRs.
105+
106+
**Recognized automation tools:**
107+
108+
| Tool | GitHub Username(s) |
109+
|------|-------------------|
110+
| Dependabot | `dependabot[bot]`, `dependabot` |
111+
| Pre-commit.ci | `pre-commit-ci[bot]`, `pre-commit-ci` |
112+
113+
**What happens when enabled:**
114+
115+
The tool rejects PRs from non-automation users by:
116+
117+
1. Logging a warning message
118+
2. Closing the PR with this comment:
119+
120+
```text
121+
This GitHub mirror does not accept pull requests.
122+
Please submit changes to the project's Gerrit server.
123+
```
124+
125+
3. Exiting with code 1
126+
127+
**Example:**
128+
129+
```yaml
130+
- uses: lfit/github2gerrit-action@main
131+
with:
132+
AUTOMATION_ONLY: "true" # default, accepts automation PRs
133+
GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY }}
134+
```
36135
37136
## Requirements
38137
@@ -664,7 +763,7 @@ alignment between action inputs, environment variables, and CLI flags:
664763
| `ORGANIZATION` | `ORGANIZATION` | `--organization` | No | `${{ github.repository_owner }}` | GitHub organization/owner |
665764
| `REVIEWERS_EMAIL` | `REVIEWERS_EMAIL` | `--reviewers-email` | No | `""` | Comma-separated reviewer emails |
666765
| `ALLOW_GHE_URLS` | `ALLOW_GHE_URLS` | `--allow-ghe-urls` | No | `"false"` | Allow GitHub Enterprise URLs in direct URL mode |
667-
| `PRESERVE_GITHUB_PRS` | `PRESERVE_GITHUB_PRS` | `--preserve-github-prs` | No | `"false"` | Do not close GitHub PRs after pushing to Gerrit |
766+
| `PRESERVE_GITHUB_PRS` | `PRESERVE_GITHUB_PRS` | `--preserve-github-prs` | No | `"true"` | Do not close GitHub PRs after pushing to Gerrit |
668767
| `DRY_RUN` | `DRY_RUN` | `--dry-run` | No | `"false"` | Check settings/PR metadata; do not write to Gerrit |
669768
| `ALLOW_DUPLICATES` | `ALLOW_DUPLICATES` | `--allow-duplicates` | No | `"false"` | Allow submitting duplicate changes without error |
670769
| `CI_TESTING` | `CI_TESTING` | `--ci-testing` | No | `"false"` | Enable CI testing mode (overrides .gitreview) |
@@ -943,8 +1042,8 @@ requiring manual configuration per PR or user.
9431042
- Adds a back‑reference comment in Gerrit with the GitHub PR and run
9441043
URL. Adds a comment on the GitHub PR with the Gerrit change URL(s).
9451044
- Closing PRs
946-
- On `pull_request_target`, the workflow may close the PR after submission to
947-
match the shell action’s behavior.
1045+
- By default, PRs are **preserved** after submission (`PRESERVE_GITHUB_PRS=true`).
1046+
- Set `PRESERVE_GITHUB_PRS=false` to close PRs after submission on `pull_request_target` events.
9481047

9491048
## Security notes
9501049

action.yaml

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ inputs:
5252
PRESERVE_GITHUB_PRS:
5353
description: "Do not close GitHub PRs after pushing to Gerrit"
5454
required: false
55-
default: "false"
55+
default: "true"
56+
CLOSE_MERGED_PRS:
57+
description: "Close GitHub PRs when corresponding Gerrit changes are merged"
58+
required: false
59+
default: "true"
5660
DRY_RUN:
5761
description: "Validate settings/PR metadata; do not write to Gerrit"
5862
required: false
@@ -65,10 +69,20 @@ inputs:
6569
description: "Enable CI testing mode; overrides .gitreview, creates orphan commits"
6670
required: false
6771
default: "false"
72+
FORCE:
73+
description: "Force PR closure regardless of Gerrit change status (abandoned, etc)"
74+
required: false
75+
default: "false"
6876
ISSUE_ID:
6977
description: "Issue ID to include (e.g., ABC-123)"
7078
required: false
7179
default: ""
80+
USE_LOCAL_ACTION:
81+
description: >-
82+
Use local repository action/code instead of the PyPI package.
83+
Set to 'true' when testing changes in a fork or branch before merging.
84+
required: false
85+
default: "false"
7286
G2G_USE_SSH_AGENT:
7387
description: "Use SSH agent for authentication instead of file-based keys (recommended)"
7488
required: false
@@ -115,6 +129,10 @@ inputs:
115129
(format: [{"key": "username", "value": "ISSUE-ID"}])
116130
required: false
117131
default: "[]"
132+
AUTOMATION_ONLY:
133+
description: "Only accept pull requests from known automation tools"
134+
required: false
135+
default: "true"
118136

119137
outputs:
120138
gerrit_change_request_url:
@@ -157,7 +175,8 @@ runs:
157175
set -euo pipefail
158176
uv --version
159177
# Install locally for self-testing, use uvx for external repos
160-
if [[ "${{ github.repository }}" =~ lfreleng-actions/github2gerrit-action ]]; then
178+
if [[ "${{ inputs.USE_LOCAL_ACTION }}" == "true" ]] || \
179+
[[ "${{ github.repository }}" =~ lfreleng-actions/github2gerrit-action ]]; then
161180
echo "Installing with: uv pip install --system ${{ github.action_path }}"
162181
uv pip install --system ${{ github.action_path }}
163182
else
@@ -199,6 +218,16 @@ runs:
199218
run: |
200219
# Extract PR number, validate context
201220
set -euo pipefail
221+
222+
# Push events don't need PR_NUMBER (used for closing merged PRs)
223+
# The CLI handles push events specially via _process_close_merged_prs()
224+
if [[ "${{ github.event_name }}" == "push" ]]; then
225+
echo "Push event detected - will process merged commits for PR closure"
226+
# Set PR_NUMBER to empty to indicate this is intentional for push events
227+
echo "PR_NUMBER=" >> "$GITHUB_ENV"
228+
exit 0
229+
fi
230+
202231
# Honor PR_NUMBER or SYNC_ALL_OPEN_PRS set by workflow_dispatch
203232
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
204233
if [[ -n "${SYNC_ALL_OPEN_PRS:-}" ]]; then
@@ -249,10 +278,13 @@ runs:
249278
ISSUE_ID: ${{ inputs.ISSUE_ID }}
250279
ISSUE_ID_LOOKUP_JSON: ${{ inputs.ISSUE_ID_LOOKUP_JSON }}
251280
CI_TESTING: ${{ inputs.CI_TESTING }}
281+
CLOSE_MERGED_PRS: ${{ inputs.CLOSE_MERGED_PRS }}
282+
FORCE: ${{ inputs.FORCE }}
252283
DUPLICATE_TYPES: ${{ inputs.DUPLICATE_TYPES }}
253284
NORMALISE_COMMIT: ${{ inputs.NORMALISE_COMMIT }}
254285
G2G_USE_SSH_AGENT: ${{ inputs.G2G_USE_SSH_AGENT }}
255286
G2G_VERBOSE: ${{ inputs.VERBOSE }}
287+
AUTOMATION_ONLY: ${{ inputs.AUTOMATION_ONLY }}
256288

257289
# Optional Gerrit overrides (when .gitreview is missing)
258290
GERRIT_SERVER: ${{ inputs.GERRIT_SERVER }}
@@ -280,8 +312,9 @@ runs:
280312
run: |
281313
# Run github2gerrit Python CLI
282314
set -euo pipefail
283-
# Use different invocation methods based on repository
284-
if [[ "${{ github.repository }}" =~ lfreleng-actions/github2gerrit-action ]]; then
315+
# Use different invocation methods based on repository or USE_LOCAL_ACTION flag
316+
if [[ "${{ inputs.USE_LOCAL_ACTION }}" == "true" ]] || \
317+
[[ "${{ github.repository }}" =~ lfreleng-actions/github2gerrit-action ]]; then
285318
echo "Running:python -m github2gerrit.cli"
286319
python -m github2gerrit.cli
287320
else

0 commit comments

Comments
 (0)