github2gerrit 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,464 @@
1
+ Metadata-Version: 2.1
2
+ Name: github2gerrit
3
+ Version: 0.1.0
4
+ Summary: Submit a GitHub pull request to a Gerrit repository.
5
+ Keywords: github,gerrit,ci,actions,typer,cli
6
+ Author-Email: Matthew Watkins <mwatkins@linuxfoundation.org>
7
+ License: Apache-2.0
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Build Tools
17
+ Classifier: Topic :: Software Development :: Version Control
18
+ Classifier: Typing :: Typed
19
+ Project-URL: Homepage, https://github.com/lfit/github2gerrit
20
+ Project-URL: Repository, https://github.com/lfit/github2gerrit
21
+ Project-URL: Issues, https://github.com/lfit/github2gerrit/issues
22
+ Requires-Python: <3.14,>=3.11
23
+ Requires-Dist: typer>=0.12.5
24
+ Requires-Dist: PyGithub>=2.3.0
25
+ Requires-Dist: pygerrit2>=2.0.0
26
+ Requires-Dist: git-review>=2.3.1
27
+ Description-Content-Type: text/markdown
28
+
29
+ <!--
30
+ SPDX-License-Identifier: Apache-2.0
31
+ SPDX-FileCopyrightText: 2025 The Linux Foundation
32
+ -->
33
+
34
+ # github2gerrit
35
+
36
+ Submit a GitHub pull request to a Gerrit repository, implemented in Python.
37
+
38
+ This action is a drop‑in replacement for the shell‑based
39
+ `lfit/github2gerrit` composite action. It mirrors the same inputs,
40
+ outputs, environment variables, and secrets so you can adopt it without
41
+ changing existing configuration in your organizations.
42
+
43
+ The tool expects a `.gitreview` file in the repository to derive Gerrit
44
+ connection details and the destination project. It uses `git` over SSH
45
+ and `git-review` semantics to push to `refs/for/<branch>` and relies on
46
+ Gerrit `Change-Id` trailers to create or update changes.
47
+
48
+ Note: the initial versions focus on compatibility and clear logging.
49
+ The behavior matches the existing action, and this implementation
50
+ refactors it to Python with typed modules and test support.
51
+
52
+ ## How it works (high level)
53
+
54
+ - Discover pull request context and inputs.
55
+ - Check for duplicate changes to prevent spam from automated tools.
56
+ - Read `.gitreview` for Gerrit host, port, and project.
57
+ - Set up `git` user config and SSH for Gerrit.
58
+ - Prepare commits:
59
+ - one‑by‑one cherry‑pick with `Change-Id` trailers, or
60
+ - squash into a single commit and keep or reuse `Change-Id`.
61
+ - Optionally replace the commit message with PR title and body.
62
+ - Push with a topic to `refs/for/<branch>` using `git-review` behavior.
63
+ - Query Gerrit for the resulting URL, change number, and patchset SHA.
64
+ - Add a back‑reference comment in Gerrit to the GitHub PR and run URL.
65
+ - Comment on the GitHub PR with the Gerrit change URL(s).
66
+ - Optionally close the PR (mirrors the shell action policy).
67
+
68
+ ## Requirements
69
+
70
+ - Repository contains a `.gitreview` file. If you cannot provide it,
71
+ you must pass `GERRIT_SERVER`, `GERRIT_SERVER_PORT`, and
72
+ `GERRIT_PROJECT` via the reusable workflow interface.
73
+ - SSH key for Gerrit and known hosts are available to the workflow.
74
+ - The default `GITHUB_TOKEN` is available for PR metadata and comments.
75
+ - The workflow grants permissions required for PR interactions:
76
+ - `pull-requests: write` (to comment on and close PRs)
77
+ - `issues: write` (to create PR comments via the Issues API)
78
+ - The workflow runs with `pull_request_target` or via
79
+ `workflow_dispatch` using a valid PR context.
80
+
81
+ ### Note on sitecustomize.py
82
+
83
+ This repository includes a sitecustomize.py that is automatically
84
+ imported by Python’s site initialization. It exists to make pytest and
85
+ coverage runs in CI more robust by:
86
+
87
+ - assigns a unique COVERAGE_FILE per process to avoid mixing data across runs
88
+ - proactively removing stale .coverage artifacts in common base directories.
89
+
90
+ The logic runs during pytest sessions and is best effort.
91
+ It never interferes with normal execution. Maintainers can keep it to
92
+ stabilize coverage reporting for parallel/xdist runs.
93
+
94
+ ## Duplicate detection
95
+
96
+ By default, the tool checks for duplicate changes to prevent spam
97
+ submissions from automated tools like Dependabot. It compares PR titles,
98
+ content, and files changed against recent PRs (last 7 days) and will
99
+ exit with an error when it finds duplicates.
100
+
101
+ ### Examples of detected duplicates
102
+
103
+ - Identical Dependabot PRs: "Bump package from 1.0 to 1.1"
104
+ - Sequential dependency updates: "Bump package 1.0→1.1", "Bump package 1.1→1.2"
105
+ - Similar bug fixes with slightly different wording
106
+
107
+ ### Allowing duplicates
108
+
109
+ Use `--allow-duplicates` or set `ALLOW_DUPLICATES=true` to override:
110
+
111
+ ```bash
112
+ # CLI usage
113
+ github2gerrit --allow-duplicates https://github.com/org/repo
114
+
115
+ # GitHub Actions
116
+ uses: onap/github2gerrit@main
117
+ with:
118
+ ALLOW_DUPLICATES: 'true'
119
+ ```
120
+
121
+ When allowed, duplicates generate warnings but processing continues.
122
+ The tool exits with code 3 when it detects duplicates and they are not allowed.
123
+
124
+ ## Usage
125
+
126
+ This action runs as part of a workflow that triggers on
127
+ `pull_request_target` and also supports manual runs via
128
+ `workflow_dispatch`.
129
+
130
+ Minimal example:
131
+
132
+ ```yaml
133
+ name: github2gerrit
134
+
135
+ on:
136
+ pull_request_target:
137
+ types: [opened, reopened, edited, synchronize]
138
+ workflow_dispatch:
139
+
140
+ permissions:
141
+ contents: read
142
+ pull-requests: write
143
+ issues: write
144
+
145
+ jobs:
146
+ submit-to-gerrit:
147
+ runs-on: ubuntu-latest
148
+ steps:
149
+ - name: Submit PR to Gerrit
150
+ id: g2g
151
+ uses: lfit/github2gerrit@main
152
+ with:
153
+ SUBMIT_SINGLE_COMMITS: "false"
154
+ USE_PR_AS_COMMIT: "false"
155
+ FETCH_DEPTH: "10"
156
+ GERRIT_KNOWN_HOSTS: ${{ vars.GERRIT_KNOWN_HOSTS }}
157
+ GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
158
+ GERRIT_SSH_USER_G2G: ${{ vars.GERRIT_SSH_USER_G2G }}
159
+ GERRIT_SSH_USER_G2G_EMAIL: ${{ vars.GERRIT_SSH_USER_G2G_EMAIL }}
160
+ ORGANIZATION: ${{ github.repository_owner }}
161
+ REVIEWERS_EMAIL: ""
162
+ ISSUE_ID: "" # Optional: adds 'Issue-ID: ...' trailer to the commit message
163
+ ```
164
+
165
+ The action reads `.gitreview`. If `.gitreview` is absent, you must
166
+ supply Gerrit connection details through a reusable workflow or by
167
+ setting the corresponding environment variables before invoking the
168
+ action. The shell action enforces `.gitreview` for the composite
169
+ variant; this Python action mirrors that behavior for compatibility.
170
+
171
+ ## Command Line Usage and Debugging
172
+
173
+ ### Direct Command Line Usage
174
+
175
+ You can run the tool directly from the command line to process GitHub pull requests:
176
+
177
+ ```bash
178
+ # Process a specific pull request
179
+ github2gerrit https://github.com/owner/repo/pull/123
180
+
181
+ # Process all open pull requests in a repository
182
+ github2gerrit https://github.com/owner/repo
183
+
184
+ # Run in CI mode (reads from environment variables)
185
+ github2gerrit
186
+ ```
187
+
188
+ ### Available Options
189
+
190
+ ```bash
191
+ github2gerrit --help
192
+ ```
193
+
194
+ Key options include:
195
+
196
+ - `--verbose` / `-v`: Enable verbose debug logging
197
+ - `--dry-run`: Check configuration without making changes
198
+ - `--submit-single-commits`: Submit each commit individually
199
+ - `--use-pr-as-commit`: Use PR title/body as commit message
200
+ - `--issue-id`: Add an Issue-ID trailer (e.g., "Issue-ID: ABC-123")
201
+ to the commit message
202
+ - `--preserve-github-prs`: Don't close GitHub PRs after submission
203
+
204
+ ### Debugging and Troubleshooting
205
+
206
+ When encountering issues, enable verbose logging to see detailed execution:
207
+
208
+ ```bash
209
+ # Using the CLI flag
210
+ github2gerrit --verbose https://github.com/owner/repo/pull/123
211
+
212
+ # Using environment variable
213
+ G2G_LOG_LEVEL=DEBUG github2gerrit https://github.com/owner/repo/pull/123
214
+
215
+ # Alternative environment variable
216
+ G2G_VERBOSE=true github2gerrit https://github.com/owner/repo/pull/123
217
+ ```
218
+
219
+ Debug output includes:
220
+
221
+ - Git command execution and output
222
+ - SSH connection attempts
223
+ - Gerrit API interactions
224
+ - Branch resolution logic
225
+ - Change-Id processing
226
+
227
+ Common issues and solutions:
228
+
229
+ 1. **SSH Permission Denied**: Ensure `GERRIT_SSH_PRIVKEY_G2G` and
230
+ `GERRIT_KNOWN_HOSTS` are properly set
231
+ 2. **Branch Not Found**: Check that the target branch exists in both GitHub and Gerrit
232
+ 3. **Change-Id Issues**: Enable debug logging to see Change-Id generation and validation
233
+ 4. **Gerrit API Errors**: Verify Gerrit server connectivity and project permissions
234
+
235
+ ### Environment Variables
236
+
237
+ The tool respects these environment variables for configuration:
238
+
239
+ - `G2G_LOG_LEVEL`: Set to `DEBUG` for verbose output (default: `INFO`)
240
+ - `G2G_VERBOSE`: Set to `true` to enable debug logging
241
+ - `GERRIT_SSH_PRIVKEY_G2G`: SSH private key content
242
+ - `GERRIT_KNOWN_HOSTS`: SSH known hosts entries
243
+ - `GERRIT_SSH_USER_G2G`: Gerrit SSH username
244
+ - `DRY_RUN`: Set to `true` for check mode
245
+
246
+ ## Advanced usage
247
+
248
+ You can explicitly install the SSH key and provide a custom SSH configuration
249
+ before invoking this action. This is useful when:
250
+
251
+ - You want to override the port/host used by SSH
252
+ - You need to define host aliases or SSH options
253
+ - Your Gerrit instance uses a non-standard HTTP base path (e.g. /r)
254
+
255
+ Example:
256
+
257
+ ```yaml
258
+ name: github2gerrit (advanced)
259
+
260
+ on:
261
+ pull_request_target:
262
+ types: [opened, reopened, edited, synchronize]
263
+ workflow_dispatch:
264
+
265
+ permissions:
266
+ contents: read
267
+ pull-requests: write
268
+ issues: write
269
+
270
+ jobs:
271
+ submit-to-gerrit:
272
+ runs-on: ubuntu-latest
273
+ steps:
274
+ - name: Install SSH key and custom SSH config
275
+ <!-- markdownlint-disable-next-line MD013 -->
276
+ uses: shimataro/ssh-key-action@d4fffb50872869abe2d9a9098a6d9c5aa7d16be4 # v2.7.0
277
+ with:
278
+ key: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
279
+ name: "id_rsa"
280
+ known_hosts: ${{ vars.GERRIT_KNOWN_HOSTS }}
281
+ config: |
282
+ Host ${{ vars.GERRIT_SERVER }}
283
+ User ${{ vars.GERRIT_SSH_USER_G2G }}
284
+ Port ${{ vars.GERRIT_SERVER_PORT }}
285
+ PubkeyAcceptedKeyTypes +ssh-rsa
286
+ IdentityFile ~/.ssh/id_rsa
287
+
288
+ - name: Submit PR to Gerrit (with explicit overrides)
289
+ id: g2g
290
+ uses: lfit/github2gerrit@main
291
+ with:
292
+ # Behavior
293
+ SUBMIT_SINGLE_COMMITS: "false"
294
+ USE_PR_AS_COMMIT: "false"
295
+ FETCH_DEPTH: "10"
296
+
297
+ # Required SSH/identity
298
+ GERRIT_KNOWN_HOSTS: ${{ vars.GERRIT_KNOWN_HOSTS }}
299
+ GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
300
+ GERRIT_SSH_USER_G2G: ${{ vars.GERRIT_SSH_USER_G2G }}
301
+ GERRIT_SSH_USER_G2G_EMAIL: ${{ vars.GERRIT_SSH_USER_G2G_EMAIL }}
302
+
303
+ # Optional overrides when .gitreview is missing or to force values
304
+ GERRIT_SERVER: ${{ vars.GERRIT_SERVER }}
305
+ GERRIT_SERVER_PORT: ${{ vars.GERRIT_SERVER_PORT }}
306
+ GERRIT_PROJECT: ${{ vars.GERRIT_PROJECT }}
307
+
308
+ # Optional Gerrit REST base path and credentials (if required)
309
+ # e.g. '/r' for some deployments
310
+ GERRIT_HTTP_BASE_PATH: ${{ vars.GERRIT_HTTP_BASE_PATH }}
311
+ GERRIT_HTTP_USER: ${{ vars.GERRIT_HTTP_USER }}
312
+ GERRIT_HTTP_PASSWORD: ${{ secrets.GERRIT_HTTP_PASSWORD }}
313
+
314
+ ORGANIZATION: ${{ github.repository_owner }}
315
+ REVIEWERS_EMAIL: ""
316
+ ```
317
+
318
+ Notes:
319
+
320
+ - If both this step and the action define SSH configuration, the last
321
+ configuration applied in the runner wins.
322
+ - For most users, you can rely on the action’s built-in SSH setup. Use this
323
+ advanced configuration when you need custom SSH behavior or hosts.
324
+
325
+ ## GitHub Enterprise support
326
+
327
+ - Direct-URL mode accepts enterprise GitHub hosts when explicitly enabled.
328
+ Default: off (use github.com by default). Enable via the CLI flag
329
+ --allow-ghe-urls or by setting ALLOW_GHE_URLS="true".
330
+ - In GitHub Actions, this action works with GitHub Enterprise when the
331
+ workflow runs in that enterprise environment and provides a valid
332
+ GITHUB_TOKEN. For direct-URL runs outside Actions, ensure ORGANIZATION
333
+ and GITHUB_REPOSITORY reflect the target repository.
334
+
335
+ ## Inputs
336
+
337
+ All inputs are strings, matching the composite action.
338
+
339
+ - SUBMIT_SINGLE_COMMITS
340
+ - Submit one commit at a time to Gerrit. Default: "false".
341
+ - USE_PR_AS_COMMIT
342
+ - Use PR title and body as the commit message. Default: "false".
343
+ - FETCH_DEPTH
344
+ - Depth used when checking out the repository. Default: "10".
345
+ - GERRIT_KNOWN_HOSTS
346
+ - SSH known hosts content for the Gerrit host. Required.
347
+ - GERRIT_SSH_PRIVKEY_G2G
348
+ - SSH private key for Gerrit. Required.
349
+ - GERRIT_SSH_USER_G2G
350
+ - Gerrit SSH username. Required.
351
+ - GERRIT_SSH_USER_G2G_EMAIL
352
+ - Gerrit SSH user email (used for commit identity). Required.
353
+ - ORGANIZATION
354
+ - Organization name, defaults to `github.repository_owner`.
355
+ - REVIEWERS_EMAIL
356
+ - Comma separated reviewer emails. If empty, defaults to
357
+ `GERRIT_SSH_USER_G2G_EMAIL`.
358
+ - ALLOW_GHE_URLS
359
+ - Allow non-github.com GitHub Enterprise URLs in direct URL mode. Default: "false".
360
+ - Set to "true" to allow non-github.com enterprise hosts.
361
+
362
+ Optional inputs when `.gitreview` is not present (parity with
363
+ the reusable workflow):
364
+
365
+ - GERRIT_SERVER
366
+ - Gerrit host, e.g. `git.opendaylight.org`. Default: "".
367
+ - GERRIT_SERVER_PORT
368
+ - Gerrit port, default "29418".
369
+ - GERRIT_PROJECT
370
+ - Gerrit project name, e.g. `releng/builder`. Default: "".
371
+
372
+ ## Outputs
373
+
374
+ - url
375
+ - Gerrit change URL(s). Multi‑line when the action submits more than one change.
376
+ - change_number
377
+ - Gerrit change number(s). Multi‑line when the action submits more than one change.
378
+
379
+ These outputs mirror the composite action. They are also exported into
380
+ the environment as:
381
+
382
+ - GERRIT_CHANGE_REQUEST_URL
383
+ - GERRIT_CHANGE_REQUEST_NUM
384
+
385
+ ## Behavior details
386
+
387
+ - Branch resolution
388
+ - Uses `GITHUB_BASE_REF` as the target branch for Gerrit, or defaults
389
+ to `master` when unset, matching the existing workflow.
390
+ - Topic naming
391
+ - Uses `GH-<repo>-<pr-number>` where `<repo>` replaces slashes with
392
+ hyphens.
393
+ - GitHub Enterprise support
394
+ - Direct URL mode accepts enterprise GitHub hosts when explicitly enabled
395
+ (default: off; use github.com by default). Enable via --allow-ghe-urls or
396
+ ALLOW_GHE_URLS="true". The tool determines the GitHub API base URL from
397
+ GITHUB_API_URL or GITHUB_SERVER_URL/api/v3.
398
+ - Change‑Id handling
399
+ - Single commits: the process amends each cherry‑picked commit to include a
400
+ `Change-Id`. The tool collects these values for querying.
401
+ - Squashed: collects trailers from original commits, preserves
402
+ `Signed-off-by`, and reuses the `Change-Id` when PRs reopen or synchronize.
403
+ - Reviewers
404
+ - If empty, defaults to the Gerrit SSH user email.
405
+ - Comments
406
+ - Adds a back‑reference comment in Gerrit with the GitHub PR and run
407
+ URL. Adds a comment on the GitHub PR with the Gerrit change URL(s).
408
+ - Closing PRs
409
+ - On `pull_request_target`, the workflow may close the PR after submission to
410
+ match the shell action’s behavior.
411
+
412
+ ## Security notes
413
+
414
+ - Do not hardcode secrets or keys. Provide the private key via the
415
+ workflow secrets and known hosts via repository or org variables.
416
+ - SSH handling is non-invasive: the tool creates temporary SSH files in
417
+ the workspace without modifying user SSH configuration or keys.
418
+ - SSH agent scanning prevention uses `IdentitiesOnly=yes` to avoid
419
+ unintended key usage (e.g., signing keys requiring biometric auth).
420
+ - Temporary SSH files are automatically cleaned up after execution.
421
+ - All external calls should use retries and clear error reporting.
422
+
423
+ ## Development
424
+
425
+ This repository follows the guidelines in `CLAUDE.md`.
426
+
427
+ - Language and CLI
428
+ - Python 3.11. The CLI uses Typer.
429
+ - Packaging
430
+ - `pyproject.toml` with PDM backend. Use `uv` to install and run.
431
+ - Structure
432
+ - `src/github2gerrit/cli.py` (CLI entrypoint)
433
+ - `src/github2gerrit/core.py` (orchestration)
434
+ - `src/github2gerrit/gitutils.py` (subprocess and git helpers)
435
+ - Linting and type checking
436
+ - Ruff and MyPy use settings in `pyproject.toml`.
437
+ - Run from pre‑commit hooks and CI.
438
+ - Tests
439
+ - Pytest with coverage targets around 80%.
440
+ - Add unit and integration tests for each feature.
441
+
442
+ ### Local setup
443
+
444
+ - Install `uv` and run:
445
+ - `uv pip install --system .`
446
+ - `uv run github2gerrit --help`
447
+ - Run tests:
448
+ - `uv run pytest -q`
449
+ - Lint and type check:
450
+ - `uv run ruff check .`
451
+ - `uv run black --check .`
452
+ - `uv run mypy src`
453
+
454
+ ### Notes on parity
455
+
456
+ - Inputs, outputs, and environment usage match the shell action.
457
+ - The action assumes the same GitHub variables and secrets are present.
458
+ - Where the shell action uses tools such as `jq` and `gh`, the Python
459
+ version uses library calls and subprocess as appropriate, with retries
460
+ and clear logging.
461
+
462
+ ## License
463
+
464
+ Apache License 2.0. See `LICENSE` for details.
@@ -0,0 +1,4 @@
1
+ github2gerrit-0.1.0.dist-info/METADATA,sha256=crIJcduqPRdW83ZJIEH4f4EcH4x5eY5o-18MZ5v0PDk,16475
2
+ github2gerrit-0.1.0.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
+ github2gerrit-0.1.0.dist-info/entry_points.txt,sha256=k9o_IZVaczDj5WeWlM3q5l86YJyVK5TEhJLV09ZPU_4,72
4
+ github2gerrit-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: pdm-backend (2.4.5)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,5 @@
1
+ [console_scripts]
2
+ github2gerrit = github2gerrit.cli:app
3
+
4
+ [gui_scripts]
5
+