github2gerrit 0.1.8__tar.gz → 0.1.10__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.
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/workflows/github2gerrit.yaml +22 -16
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.pre-commit-config.yaml +7 -6
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/PKG-INFO +28 -6
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/README.md +27 -5
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/REUSE.toml +1 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/action.yaml +51 -42
- github2gerrit-0.1.10/docs/github2gerrit_token_permissions_classic.png +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/cli.py +30 -18
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/config.py +79 -1
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/core.py +22 -3
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/duplicate_detection.py +4 -2
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/external_api.py +3 -2
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/github_api.py +2 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/gitutils.py +12 -4
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/similarity.py +2 -1
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit.egg-info/PKG-INFO +28 -6
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit.egg-info/SOURCES.txt +1 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_duplicate_detection.py +4 -1
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_external_api_framework.py +2 -1
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_gerrit_change_id_footer.py +21 -8
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_gerrit_rest_client.py +4 -1
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_gitutils_helpers.py +2 -1
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_pr_content_filter_integration.py +6 -2
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_url_parser.py +1 -1
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.editorconfig +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/actionlint.yaml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/dependabot.yml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/release-drafter.yml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/workflows/build-test-release.yaml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/workflows/build-test.yaml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/workflows/dependencies.yaml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/workflows/release-drafter.yaml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/workflows/semantic-pull-request.yaml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/workflows/sha-pinned-actions.yaml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.github/workflows/testing.yaml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.gitignore +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.gitlint +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.markdownlint.yaml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.readthedocs.yml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/.yamllint +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/LICENSE +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/LICENSES/Apache-2.0.txt +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/pyproject.toml +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/setup.cfg +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/sitecustomize.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/__init__.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/commit_normalization.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/gerrit_rest.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/gerrit_urls.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/models.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/pr_content_filter.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/ssh_agent_setup.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/ssh_common.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/ssh_discovery.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit/utils.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit.egg-info/dependency_links.txt +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit.egg-info/entry_points.txt +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit.egg-info/requires.txt +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/src/github2gerrit.egg-info/top_level.txt +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/conftest.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/fixtures/__init__.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/fixtures/make_repo.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_change_id_deduplication.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_cli.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_cli_helpers.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_cli_outputs_file.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_cli_url_and_dryrun.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_commit_normalization.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_config_and_reviewers.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_config_helpers.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_core_close_pr_policy.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_core_config_and_errors.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_core_gerrit_backref_comment.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_core_gerrit_push_errors.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_core_gerrit_rest_results.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_core_integration_fixture_repo.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_core_prepare_commits.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_core_ssh_setup.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_gerrit_urls.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_gerrit_urls_more.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_ghe_and_gitreview_args.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_github_api_helpers.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_github_api_retry_and_helpers.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_misc_small_coverage.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_pr_content_filter.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_ssh_agent.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_ssh_common.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_ssh_discovery.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/tests/test_utils.py +0 -0
- {github2gerrit-0.1.8 → github2gerrit-0.1.10}/uv.lock +0 -0
@@ -25,7 +25,7 @@ on:
|
|
25
25
|
type: string
|
26
26
|
GERRIT_KNOWN_HOSTS:
|
27
27
|
description: "known hosts"
|
28
|
-
required:
|
28
|
+
required: false
|
29
29
|
type: string
|
30
30
|
GERRIT_SERVER:
|
31
31
|
description: "Gerrit hostname ex: git.opendaylight.org"
|
@@ -44,11 +44,11 @@ on:
|
|
44
44
|
type: string
|
45
45
|
GERRIT_SSH_USER_G2G:
|
46
46
|
description: "Gerrit user-id for SSH"
|
47
|
-
required:
|
47
|
+
required: false
|
48
48
|
type: string
|
49
49
|
GERRIT_SSH_USER_G2G_EMAIL:
|
50
50
|
description: "Email of the SSH user"
|
51
|
-
required:
|
51
|
+
required: false
|
52
52
|
type: string
|
53
53
|
ORGANIZATION:
|
54
54
|
description: "Organization name, e.g. opendaylight"
|
@@ -95,6 +95,11 @@ on:
|
|
95
95
|
required: false
|
96
96
|
default: ""
|
97
97
|
type: string
|
98
|
+
ALLOW_DUPLICATES:
|
99
|
+
description: "Allow submitting duplicate changes without error"
|
100
|
+
required: false
|
101
|
+
default: false
|
102
|
+
type: boolean
|
98
103
|
secrets:
|
99
104
|
GERRIT_SSH_PRIVKEY_G2G:
|
100
105
|
description: "SSH Private key"
|
@@ -116,22 +121,18 @@ on:
|
|
116
121
|
required: false
|
117
122
|
default: false
|
118
123
|
type: boolean
|
119
|
-
|
120
|
-
description: "fetch-depth for the clone. (Default: 10)"
|
121
|
-
required: false
|
122
|
-
default: "10"
|
123
|
-
type: string
|
124
|
+
|
124
125
|
GERRIT_KNOWN_HOSTS:
|
125
126
|
description: "known hosts"
|
126
|
-
required:
|
127
|
+
required: false
|
127
128
|
type: string
|
128
129
|
GERRIT_SSH_USER_G2G:
|
129
130
|
description: "Gerrit user-id for SSH"
|
130
|
-
required:
|
131
|
+
required: false
|
131
132
|
type: string
|
132
133
|
GERRIT_SSH_USER_G2G_EMAIL:
|
133
134
|
description: "Email of the SSH user"
|
134
|
-
required:
|
135
|
+
required: false
|
135
136
|
type: string
|
136
137
|
|
137
138
|
PRESERVE_GITHUB_PRS:
|
@@ -149,6 +150,11 @@ on:
|
|
149
150
|
required: false
|
150
151
|
default: ""
|
151
152
|
type: string
|
153
|
+
ALLOW_DUPLICATES:
|
154
|
+
description: "Allow submitting duplicate changes without error"
|
155
|
+
required: false
|
156
|
+
default: false
|
157
|
+
type: boolean
|
152
158
|
|
153
159
|
concurrency:
|
154
160
|
group: reusable-${{ github.workflow }}-${{ github.run_id }}
|
@@ -159,7 +165,7 @@ jobs:
|
|
159
165
|
# Manual run: allow optional PR_NUMBER (0 => process all PRs)
|
160
166
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
161
167
|
runs-on: ubuntu-latest
|
162
|
-
timeout-minutes:
|
168
|
+
timeout-minutes: 12
|
163
169
|
steps:
|
164
170
|
# yamllint disable rule:line-length
|
165
171
|
# PR_NUMBER normalization is handled by the composite action
|
@@ -169,13 +175,12 @@ jobs:
|
|
169
175
|
with:
|
170
176
|
SUBMIT_SINGLE_COMMITS: ${{ inputs.SUBMIT_SINGLE_COMMITS }}
|
171
177
|
USE_PR_AS_COMMIT: ${{ inputs.USE_PR_AS_COMMIT }}
|
172
|
-
|
178
|
+
|
173
179
|
GERRIT_KNOWN_HOSTS: ${{ inputs.GERRIT_KNOWN_HOSTS }}
|
174
180
|
GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
|
175
181
|
GERRIT_SSH_USER_G2G: ${{ inputs.GERRIT_SSH_USER_G2G }}
|
176
182
|
GERRIT_SSH_USER_G2G_EMAIL: ${{ inputs.GERRIT_SSH_USER_G2G_EMAIL }}
|
177
|
-
|
178
|
-
ALLOW_GHE_URLS: ${{ inputs.ALLOW_GHE_URLS }}
|
183
|
+
ALLOW_DUPLICATES: ${{ inputs.ALLOW_DUPLICATES }}
|
179
184
|
PRESERVE_GITHUB_PRS: ${{ inputs.PRESERVE_GITHUB_PRS }}
|
180
185
|
DRY_RUN: ${{ inputs.DRY_RUN }}
|
181
186
|
ISSUE_ID: ${{ inputs.ISSUE_ID }}
|
@@ -185,7 +190,7 @@ jobs:
|
|
185
190
|
# Only run if we have a proper pull request context
|
186
191
|
if: ${{ github.event.pull_request.number || github.event.issue.number }}
|
187
192
|
runs-on: ubuntu-latest
|
188
|
-
timeout-minutes:
|
193
|
+
timeout-minutes: 12
|
189
194
|
permissions:
|
190
195
|
contents: read
|
191
196
|
pull-requests: write
|
@@ -206,6 +211,7 @@ jobs:
|
|
206
211
|
ALLOW_GHE_URLS: ${{ inputs.ALLOW_GHE_URLS }}
|
207
212
|
PRESERVE_GITHUB_PRS: ${{ inputs.PRESERVE_GITHUB_PRS }}
|
208
213
|
DRY_RUN: ${{ inputs.DRY_RUN }}
|
214
|
+
ALLOW_DUPLICATES: ${{ inputs.ALLOW_DUPLICATES }}
|
209
215
|
ISSUE_ID: ${{ inputs.ISSUE_ID }}
|
210
216
|
GERRIT_SERVER: ${{ inputs.GERRIT_SERVER }}
|
211
217
|
GERRIT_SERVER_PORT: ${{ inputs.GERRIT_SERVER_PORT }}
|
@@ -58,7 +58,7 @@ repos:
|
|
58
58
|
types: [yaml]
|
59
59
|
|
60
60
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
61
|
-
rev:
|
61
|
+
rev: 0acff885bcb16381b67930fefb91e460202f172c # frozen: v0.12.10
|
62
62
|
hooks:
|
63
63
|
- id: ruff
|
64
64
|
files: ^(src|scripts|tests)/.+\.py$
|
@@ -74,11 +74,12 @@ repos:
|
|
74
74
|
- types-PyYAML
|
75
75
|
- types-requests
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
77
|
+
# Doesn't seem to run reliably inside pre-commit.ci
|
78
|
+
# - repo: https://github.com/RobertCraigie/pyright-python
|
79
|
+
# rev: d393df1703a808473b84bd14a2702f4793014031 # frozen: v1.1.404
|
80
|
+
# hooks:
|
81
|
+
# - id: pyright
|
82
|
+
# files: ^(src|scripts|tests)/.+\.py$
|
82
83
|
|
83
84
|
- repo: https://github.com/btford/write-good
|
84
85
|
rev: ab66ce10136dfad5146e69e70f82a3efac8842c1 # frozen: v1.0.8
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: github2gerrit
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.10
|
4
4
|
Summary: Submit a GitHub pull request to a Gerrit repository.
|
5
5
|
Author-email: Matthew Watkins <mwatkins@linuxfoundation.org>
|
6
6
|
License-Expression: Apache-2.0
|
@@ -140,6 +140,27 @@ with:
|
|
140
140
|
When allowed, duplicates generate warnings but processing continues.
|
141
141
|
The tool exits with code 3 when it detects duplicates and they are not allowed.
|
142
142
|
|
143
|
+
### Configuring duplicate detection scope
|
144
|
+
|
145
|
+
By default, the duplicate detector considers changes with status `open` when searching for potential duplicates.
|
146
|
+
You can customize which Gerrit change states to check using `--duplicate-types` or setting `DUPLICATE_TYPES`:
|
147
|
+
|
148
|
+
```bash
|
149
|
+
# CLI usage - check against open and merged changes
|
150
|
+
github2gerrit --duplicate-types=open,merged https://github.com/org/repo
|
151
|
+
|
152
|
+
# Environment variable
|
153
|
+
DUPLICATE_TYPES=open,merged,abandoned github2gerrit https://github.com/org/repo
|
154
|
+
|
155
|
+
# GitHub Actions
|
156
|
+
uses: onap/github2gerrit@main
|
157
|
+
with:
|
158
|
+
DUPLICATE_TYPES: 'open,merged'
|
159
|
+
```
|
160
|
+
|
161
|
+
Valid change states include `open`, `merged`, and `abandoned`. This setting determines which existing changes
|
162
|
+
to check when evaluating whether a new change would be a duplicate.
|
163
|
+
|
143
164
|
## Commit Message Normalization
|
144
165
|
|
145
166
|
The tool includes intelligent commit message normalization that automatically
|
@@ -297,7 +318,7 @@ jobs:
|
|
297
318
|
steps:
|
298
319
|
- name: Submit PR to Gerrit
|
299
320
|
id: g2g
|
300
|
-
uses:
|
321
|
+
uses: lfreleng-actions/github2gerrit-action@main
|
301
322
|
with:
|
302
323
|
SUBMIT_SINGLE_COMMITS: "false"
|
303
324
|
USE_PR_AS_COMMIT: "false"
|
@@ -343,7 +364,7 @@ uv run github2gerrit
|
|
343
364
|
uvx github2gerrit https://github.com/owner/repo/pull/123
|
344
365
|
|
345
366
|
# Install from specific version/source
|
346
|
-
uvx --from git+https://github.com/
|
367
|
+
uvx --from git+https://github.com/lfreleng-actions/github2gerrit-action@main github2gerrit https://github.com/owner/repo/pull/123
|
347
368
|
```
|
348
369
|
|
349
370
|
### Available Options
|
@@ -368,6 +389,7 @@ Key options include:
|
|
368
389
|
- `--use-pr-as-commit`: Use PR title/body as commit message (`USE_PR_AS_COMMIT`)
|
369
390
|
- `--issue-id`: Add an Issue-ID trailer (e.g., "Issue-ID: ABC-123") to the commit message (`ISSUE_ID`)
|
370
391
|
- `--preserve-github-prs`: Don't close GitHub PRs after submission (`PRESERVE_GITHUB_PRS`)
|
392
|
+
- `--duplicate-types`: Configure which Gerrit change states to check for duplicates (`DUPLICATE_TYPES`)
|
371
393
|
|
372
394
|
For a complete list of all available options, see the [Inputs](#inputs) section.
|
373
395
|
|
@@ -524,7 +546,7 @@ jobs:
|
|
524
546
|
|
525
547
|
- name: Submit PR to Gerrit (with explicit overrides)
|
526
548
|
id: g2g
|
527
|
-
uses:
|
549
|
+
uses: lfreleng-actions/github2gerrit-action@main
|
528
550
|
with:
|
529
551
|
# Behavior
|
530
552
|
SUBMIT_SINGLE_COMMITS: "false"
|
@@ -593,7 +615,7 @@ alignment between action inputs, environment variables, and CLI flags:
|
|
593
615
|
| `CI_TESTING` | `CI_TESTING` | `--ci-testing` | No | `"false"` | Enable CI testing mode (overrides .gitreview) |
|
594
616
|
| `ISSUE_ID` | `ISSUE_ID` | `--issue-id` | No | `""` | Issue ID to include (e.g., ABC-123) |
|
595
617
|
| `G2G_USE_SSH_AGENT` | `G2G_USE_SSH_AGENT` | N/A | No | `"true"` | Use SSH agent for authentication |
|
596
|
-
| `
|
618
|
+
| `DUPLICATE_TYPES` | `DUPLICATE_TYPES` | `--duplicate-types` | No | `"open"` | Comma-separated Gerrit change states to check for duplicate detection |
|
597
619
|
| `GERRIT_SERVER` | `GERRIT_SERVER` | `--gerrit-server` | No² | `""` | Gerrit server hostname (auto-derived if enabled) |
|
598
620
|
| `GERRIT_SERVER_PORT` | `GERRIT_SERVER_PORT` | `--gerrit-server-port` | No | `"29418"` | Gerrit SSH port |
|
599
621
|
| `GERRIT_PROJECT` | `GERRIT_PROJECT` | `--gerrit-project` | No² | `""` | Gerrit project name |
|
@@ -777,7 +799,7 @@ For CI/CD pipelines (like GitHub Actions), use `uvx` to install and run without
|
|
777
799
|
uvx github2gerrit <PR_URL> --dry-run
|
778
800
|
|
779
801
|
# Install from a specific version or source
|
780
|
-
uvx --from git+https://github.com/
|
802
|
+
uvx --from git+https://github.com/lfreleng-actions/github2gerrit-action@main github2gerrit <PR_URL>
|
781
803
|
|
782
804
|
# Run with specific Python version
|
783
805
|
uvx --python 3.11 github2gerrit <PR_URL>
|
@@ -100,6 +100,27 @@ with:
|
|
100
100
|
When allowed, duplicates generate warnings but processing continues.
|
101
101
|
The tool exits with code 3 when it detects duplicates and they are not allowed.
|
102
102
|
|
103
|
+
### Configuring duplicate detection scope
|
104
|
+
|
105
|
+
By default, the duplicate detector considers changes with status `open` when searching for potential duplicates.
|
106
|
+
You can customize which Gerrit change states to check using `--duplicate-types` or setting `DUPLICATE_TYPES`:
|
107
|
+
|
108
|
+
```bash
|
109
|
+
# CLI usage - check against open and merged changes
|
110
|
+
github2gerrit --duplicate-types=open,merged https://github.com/org/repo
|
111
|
+
|
112
|
+
# Environment variable
|
113
|
+
DUPLICATE_TYPES=open,merged,abandoned github2gerrit https://github.com/org/repo
|
114
|
+
|
115
|
+
# GitHub Actions
|
116
|
+
uses: onap/github2gerrit@main
|
117
|
+
with:
|
118
|
+
DUPLICATE_TYPES: 'open,merged'
|
119
|
+
```
|
120
|
+
|
121
|
+
Valid change states include `open`, `merged`, and `abandoned`. This setting determines which existing changes
|
122
|
+
to check when evaluating whether a new change would be a duplicate.
|
123
|
+
|
103
124
|
## Commit Message Normalization
|
104
125
|
|
105
126
|
The tool includes intelligent commit message normalization that automatically
|
@@ -257,7 +278,7 @@ jobs:
|
|
257
278
|
steps:
|
258
279
|
- name: Submit PR to Gerrit
|
259
280
|
id: g2g
|
260
|
-
uses:
|
281
|
+
uses: lfreleng-actions/github2gerrit-action@main
|
261
282
|
with:
|
262
283
|
SUBMIT_SINGLE_COMMITS: "false"
|
263
284
|
USE_PR_AS_COMMIT: "false"
|
@@ -303,7 +324,7 @@ uv run github2gerrit
|
|
303
324
|
uvx github2gerrit https://github.com/owner/repo/pull/123
|
304
325
|
|
305
326
|
# Install from specific version/source
|
306
|
-
uvx --from git+https://github.com/
|
327
|
+
uvx --from git+https://github.com/lfreleng-actions/github2gerrit-action@main github2gerrit https://github.com/owner/repo/pull/123
|
307
328
|
```
|
308
329
|
|
309
330
|
### Available Options
|
@@ -328,6 +349,7 @@ Key options include:
|
|
328
349
|
- `--use-pr-as-commit`: Use PR title/body as commit message (`USE_PR_AS_COMMIT`)
|
329
350
|
- `--issue-id`: Add an Issue-ID trailer (e.g., "Issue-ID: ABC-123") to the commit message (`ISSUE_ID`)
|
330
351
|
- `--preserve-github-prs`: Don't close GitHub PRs after submission (`PRESERVE_GITHUB_PRS`)
|
352
|
+
- `--duplicate-types`: Configure which Gerrit change states to check for duplicates (`DUPLICATE_TYPES`)
|
331
353
|
|
332
354
|
For a complete list of all available options, see the [Inputs](#inputs) section.
|
333
355
|
|
@@ -484,7 +506,7 @@ jobs:
|
|
484
506
|
|
485
507
|
- name: Submit PR to Gerrit (with explicit overrides)
|
486
508
|
id: g2g
|
487
|
-
uses:
|
509
|
+
uses: lfreleng-actions/github2gerrit-action@main
|
488
510
|
with:
|
489
511
|
# Behavior
|
490
512
|
SUBMIT_SINGLE_COMMITS: "false"
|
@@ -553,7 +575,7 @@ alignment between action inputs, environment variables, and CLI flags:
|
|
553
575
|
| `CI_TESTING` | `CI_TESTING` | `--ci-testing` | No | `"false"` | Enable CI testing mode (overrides .gitreview) |
|
554
576
|
| `ISSUE_ID` | `ISSUE_ID` | `--issue-id` | No | `""` | Issue ID to include (e.g., ABC-123) |
|
555
577
|
| `G2G_USE_SSH_AGENT` | `G2G_USE_SSH_AGENT` | N/A | No | `"true"` | Use SSH agent for authentication |
|
556
|
-
| `
|
578
|
+
| `DUPLICATE_TYPES` | `DUPLICATE_TYPES` | `--duplicate-types` | No | `"open"` | Comma-separated Gerrit change states to check for duplicate detection |
|
557
579
|
| `GERRIT_SERVER` | `GERRIT_SERVER` | `--gerrit-server` | No² | `""` | Gerrit server hostname (auto-derived if enabled) |
|
558
580
|
| `GERRIT_SERVER_PORT` | `GERRIT_SERVER_PORT` | `--gerrit-server-port` | No | `"29418"` | Gerrit SSH port |
|
559
581
|
| `GERRIT_PROJECT` | `GERRIT_PROJECT` | `--gerrit-project` | No² | `""` | Gerrit project name |
|
@@ -737,7 +759,7 @@ For CI/CD pipelines (like GitHub Actions), use `uvx` to install and run without
|
|
737
759
|
uvx github2gerrit <PR_URL> --dry-run
|
738
760
|
|
739
761
|
# Install from a specific version or source
|
740
|
-
uvx --from git+https://github.com/
|
762
|
+
uvx --from git+https://github.com/lfreleng-actions/github2gerrit-action@main github2gerrit <PR_URL>
|
741
763
|
|
742
764
|
# Run with specific Python version
|
743
765
|
uvx --python 3.11 github2gerrit <PR_URL>
|
@@ -6,6 +6,10 @@ name: github2gerrit
|
|
6
6
|
description: "Creates Gerrit changes from GitHub pull requests"
|
7
7
|
|
8
8
|
inputs:
|
9
|
+
# Optional
|
10
|
+
GERRIT_SSH_PRIVKEY_G2G:
|
11
|
+
description: "SSH private key content used to authenticate to Gerrit"
|
12
|
+
required: true
|
9
13
|
SUBMIT_SINGLE_COMMITS:
|
10
14
|
description: "Submit one commit at a time to the Gerrit repository"
|
11
15
|
required: false
|
@@ -22,35 +26,17 @@ inputs:
|
|
22
26
|
description: "Pull request number to process, use 0 to process all open"
|
23
27
|
required: false
|
24
28
|
default: "0"
|
25
|
-
|
26
|
-
# SSH and identity
|
27
29
|
GERRIT_KNOWN_HOSTS:
|
28
30
|
description: "Known hosts entries for Gerrit SSH (single or multi-line)"
|
29
|
-
required:
|
30
|
-
GERRIT_SSH_PRIVKEY_G2G:
|
31
|
-
description: "SSH private key content used to authenticate to Gerrit"
|
32
|
-
required: true
|
31
|
+
required: false
|
33
32
|
GERRIT_SSH_USER_G2G:
|
34
|
-
description:
|
35
|
-
Gerrit SSH username (e.g. automation bot account). In GitHub Actions,
|
36
|
-
automatically derived as [ORGANIZATION].gh2gerrit when not provided if
|
37
|
-
G2G_ENABLE_DERIVATION=true (default: false). For local CLI usage,
|
38
|
-
derivation is enabled by default; set
|
39
|
-
G2G_ENABLE_DERIVATION=false to disable.
|
33
|
+
description: "Gerrit SSH username; derived if not supplied explicitly"
|
40
34
|
required: false
|
41
35
|
default: ""
|
42
36
|
GERRIT_SSH_USER_G2G_EMAIL:
|
43
|
-
description:
|
44
|
-
Email address associated to the Gerrit SSH user. In GitHub Actions,
|
45
|
-
automatically derived as
|
46
|
-
releng+[ORGANIZATION]-gh2gerrit@linuxfoundation.org when not provided if
|
47
|
-
G2G_ENABLE_DERIVATION=true (default: false). For local CLI usage,
|
48
|
-
derivation is enabled by default; set
|
49
|
-
G2G_ENABLE_DERIVATION=false to disable.
|
37
|
+
description: "Gerrit user email address; derived if not supplied explicitly"
|
50
38
|
required: false
|
51
39
|
default: ""
|
52
|
-
|
53
|
-
# Behavior and metadata
|
54
40
|
ORGANIZATION:
|
55
41
|
description: "GitHub organization/owner (defaults to repo owner)"
|
56
42
|
required: false
|
@@ -76,7 +62,7 @@ inputs:
|
|
76
62
|
required: false
|
77
63
|
default: "false"
|
78
64
|
CI_TESTING:
|
79
|
-
description: "Enable CI testing mode
|
65
|
+
description: "Enable CI testing mode; overrides .gitreview, creates orphan commits"
|
80
66
|
required: false
|
81
67
|
default: "false"
|
82
68
|
ISSUE_ID:
|
@@ -87,38 +73,26 @@ inputs:
|
|
87
73
|
description: "Use SSH agent for authentication instead of file-based keys (recommended)"
|
88
74
|
required: false
|
89
75
|
default: "true"
|
90
|
-
|
91
|
-
|
92
|
-
description: >
|
93
|
-
Comma-separated Gerrit statuses to consider for duplicate
|
94
|
-
detection (e.g., open,merged,abandoned)
|
76
|
+
DUPLICATE_TYPES:
|
77
|
+
description: "Comma-separated Gerrit states for evaluating duplicates"
|
95
78
|
required: false
|
96
79
|
default: "open"
|
97
80
|
NORMALISE_COMMIT:
|
98
81
|
description: "Normalize commit messages to conventional commit format"
|
99
82
|
required: false
|
100
|
-
default: "
|
101
|
-
|
102
|
-
# Optional Gerrit overrides (used when .gitreview is missing)
|
83
|
+
default: "false"
|
103
84
|
GERRIT_SERVER:
|
104
|
-
description:
|
105
|
-
Gerrit server hostname (optional; use .gitreview if present). In GitHub
|
106
|
-
Actions, automatically derived as gerrit.[ORGANIZATION].org when not
|
107
|
-
provided if G2G_ENABLE_DERIVATION=true (default: false). For local CLI
|
108
|
-
usage, derivation is enabled by default; set G2G_ENABLE_DERIVATION=false
|
109
|
-
to disable.
|
85
|
+
description: "Gerrit server hostname; derived if not supplied explicitly"
|
110
86
|
required: false
|
111
87
|
default: ""
|
112
88
|
GERRIT_SERVER_PORT:
|
113
|
-
description: "Gerrit
|
89
|
+
description: "Gerrit serverSSH TCP/port"
|
114
90
|
required: false
|
115
91
|
default: "29418"
|
116
92
|
GERRIT_PROJECT:
|
117
|
-
description: "Gerrit project
|
93
|
+
description: "Gerrit project; optional if .gitreview exists"
|
118
94
|
required: false
|
119
95
|
default: ""
|
120
|
-
|
121
|
-
# Optional Gerrit REST-related settings
|
122
96
|
GERRIT_HTTP_BASE_PATH:
|
123
97
|
description: "Optional HTTP base path for Gerrit REST (e.g. /r)"
|
124
98
|
required: false
|
@@ -165,6 +139,41 @@ runs:
|
|
165
139
|
# Ensure we are on the PR's head SHA when triggered by PR events
|
166
140
|
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
167
141
|
|
142
|
+
- name: "Set key to use for JSON lookup"
|
143
|
+
if: ${{ inputs.ISSUE_ID == '' && vars.ISSUE_ID_LOOKUP == 'true' }}
|
144
|
+
shell: bash
|
145
|
+
run: |
|
146
|
+
# Set key to use for JSON lookup
|
147
|
+
ACTOR="${{ github.actor }}"
|
148
|
+
ACTOR_ID="${{ github.actor_id }}"
|
149
|
+
echo "Using GitHub actor as lookup key: $ACTOR [$ACTOR_ID]"
|
150
|
+
echo "key=$ACTOR" >> "$GITHUB_ENV"
|
151
|
+
|
152
|
+
- name: "Get ticket from JSON lookup table"
|
153
|
+
if: ${{ inputs.ISSUE_ID == '' && vars.ISSUE_ID_LOOKUP == 'true' }}
|
154
|
+
id: json-lookup
|
155
|
+
uses: lfit/releng-reusable-workflows/.github/actions/json-key-value-lookup-action@main
|
156
|
+
with:
|
157
|
+
json: ${{ vars.ISSUE_ID_LOOKUP_JSON }}
|
158
|
+
key: ${{ env.key }}
|
159
|
+
|
160
|
+
- name: "Set IssueID in GITHUB_ENV"
|
161
|
+
if: ${{ inputs.ISSUE_ID == '' && vars.ISSUE_ID_LOOKUP == 'true' }}
|
162
|
+
shell: bash
|
163
|
+
# yamllint disable rule:line-length
|
164
|
+
run: |
|
165
|
+
set -euo pipefail
|
166
|
+
val="${{ steps.json-lookup.outputs.value }}"
|
167
|
+
if [ -z "$val" ]; then
|
168
|
+
alt="${{ env.value }}"
|
169
|
+
if [ -n "$alt" ]; then
|
170
|
+
val="$alt"
|
171
|
+
fi
|
172
|
+
fi
|
173
|
+
if [ -n "$val" ]; then
|
174
|
+
echo "RESOLVED_ISSUE_ID=$val" >> "$GITHUB_ENV"
|
175
|
+
fi
|
176
|
+
|
168
177
|
- name: Install required dependencies
|
169
178
|
shell: bash
|
170
179
|
run: |
|
@@ -253,9 +262,9 @@ runs:
|
|
253
262
|
PRESERVE_GITHUB_PRS: ${{ inputs.PRESERVE_GITHUB_PRS }}
|
254
263
|
DRY_RUN: ${{ inputs.DRY_RUN }}
|
255
264
|
ALLOW_DUPLICATES: ${{ inputs.ALLOW_DUPLICATES }}
|
256
|
-
ISSUE_ID: ${{ inputs.ISSUE_ID }}
|
265
|
+
ISSUE_ID: ${{ inputs.ISSUE_ID != '' && inputs.ISSUE_ID || env.RESOLVED_ISSUE_ID }}
|
257
266
|
CI_TESTING: ${{ inputs.CI_TESTING }}
|
258
|
-
|
267
|
+
DUPLICATE_TYPES: ${{ inputs.DUPLICATE_TYPES }}
|
259
268
|
NORMALISE_COMMIT: ${{ inputs.NORMALISE_COMMIT }}
|
260
269
|
G2G_USE_SSH_AGENT: ${{ inputs.G2G_USE_SSH_AGENT }}
|
261
270
|
|
Binary file
|
@@ -3,13 +3,10 @@
|
|
3
3
|
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
-
import io
|
7
6
|
import json
|
8
7
|
import logging
|
9
8
|
import os
|
10
|
-
import shutil
|
11
9
|
import tempfile
|
12
|
-
import zipfile
|
13
10
|
from collections.abc import Callable
|
14
11
|
from concurrent.futures import ThreadPoolExecutor
|
15
12
|
from concurrent.futures import as_completed
|
@@ -20,8 +17,6 @@ from typing import Protocol
|
|
20
17
|
from typing import TypeVar
|
21
18
|
from typing import cast
|
22
19
|
from urllib.parse import urlparse
|
23
|
-
from urllib.request import Request
|
24
|
-
from urllib.request import urlopen
|
25
20
|
|
26
21
|
import click
|
27
22
|
import typer
|
@@ -270,12 +265,13 @@ def main(
|
|
270
265
|
envvar="CI_TESTING",
|
271
266
|
help="Enable CI testing mode (overrides .gitreview, handles unrelated repos).",
|
272
267
|
),
|
273
|
-
|
268
|
+
duplicate_types: str = typer.Option(
|
274
269
|
"open",
|
275
|
-
"--
|
276
|
-
envvar="
|
270
|
+
"--duplicate-types",
|
271
|
+
envvar="DUPLICATE_TYPES",
|
277
272
|
help=(
|
278
|
-
|
273
|
+
"Gerrit change states to evaluate when determining if a change should be considered a duplicate "
|
274
|
+
'(comma-separated). E.g. "open,merged,abandoned". Default: "open".'
|
279
275
|
),
|
280
276
|
),
|
281
277
|
normalise_commit: bool = typer.Option(
|
@@ -295,11 +291,14 @@ def main(
|
|
295
291
|
"""
|
296
292
|
Tool to convert GitHub pull requests into Gerrit changes
|
297
293
|
|
298
|
-
- Providing a URL to a pull request: converts that pull request
|
294
|
+
- Providing a URL to a pull request: converts that pull request
|
295
|
+
into a Gerrit change
|
299
296
|
|
300
|
-
- Providing a URL to a GitHub repository converts all open pull
|
297
|
+
- Providing a URL to a GitHub repository converts all open pull
|
298
|
+
requests into Gerrit changes
|
301
299
|
|
302
|
-
- No arguments for CI/CD environment; reads parameters from
|
300
|
+
- No arguments for CI/CD environment; reads parameters from
|
301
|
+
environment variables
|
303
302
|
"""
|
304
303
|
# Override boolean parameters with properly parsed environment variables
|
305
304
|
# This ensures that string "false" from GitHub Actions is handled correctly
|
@@ -356,20 +355,26 @@ def main(
|
|
356
355
|
os.environ["ISSUE_ID"] = issue_id
|
357
356
|
os.environ["ALLOW_DUPLICATES"] = "true" if allow_duplicates else "false"
|
358
357
|
os.environ["CI_TESTING"] = "true" if ci_testing else "false"
|
359
|
-
if
|
360
|
-
os.environ["
|
358
|
+
if duplicate_types:
|
359
|
+
os.environ["DUPLICATE_TYPES"] = duplicate_types
|
361
360
|
# URL mode handling
|
362
361
|
if target_url:
|
363
362
|
org, repo, pr = _parse_github_target(target_url)
|
363
|
+
log.debug("Parsed GitHub URL: org=%s, repo=%s, pr=%s", org, repo, pr)
|
364
364
|
if org:
|
365
365
|
os.environ["ORGANIZATION"] = org
|
366
|
+
log.debug("Set ORGANIZATION=%s", org)
|
366
367
|
if org and repo:
|
367
|
-
|
368
|
+
github_repo = f"{org}/{repo}"
|
369
|
+
os.environ["GITHUB_REPOSITORY"] = github_repo
|
370
|
+
log.debug("Set GITHUB_REPOSITORY=%s", github_repo)
|
368
371
|
if pr:
|
369
372
|
os.environ["PR_NUMBER"] = str(pr)
|
370
373
|
os.environ["SYNC_ALL_OPEN_PRS"] = "false"
|
374
|
+
log.debug("Set PR_NUMBER=%s", pr)
|
371
375
|
else:
|
372
376
|
os.environ["SYNC_ALL_OPEN_PRS"] = "true"
|
377
|
+
log.debug("Set SYNC_ALL_OPEN_PRS=true")
|
373
378
|
os.environ["G2G_TARGET_URL"] = "1"
|
374
379
|
# Debug: Show environment at CLI startup
|
375
380
|
log.debug("CLI startup environment check:")
|
@@ -428,7 +433,7 @@ def _build_inputs_from_env() -> Inputs:
|
|
428
433
|
issue_id=env_str("ISSUE_ID", ""),
|
429
434
|
allow_duplicates=env_bool("ALLOW_DUPLICATES", False),
|
430
435
|
ci_testing=env_bool("CI_TESTING", False),
|
431
|
-
duplicates_filter=env_str("
|
436
|
+
duplicates_filter=env_str("DUPLICATE_TYPES", "open"),
|
432
437
|
)
|
433
438
|
|
434
439
|
|
@@ -472,7 +477,7 @@ def _process_bulk(data: Inputs, gh: GitHubContext) -> bool:
|
|
472
477
|
|
473
478
|
try:
|
474
479
|
if data.duplicates_filter:
|
475
|
-
os.environ["
|
480
|
+
os.environ["DUPLICATE_TYPES"] = data.duplicates_filter
|
476
481
|
check_for_duplicates(per_ctx, allow_duplicates=data.allow_duplicates)
|
477
482
|
except DuplicateChangeError as exc:
|
478
483
|
log_exception_conditionally(log, "Skipping PR #%d", pr_number)
|
@@ -748,6 +753,13 @@ def _prepare_local_checkout(workspace: Path, gh: GitHubContext, data: Inputs) ->
|
|
748
753
|
|
749
754
|
def _fallback_to_api_archive(workspace: Path, gh: GitHubContext, data: Inputs, pr_num_str: str) -> None:
|
750
755
|
"""Fallback to GitHub API archive download for private repos."""
|
756
|
+
import io
|
757
|
+
import json
|
758
|
+
import shutil
|
759
|
+
import zipfile
|
760
|
+
from urllib.request import Request
|
761
|
+
from urllib.request import urlopen
|
762
|
+
|
751
763
|
log.info("Attempting API archive fallback for PR #%s", pr_num_str)
|
752
764
|
|
753
765
|
# Get GitHub token for authenticated requests
|
@@ -1011,7 +1023,7 @@ def _process() -> None:
|
|
1011
1023
|
if gh.pr_number and not env_bool("SYNC_ALL_OPEN_PRS", False):
|
1012
1024
|
try:
|
1013
1025
|
if data.duplicates_filter:
|
1014
|
-
os.environ["
|
1026
|
+
os.environ["DUPLICATE_TYPES"] = data.duplicates_filter
|
1015
1027
|
check_for_duplicates(gh, allow_duplicates=data.allow_duplicates)
|
1016
1028
|
except DuplicateChangeError as exc:
|
1017
1029
|
log_exception_conditionally(
|