github2gerrit 0.1.5__py3-none-any.whl → 0.1.7__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,798 @@
1
+ Metadata-Version: 2.4
2
+ Name: github2gerrit
3
+ Version: 0.1.7
4
+ Summary: Submit a GitHub pull request to a Gerrit repository.
5
+ Author-email: Matthew Watkins <mwatkins@linuxfoundation.org>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/lfreleng-actions/github2gerrit
8
+ Project-URL: Repository, https://github.com/lfreleng-actions/github2gerrit
9
+ Project-URL: Issues, https://github.com/lfreleng-actions/github2gerrit/issues
10
+ Keywords: github,gerrit,ci,actions,typer,cli
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Build Tools
20
+ Classifier: Topic :: Software Development :: Version Control
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: <3.14,>=3.11
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: typer>=0.12.5
26
+ Requires-Dist: PyGithub>=2.3.0
27
+ Requires-Dist: pygerrit2>=2.0.0
28
+ Requires-Dist: git-review>=2.3.1
29
+ Requires-Dist: PyYAML>=6.0.1
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=8.3.2; extra == "dev"
32
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
33
+ Requires-Dist: coverage[toml]>=7.6.1; extra == "dev"
34
+ Requires-Dist: ruff>=0.6.3; extra == "dev"
35
+ Requires-Dist: mypy>=1.11.2; extra == "dev"
36
+ Requires-Dist: pytest-mock>=3.14.0; extra == "dev"
37
+ Requires-Dist: types-requests>=2.31.0; extra == "dev"
38
+ Requires-Dist: types-click>=7.1.8; extra == "dev"
39
+ Dynamic: license-file
40
+
41
+ <!--
42
+ SPDX-License-Identifier: Apache-2.0
43
+ SPDX-FileCopyrightText: 2025 The Linux Foundation
44
+ -->
45
+
46
+ # github2gerrit
47
+
48
+ Submit a GitHub pull request to a Gerrit repository, implemented in Python.
49
+
50
+ This action is a drop‑in replacement for the shell‑based
51
+ `lfit/github2gerrit` composite action. It mirrors the same inputs,
52
+ outputs, environment variables, and secrets so you can adopt it without
53
+ changing existing configuration in your organizations.
54
+
55
+ The tool expects a `.gitreview` file in the repository to derive Gerrit
56
+ connection details and the destination project. It uses `git` over SSH
57
+ and `git-review` semantics to push to `refs/for/<branch>` and relies on
58
+ Gerrit `Change-Id` trailers to create or update changes.
59
+
60
+ ## How it works (high level)
61
+
62
+ - Discover pull request context and inputs.
63
+ - Detects and prevents tool runs from creating duplicate changes.
64
+ - Reads `.gitreview` for Gerrit host, port, and project.
65
+ - When run locally, will pull `.gitreview` from the remote repository.
66
+ - Sets up `git` user config and SSH for Gerrit.
67
+ - Prepare commits:
68
+ - one‑by‑one cherry‑pick with `Change-Id` trailers, or
69
+ - squash into a single commit and keep or reuse `Change-Id`.
70
+ - Optionally replace the commit message with PR title and body.
71
+ - Push with a topic to `refs/for/<branch>` using `git-review` behavior.
72
+ - Query Gerrit for the resulting URL, change number, and patchset SHA.
73
+ - Add a back‑reference comment in Gerrit to the GitHub PR and run URL.
74
+ - Comment on the GitHub PR with the Gerrit change URL(s).
75
+ - Optionally close the PR (mirrors the shell action policy).
76
+
77
+ ## Requirements
78
+
79
+ - Repository contains a `.gitreview` file. If you cannot provide it,
80
+ you must pass `GERRIT_SERVER`, `GERRIT_SERVER_PORT`, and
81
+ `GERRIT_PROJECT` via the reusable workflow interface.
82
+ - SSH key used to push changes into Gerrit
83
+ - The system populates Gerrit known hosts automatically on first run.
84
+ - The default `GITHUB_TOKEN` is available for PR metadata and comments.
85
+ - The workflow grants permissions required for PR interactions:
86
+ - `pull-requests: write` (to comment on and close PRs)
87
+ - `issues: write` (to create PR comments via the Issues API)
88
+ - The workflow runs with `pull_request_target` or via
89
+ `workflow_dispatch` using a valid PR context.
90
+
91
+ ### Note on sitecustomize.py
92
+
93
+ This repository includes a sitecustomize.py that is automatically
94
+ imported by Python’s site initialization. It exists to make pytest and
95
+ coverage runs in CI more robust by:
96
+
97
+ - assigns a unique COVERAGE_FILE per process to avoid mixing data across runs
98
+ - proactively removing stale .coverage artifacts in common base directories.
99
+
100
+ The logic runs during pytest sessions and is best effort.
101
+ It never interferes with normal execution. Maintainers can keep it to
102
+ stabilize coverage reporting for parallel/xdist runs.
103
+
104
+ ## Duplicate detection
105
+
106
+ Duplicate detection uses a scoring-based approach. Instead of relying on a hash
107
+ added by this action, the detector compares the first line of the commit message
108
+ (subject/PR title), analyzes the body text and the set of files changed, and
109
+ computes a similarity score. When the score meets or exceeds a configurable
110
+ threshold (default 0.8), the tool treats the change as a duplicate and blocks
111
+ submission. This approach aims to remain robust even when similar changes
112
+ appeared outside this pipeline.
113
+
114
+ ### Examples of detected duplicates
115
+
116
+ - Dependency bumps for the same package across close versions
117
+ (e.g., "Bump foo from 1.0 to 1.1" vs "Bump foo from 1.1 to 1.2")
118
+ with overlapping files — high score
119
+ - Pre-commit autoupdates that change .pre-commit-config.yaml and hook versions —
120
+ high score
121
+ - GitHub Actions version bumps that update .github/workflows/* uses lines —
122
+ medium to high score
123
+ - Similar bug fixes with the same subject and significant file overlap —
124
+ strong match
125
+
126
+ ### Allowing duplicates
127
+
128
+ Use `--allow-duplicates` or set `ALLOW_DUPLICATES=true` to override:
129
+
130
+ ```bash
131
+ # CLI usage
132
+ github2gerrit --allow-duplicates https://github.com/org/repo
133
+
134
+ # GitHub Actions
135
+ uses: onap/github2gerrit@main
136
+ with:
137
+ ALLOW_DUPLICATES: 'true'
138
+ ```
139
+
140
+ When allowed, duplicates generate warnings but processing continues.
141
+ The tool exits with code 3 when it detects duplicates and they are not allowed.
142
+
143
+ ## Commit Message Normalization
144
+
145
+ The tool includes intelligent commit message normalization that automatically
146
+ converts automated PR titles (from tools like Dependabot, pre-commit.ci, etc.)
147
+ to follow conventional commit standards. This feature defaults to enabled
148
+ and you can control it via the `NORMALISE_COMMIT` setting.
149
+
150
+ ### How it works
151
+
152
+ 1. **Repository Analysis**: The tool analyzes your repository to determine
153
+ preferred conventional commit patterns by examining:
154
+ - `.pre-commit-config.yaml` for commit message formats
155
+ - `.github/release-drafter.yml` for commit type patterns
156
+ - Recent git history for existing conventional commit usage
157
+
158
+ 2. **Smart Detection**: Applies normalization to automated PRs from
159
+ known bots (dependabot[bot], pre-commit-ci[bot], etc.) or PRs with
160
+ automation patterns in the title.
161
+
162
+ 3. **Adaptive Formatting**: Respects your repository's existing conventions:
163
+ - **Capitalization**: Detects whether you use `feat:` or `FEAT:`
164
+ - **Commit Types**: Uses appropriate types (`chore`, `build`, `ci`, etc.)
165
+ - **Dependency Updates**: Converts "Bump package from X to Y" to
166
+ "chore: bump package from X to Y"
167
+
168
+ ### Examples
169
+
170
+ **Before normalization:**
171
+
172
+ ```text
173
+ Bump net.logstash.logback:logstash-logback-encoder from 7.4 to 8.1
174
+ pre-commit autoupdate
175
+ Update GitHub Action dependencies
176
+ ```
177
+
178
+ **After normalization:**
179
+
180
+ ```text
181
+ chore: bump net.logstash.logback:logstash-logback-encoder from 7.4 to 8.1
182
+ chore: pre-commit autoupdate
183
+ build: update GitHub Action dependencies
184
+ ```
185
+
186
+ ### Configuration
187
+
188
+ Enable or disable commit normalization:
189
+
190
+ ```bash
191
+ # CLI usage
192
+ github2gerrit --normalise-commit https://github.com/org/repo
193
+ github2gerrit --no-normalise-commit https://github.com/org/repo
194
+
195
+ # Environment variable
196
+ NORMALISE_COMMIT=true github2gerrit https://github.com/org/repo
197
+ NORMALISE_COMMIT=false github2gerrit https://github.com/org/repo
198
+
199
+ # GitHub Actions
200
+ uses: onap/github2gerrit@main
201
+ with:
202
+ NORMALISE_COMMIT: 'true' # default
203
+ # or
204
+ NORMALISE_COMMIT: 'false' # disable
205
+ ```
206
+
207
+ ### Repository-specific Configuration
208
+
209
+ To influence the normalization behavior, configure your repository:
210
+
211
+ **`.pre-commit-config.yaml`:**
212
+
213
+ ```yaml
214
+ ci:
215
+ autofix_commit_msg: |
216
+ Chore: pre-commit autofixes
217
+
218
+ Signed-off-by: pre-commit-ci[bot] <pre-commit-ci@users.noreply.github.com>
219
+ autoupdate_commit_msg: |
220
+ Chore: pre-commit autoupdate
221
+
222
+ Signed-off-by: pre-commit-ci[bot] <pre-commit-ci@users.noreply.github.com>
223
+ ```
224
+
225
+ **`.github/release-drafter.yml`:**
226
+
227
+ ```yaml
228
+ autolabeler:
229
+ - label: "chore"
230
+ title:
231
+ - "/chore:/i"
232
+ - label: "feature"
233
+ title:
234
+ - "/feat:/i"
235
+ - label: "bug"
236
+ title:
237
+ - "/fix:/i"
238
+ ```
239
+
240
+ The tool will detect the capitalization style from these files and apply
241
+ it consistently to normalized commit messages.
242
+
243
+ ## Exit Codes
244
+
245
+ The CLI tool uses specific exit codes to signal different types of failures,
246
+ making it easier to handle errors in automation and CI/CD pipelines:
247
+
248
+ | Exit Code | Description | Common Causes |
249
+ |-----------|-------------|---------------|
250
+ | `0` | Success | Operation completed |
251
+ | `1` | General runtime failure | Submission pipeline errors, Git operations failed, network issues, unhandled exceptions |
252
+ | `2` | Configuration or validation error | Invalid configuration parameters, missing required settings, empty PR context |
253
+ | `3` | Duplicate detection blocked submission | Similar change already exists in Gerrit and `ALLOW_DUPLICATES` is `false` |
254
+
255
+ ### Example Usage in CI/CD
256
+
257
+ ```bash
258
+ # Run the tool and handle different exit codes
259
+ if github2gerrit "$PR_URL"; then
260
+ echo "✅ Submitted to Gerrit"
261
+ elif [ $? -eq 2 ]; then
262
+ echo "❌ Configuration error - check your settings"
263
+ exit 1
264
+ elif [ $? -eq 3 ]; then
265
+ echo "⚠️ Duplicate detected - use ALLOW_DUPLICATES=true to override"
266
+ exit 0 # Treat as non-fatal in some workflows
267
+ else
268
+ echo "❌ Runtime failure - check logs for details"
269
+ exit 1
270
+ fi
271
+ ```
272
+
273
+ ## Usage
274
+
275
+ This action runs as part of a workflow that triggers on
276
+ `pull_request_target` and also supports manual runs via
277
+ `workflow_dispatch`.
278
+
279
+ Minimal example:
280
+
281
+ ```yaml
282
+ name: github2gerrit
283
+
284
+ on:
285
+ pull_request_target:
286
+ types: [opened, reopened, edited, synchronize]
287
+ workflow_dispatch:
288
+
289
+ permissions:
290
+ contents: read
291
+ pull-requests: write
292
+ issues: write
293
+
294
+ jobs:
295
+ submit-to-gerrit:
296
+ runs-on: ubuntu-latest
297
+ steps:
298
+ - name: Submit PR to Gerrit
299
+ id: g2g
300
+ uses: lfit/github2gerrit@main
301
+ with:
302
+ SUBMIT_SINGLE_COMMITS: "false"
303
+ USE_PR_AS_COMMIT: "false"
304
+ FETCH_DEPTH: "10"
305
+ GERRIT_KNOWN_HOSTS: ${{ vars.GERRIT_KNOWN_HOSTS }}
306
+ GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
307
+ GERRIT_SSH_USER_G2G: ${{ vars.GERRIT_SSH_USER_G2G }}
308
+ GERRIT_SSH_USER_G2G_EMAIL: ${{ vars.GERRIT_SSH_USER_G2G_EMAIL }}
309
+ ORGANIZATION: ${{ github.repository_owner }}
310
+ REVIEWERS_EMAIL: ""
311
+ ISSUE_ID: "" # Optional: adds 'Issue-ID: ...' trailer to the commit message
312
+ ```
313
+
314
+ The action reads `.gitreview`. If `.gitreview` is absent, you must
315
+ supply Gerrit connection details through a reusable workflow or by
316
+ setting the corresponding environment variables before invoking the
317
+ action. The shell action enforces `.gitreview` for the composite
318
+ variant; this Python action mirrors that behavior for compatibility.
319
+
320
+ ## Command Line Usage and Debugging
321
+
322
+ ### Direct Command Line Usage
323
+
324
+ You can run the tool directly from the command line to process GitHub pull requests.
325
+
326
+ **For development (with local checkout):**
327
+
328
+ ```bash
329
+ # Process a specific pull request
330
+ uv run github2gerrit https://github.com/owner/repo/pull/123
331
+
332
+ # Process all open pull requests in a repository
333
+ uv run github2gerrit https://github.com/owner/repo
334
+
335
+ # Run in CI mode (reads from environment variables)
336
+ uv run github2gerrit
337
+ ```
338
+
339
+ **For CI/CD or one-time usage:**
340
+
341
+ ```bash
342
+ # Install and run in one command
343
+ uvx github2gerrit https://github.com/owner/repo/pull/123
344
+
345
+ # Install from specific version/source
346
+ uvx --from git+https://github.com/lfit/github2gerrit@main github2gerrit https://github.com/owner/repo/pull/123
347
+ ```
348
+
349
+ ### Available Options
350
+
351
+ ```bash
352
+ # View help (local development)
353
+ uv run github2gerrit --help
354
+
355
+ # View help (CI/CD)
356
+ uvx github2gerrit --help
357
+ ```
358
+
359
+ The comprehensive [Inputs](#inputs) table above documents all CLI options and shows
360
+ alignment between action inputs, environment variables, and CLI flags. All CLI flags
361
+ have corresponding environment variables for configuration.
362
+
363
+ Key options include:
364
+
365
+ - `--verbose` / `-v`: Enable verbose debug logging (`G2G_VERBOSE`)
366
+ - `--dry-run`: Check configuration without making changes (`DRY_RUN`)
367
+ - `--submit-single-commits`: Submit each commit individually (`SUBMIT_SINGLE_COMMITS`)
368
+ - `--use-pr-as-commit`: Use PR title/body as commit message (`USE_PR_AS_COMMIT`)
369
+ - `--issue-id`: Add an Issue-ID trailer (e.g., "Issue-ID: ABC-123") to the commit message (`ISSUE_ID`)
370
+ - `--preserve-github-prs`: Don't close GitHub PRs after submission (`PRESERVE_GITHUB_PRS`)
371
+
372
+ For a complete list of all available options, see the [Inputs](#inputs) section.
373
+
374
+ ### Debugging and Troubleshooting
375
+
376
+ When encountering issues, enable verbose logging to see detailed execution:
377
+
378
+ ```bash
379
+ # Using the CLI flag
380
+ github2gerrit --verbose https://github.com/owner/repo/pull/123
381
+
382
+ # Using environment variable
383
+ G2G_LOG_LEVEL=DEBUG github2gerrit https://github.com/owner/repo/pull/123
384
+
385
+ # Alternative environment variable
386
+ G2G_VERBOSE=true github2gerrit https://github.com/owner/repo/pull/123
387
+ ```
388
+
389
+ Debug output includes:
390
+
391
+ - Git command execution and output
392
+ - SSH connection attempts
393
+ - Gerrit API interactions
394
+ - Branch resolution logic
395
+ - Change-Id processing
396
+
397
+ Common issues and solutions:
398
+
399
+ 1. **Configuration Validation Errors**: The tool provides clear error messages when
400
+ required configuration is missing or invalid. Look for messages starting with
401
+ "Configuration validation failed:" that specify missing inputs like
402
+ `GERRIT_KNOWN_HOSTS`, `GERRIT_SSH_PRIVKEY_G2G`, etc.
403
+
404
+ 2. **SSH Permission Denied**:
405
+ - Ensure `GERRIT_SSH_PRIVKEY_G2G` and `GERRIT_KNOWN_HOSTS` are properly set
406
+ - If you see "Permissions 0644 for 'gerrit_key' are too open", the action will automatically try SSH agent
407
+ authentication
408
+ - For persistent file permission issues, ensure `G2G_USE_SSH_AGENT=true` (default)
409
+
410
+ 3. **Branch Not Found**: Check that the target branch exists in both GitHub and Gerrit
411
+ 4. **Change-Id Issues**: Enable debug logging to see Change-Id generation and validation
412
+ 5. **Gerrit API Errors**: Verify Gerrit server connectivity and project permissions
413
+
414
+ > **Note**: The tool displays configuration errors cleanly without Python tracebacks.
415
+ > If you see a traceback in the output, please report it as a bug.
416
+
417
+ ### Environment Variables
418
+
419
+ The comprehensive [Inputs](#inputs) table above documents all environment variables.
420
+ Key variables for CLI usage include:
421
+
422
+ - `G2G_LOG_LEVEL`: Set to `DEBUG` for verbose output (default: `INFO`)
423
+ - `G2G_VERBOSE`: Set to `true` to enable debug logging (same as `--verbose` flag)
424
+ - `GERRIT_SSH_PRIVKEY_G2G`: SSH private key content
425
+ - `GERRIT_KNOWN_HOSTS`: SSH known hosts entries
426
+ - `GERRIT_SSH_USER_G2G`: Gerrit SSH username
427
+ - `G2G_USE_SSH_AGENT`: Set to `false` to force file-based SSH (default: `true`)
428
+ - `DRY_RUN`: Set to `true` for check mode
429
+ - `CI_TESTING`: Set to `true` to ignore `.gitreview` file and use environment variables instead
430
+
431
+ For a complete list of all supported environment variables, their defaults, and
432
+ their corresponding action inputs and CLI flags, see the [Inputs](#inputs) section.
433
+
434
+ ## Advanced usage
435
+
436
+ ### Overriding .gitreview Settings
437
+
438
+ When `CI_TESTING=true`, the tool ignores any `.gitreview` file in the
439
+ repository and uses environment variables instead. This is useful for:
440
+
441
+ - **Integration testing** against different Gerrit servers
442
+ - **Overriding repository settings** when the `.gitreview` points to the wrong server
443
+ - **Development and debugging** with custom Gerrit configurations
444
+
445
+ **Example:**
446
+
447
+ ```bash
448
+ export CI_TESTING=true
449
+ export GERRIT_SERVER=gerrit.example.org
450
+ export GERRIT_PROJECT=sandbox
451
+ github2gerrit https://github.com/org/repo/pull/123
452
+ ```
453
+
454
+ ### SSH Authentication Methods
455
+
456
+ This action supports two SSH authentication methods:
457
+
458
+ 1. **SSH Agent Authentication (Default)**: More secure, avoids file permission issues in CI
459
+ 2. **File-based Authentication**: Fallback method that writes keys to temporary files
460
+
461
+ #### SSH Agent Authentication
462
+
463
+ By default, the action uses SSH agent to load keys into memory rather than writing them to disk. This is more
464
+ secure and avoids the file permission issues commonly seen in CI environments.
465
+
466
+ To control this behavior:
467
+
468
+ ```yaml
469
+ - name: Submit to Gerrit
470
+ uses: your-org/github2gerrit-action@v1
471
+ env:
472
+ G2G_USE_SSH_AGENT: "true" # Default: enables SSH agent (recommended)
473
+ # G2G_USE_SSH_AGENT: "false" # Forces file-based authentication
474
+ with:
475
+ GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
476
+ # ... other inputs
477
+ ```
478
+
479
+ **Benefits of SSH Agent Authentication:**
480
+
481
+ - No temporary files written to disk
482
+ - Avoids SSH key file permission issues (0644 vs 0600)
483
+ - More secure in containerized CI environments
484
+ - Automatic cleanup when process exits
485
+
486
+ #### File-based Authentication (Fallback)
487
+
488
+ If SSH agent setup fails, the action automatically falls back to writing the SSH key to a temporary file with
489
+ secure permissions. This method:
490
+
491
+ - Creates files in workspace-specific `.ssh-g2g/` directory
492
+ - Attempts to set proper file permissions (0600)
493
+ - Includes four fallback permission-setting strategies for CI environments
494
+
495
+ ### Custom SSH Configuration
496
+
497
+ You can explicitly install the SSH key and provide a custom SSH configuration
498
+ before invoking this action. This is useful when:
499
+
500
+ - You want to override the port/host used by SSH
501
+ - You need to define host aliases or SSH options
502
+ - Your Gerrit instance uses a non-standard HTTP base path (e.g. /r)
503
+
504
+ Example:
505
+
506
+ ```yaml
507
+ name: github2gerrit (advanced)
508
+
509
+ on:
510
+ pull_request_target:
511
+ types: [opened, reopened, edited, synchronize]
512
+ workflow_dispatch:
513
+
514
+ permissions:
515
+ contents: read
516
+ pull-requests: write
517
+ issues: write
518
+
519
+ jobs:
520
+ submit-to-gerrit:
521
+ runs-on: ubuntu-latest
522
+ steps:
523
+
524
+
525
+ - name: Submit PR to Gerrit (with explicit overrides)
526
+ id: g2g
527
+ uses: lfit/github2gerrit@main
528
+ with:
529
+ # Behavior
530
+ SUBMIT_SINGLE_COMMITS: "false"
531
+ USE_PR_AS_COMMIT: "false"
532
+ FETCH_DEPTH: "10"
533
+
534
+ # Required SSH/identity
535
+ GERRIT_KNOWN_HOSTS: ${{ vars.GERRIT_KNOWN_HOSTS }}
536
+ GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
537
+ GERRIT_SSH_USER_G2G: ${{ vars.GERRIT_SSH_USER_G2G }}
538
+ GERRIT_SSH_USER_G2G_EMAIL: ${{ vars.GERRIT_SSH_USER_G2G_EMAIL }}
539
+
540
+ # Optional overrides when .gitreview is missing or to force values
541
+ GERRIT_SERVER: ${{ vars.GERRIT_SERVER }}
542
+ GERRIT_SERVER_PORT: ${{ vars.GERRIT_SERVER_PORT }}
543
+ GERRIT_PROJECT: ${{ vars.GERRIT_PROJECT }}
544
+
545
+ # Optional Gerrit REST base path and credentials (if required)
546
+ # e.g. '/r' for some deployments
547
+ GERRIT_HTTP_BASE_PATH: ${{ vars.GERRIT_HTTP_BASE_PATH }}
548
+ GERRIT_HTTP_USER: ${{ vars.GERRIT_HTTP_USER }}
549
+ GERRIT_HTTP_PASSWORD: ${{ secrets.GERRIT_HTTP_PASSWORD }}
550
+
551
+ ORGANIZATION: ${{ github.repository_owner }}
552
+ REVIEWERS_EMAIL: ""
553
+ ```
554
+
555
+ Notes:
556
+
557
+ - The action configures SSH internally using the provided inputs (key,
558
+ known_hosts) and does not use the runner’s SSH agent or ~/.ssh/config.
559
+ - Do not add external steps to install SSH keys or edit SSH config; they’re
560
+ unnecessary and may conflict with the action.
561
+
562
+ ## GitHub Enterprise support
563
+
564
+ - Direct-URL mode accepts enterprise GitHub hosts when explicitly enabled.
565
+ Default: off (use github.com by default). Enable via the CLI flag
566
+ --allow-ghe-urls or by setting ALLOW_GHE_URLS="true".
567
+ - In GitHub Actions, this action works with GitHub Enterprise when the
568
+ workflow runs in that enterprise environment and provides a valid
569
+ GITHUB_TOKEN. For direct-URL runs outside Actions, ensure ORGANIZATION
570
+ and GITHUB_REPOSITORY reflect the target repository.
571
+
572
+ ## Inputs
573
+
574
+ All inputs are strings, matching the composite action. The following table shows
575
+ alignment between action inputs, environment variables, and CLI flags:
576
+
577
+ | Action Input | Environment Variable | CLI Flag | Required | Default | Description |
578
+ |-------------|---------------------|----------|----------|---------|-------------|
579
+ | `SUBMIT_SINGLE_COMMITS` | `SUBMIT_SINGLE_COMMITS` | `--submit-single-commits` | No | `"false"` | Submit one commit at a time to Gerrit |
580
+ | `USE_PR_AS_COMMIT` | `USE_PR_AS_COMMIT` | `--use-pr-as-commit` | No | `"false"` | Use PR title and body as the commit message |
581
+ | `FETCH_DEPTH` | `FETCH_DEPTH` | `--fetch-depth` | No | `"10"` | Fetch depth for checkout |
582
+ | `PR_NUMBER` | `PR_NUMBER` | N/A | No | `"0"` | Pull request number to process (workflow_dispatch) |
583
+ | `GERRIT_KNOWN_HOSTS` | `GERRIT_KNOWN_HOSTS` | `--gerrit-known-hosts` | Yes | N/A | SSH known hosts entries for Gerrit |
584
+ | `GERRIT_SSH_PRIVKEY_G2G` | `GERRIT_SSH_PRIVKEY_G2G` | `--gerrit-ssh-privkey-g2g` | Yes | N/A | SSH private key content for Gerrit authentication |
585
+ | `GERRIT_SSH_USER_G2G` | `GERRIT_SSH_USER_G2G` | `--gerrit-ssh-user-g2g` | No¹ | `""` | Gerrit SSH username (auto-derived if enabled) |
586
+ | `GERRIT_SSH_USER_G2G_EMAIL` | `GERRIT_SSH_USER_G2G_EMAIL` | `--gerrit-ssh-user-g2g-email` | No¹ | `""` | Email for Gerrit SSH user (auto-derived if enabled) |
587
+ | `ORGANIZATION` | `ORGANIZATION` | `--organization` | No | `${{ github.repository_owner }}` | GitHub organization/owner |
588
+ | `REVIEWERS_EMAIL` | `REVIEWERS_EMAIL` | `--reviewers-email` | No | `""` | Comma-separated reviewer emails |
589
+ | `ALLOW_GHE_URLS` | `ALLOW_GHE_URLS` | `--allow-ghe-urls` | No | `"false"` | Allow GitHub Enterprise URLs in direct URL mode |
590
+ | `PRESERVE_GITHUB_PRS` | `PRESERVE_GITHUB_PRS` | `--preserve-github-prs` | No | `"false"` | Do not close GitHub PRs after pushing to Gerrit |
591
+ | `DRY_RUN` | `DRY_RUN` | `--dry-run` | No | `"false"` | Check settings/PR metadata; do not write to Gerrit |
592
+ | `ALLOW_DUPLICATES` | `ALLOW_DUPLICATES` | `--allow-duplicates` | No | `"false"` | Allow submitting duplicate changes without error |
593
+ | `CI_TESTING` | `CI_TESTING` | `--ci-testing` | No | `"false"` | Enable CI testing mode (overrides .gitreview) |
594
+ | `ISSUE_ID` | `ISSUE_ID` | `--issue-id` | No | `""` | Issue ID to include (e.g., ABC-123) |
595
+ | `G2G_USE_SSH_AGENT` | `G2G_USE_SSH_AGENT` | N/A | No | `"true"` | Use SSH agent for authentication |
596
+ | `DUPLICATES` | `DUPLICATES` | `--duplicates` | No | `"open"` | Comma-separated Gerrit statuses for duplicate detection |
597
+ | `GERRIT_SERVER` | `GERRIT_SERVER` | `--gerrit-server` | No² | `""` | Gerrit server hostname (auto-derived if enabled) |
598
+ | `GERRIT_SERVER_PORT` | `GERRIT_SERVER_PORT` | `--gerrit-server-port` | No | `"29418"` | Gerrit SSH port |
599
+ | `GERRIT_PROJECT` | `GERRIT_PROJECT` | `--gerrit-project` | No² | `""` | Gerrit project name |
600
+ | `GERRIT_HTTP_BASE_PATH` | `GERRIT_HTTP_BASE_PATH` | N/A | No | `""` | HTTP base path for Gerrit REST API |
601
+ | `GERRIT_HTTP_USER` | `GERRIT_HTTP_USER` | N/A | No | `""` | Gerrit HTTP user for REST authentication |
602
+ | `GERRIT_HTTP_PASSWORD` | `GERRIT_HTTP_PASSWORD` | N/A | No | `""` | Gerrit HTTP password/token for REST authentication |
603
+ | N/A | `G2G_VERBOSE` | `--verbose`, `-v` | No | `"false"` | Enable verbose debug logging |
604
+
605
+ **Notes:**
606
+
607
+ 1. Auto-derived when `G2G_ENABLE_DERIVATION=true` (default: false in GitHub Actions, true in CLI)
608
+ 2. Optional if `.gitreview` file exists in repository
609
+
610
+ ### Internal Environment Variables
611
+
612
+ The following environment variables control internal behavior but are not action inputs:
613
+
614
+ | Environment Variable | Description | Default |
615
+ |---------------------|-------------|---------|
616
+ | `G2G_LOG_LEVEL` | Logging level (DEBUG, INFO, WARNING, ERROR) | `"INFO"` |
617
+ | `G2G_ENABLE_DERIVATION` | Enable auto-derivation of Gerrit parameters | `"false"` (GitHub Actions), `"true"` (CLI) |
618
+ | `G2G_CONFIG_PATH` | Path to organization configuration file | `~/.config/github2gerrit/config.ini` |
619
+ | `G2G_AUTO_SAVE_CONFIG` | Auto-save derived parameters to config | `"false"` (GitHub Actions), `"true"` (CLI) |
620
+ | `G2G_TARGET_URL` | Internal flag for direct URL mode | Set automatically |
621
+ | `G2G_TMP_BRANCH` | Temporary branch name for single commits | `"tmp_branch"` |
622
+ | `G2G_TOPIC_PREFIX` | Prefix for Gerrit topic names | `"GH"` |
623
+ | `G2G_SKIP_GERRIT_COMMENTS` | Skip posting back-reference comments in Gerrit | `"false"` |
624
+ | `G2G_DRYRUN_DISABLE_NETWORK` | Disable network calls in dry-run mode | `"false"` |
625
+ | `SYNC_ALL_OPEN_PRS` | Process all open PRs (set automatically) | Set automatically |
626
+ | `GERRIT_BRANCH` | Override target branch for Gerrit | Uses `GITHUB_BASE_REF` |
627
+ | `GITHUB_TOKEN` | GitHub API token | Provided by GitHub Actions |
628
+ | `GITHUB_*` context | GitHub Actions context variables | Provided by GitHub Actions |
629
+
630
+ ## Outputs
631
+
632
+ The action provides the following outputs for use in later workflow steps:
633
+
634
+ | Output Name | Description | Environment Variable |
635
+ |-------------|-------------|---------------------|
636
+ | `gerrit_change_request_url` | Gerrit change URL(s) (newline-separated) | `GERRIT_CHANGE_REQUEST_URL` |
637
+ | `gerrit_change_request_num` | Gerrit change number(s) (newline-separated) | `GERRIT_CHANGE_REQUEST_NUM` |
638
+ | `gerrit_commit_sha` | Patch set commit SHA(s) (newline-separated) | `GERRIT_COMMIT_SHA` |
639
+
640
+ These outputs export automatically as environment variables and are accessible in
641
+ later workflow steps using `${{ steps.<step-id>.outputs.<output-name> }}` syntax.
642
+
643
+ ## Configuration and Parameters
644
+
645
+ For a complete list of all supported configuration parameters, including action
646
+ inputs, environment variables, and CLI flags, see the comprehensive [Inputs](#inputs)
647
+ table above.
648
+
649
+ ### Configuration Precedence
650
+
651
+ The tool follows this precedence order for configuration values:
652
+
653
+ 1. **CLI flags** (highest priority)
654
+ 2. **Environment variables**
655
+ 3. **Configuration file values**
656
+ 4. **Tool defaults** (lowest priority)
657
+
658
+ ### Configuration File Format
659
+
660
+ Configuration files use INI format with organization-specific sections:
661
+
662
+ ```ini
663
+ [default]
664
+ GERRIT_SERVER = "gerrit.example.org"
665
+ PRESERVE_GITHUB_PRS = "true"
666
+
667
+ [onap]
668
+ ISSUE_ID = "CIMAN-33"
669
+ REVIEWERS_EMAIL = "user@example.org"
670
+
671
+ [opendaylight]
672
+ GERRIT_HTTP_USER = "bot-user"
673
+ GERRIT_HTTP_PASSWORD = "${ENV:ODL_GERRIT_TOKEN}"
674
+ ```
675
+
676
+ The tool loads configuration from `~/.config/github2gerrit/configuration.txt`
677
+ by default, or from the path specified in the `G2G_CONFIG_PATH` environment
678
+ variable.
679
+
680
+ **Note**: Unknown configuration keys will generate warnings to help catch typos
681
+ and missing functionality.
682
+
683
+ ## Behavior details
684
+
685
+ - Branch resolution
686
+ - Uses `GITHUB_BASE_REF` as the target branch for Gerrit, or defaults
687
+ to `master` when unset, matching the existing workflow.
688
+ - Topic naming
689
+ - Uses `GH-<repo>-<pr-number>` where `<repo>` replaces slashes with
690
+ hyphens.
691
+ - GitHub Enterprise support
692
+ - Direct URL mode accepts enterprise GitHub hosts when explicitly enabled
693
+ (default: off; use github.com by default). Enable via --allow-ghe-urls or
694
+ ALLOW_GHE_URLS="true". The tool determines the GitHub API base URL from
695
+ GITHUB_API_URL or GITHUB_SERVER_URL/api/v3.
696
+ - Change‑Id handling
697
+ - Single commits: the process amends each cherry‑picked commit to include a
698
+ `Change-Id`. The tool collects these values for querying.
699
+ - Squashed: collects trailers from original commits, preserves
700
+ `Signed-off-by`, and reuses the `Change-Id` when PRs reopen or synchronize.
701
+ - Reviewers
702
+ - If empty, defaults to the Gerrit SSH user email.
703
+ - Comments
704
+ - Adds a back‑reference comment in Gerrit with the GitHub PR and run
705
+ URL. Adds a comment on the GitHub PR with the Gerrit change URL(s).
706
+ - Closing PRs
707
+ - On `pull_request_target`, the workflow may close the PR after submission to
708
+ match the shell action’s behavior.
709
+
710
+ ## Security notes
711
+
712
+ - Do not hardcode secrets or keys. Provide the private key via the
713
+ workflow secrets and known hosts via repository or org variables.
714
+ - SSH handling is non-invasive: the tool creates temporary SSH files in
715
+ the workspace without modifying user SSH configuration or keys.
716
+ - SSH agent scanning prevention uses `IdentitiesOnly=yes` to avoid
717
+ unintended key usage (e.g., signing keys requiring biometric auth).
718
+ - Temporary SSH files are automatically cleaned up after execution.
719
+ - All external calls should use retries and clear error reporting.
720
+
721
+ ## Development
722
+
723
+ - Language and CLI
724
+ - Python 3.11+, the CLI uses Typer.
725
+ - Packaging
726
+ - `pyproject.toml` with setuptools backend. Use `uv` to install and run.
727
+ - Structure
728
+ - `src/github2gerrit/cli.py` (CLI entrypoint)
729
+ - `src/github2gerrit/core.py` (orchestration)
730
+ - `src/github2gerrit/gitutils.py` (subprocess and git helpers)
731
+ - Linting and type checking
732
+ - Ruff and MyPy use settings in `pyproject.toml`.
733
+ - Run from pre‑commit hooks and CI.
734
+ - Tests
735
+ - Pytest with coverage targets around 80%.
736
+ - Add unit and integration tests for each feature.
737
+
738
+ ### Local setup
739
+
740
+ - Install `uv` and run:
741
+ - `uv pip install --system .`
742
+ - `uv run github2gerrit --help`
743
+ - Run tests:
744
+ - `uv run pytest -q`
745
+ - Lint and type check:
746
+ - `uv run ruff check .`
747
+ - `uv run ruff format .`
748
+ - `uv run mypy src`
749
+
750
+ ### Dependency management
751
+
752
+ - **Update dependencies**: Use `uv lock --upgrade` to rebuild and update the `uv.lock` file with the latest compatible versions
753
+ - **Add new dependencies**: Add to `pyproject.toml` then run `uv lock` to update the lock file
754
+ - **Install from lock file**: `uv pip install --system .` will use the exact versions from `uv.lock`
755
+
756
+ ### Local testing and development
757
+
758
+ Test local builds before releases with commands like:
759
+
760
+ ```bash
761
+ # Test against a real PR with dry-run mode
762
+ uv run python -m github2gerrit.cli https://github.com/onap/portal-ng-bff/pull/37 --preserve-github-prs --dry-run
763
+
764
+ # Test with different options
765
+ uv run python -m github2gerrit.cli <PR_URL> --help
766
+
767
+ # Run the CLI directly for development
768
+ uv run github2gerrit --help
769
+ ```
770
+
771
+ ### CI/CD and production usage
772
+
773
+ For CI/CD pipelines (like GitHub Actions), use `uvx` to install and run without managing virtual environments:
774
+
775
+ ```bash
776
+ # Install and run in one command
777
+ uvx github2gerrit <PR_URL> --dry-run
778
+
779
+ # Install from a specific version or source
780
+ uvx --from git+https://github.com/lfit/github2gerrit@main github2gerrit <PR_URL>
781
+
782
+ # Run with specific Python version
783
+ uvx --python 3.11 github2gerrit <PR_URL>
784
+ ```
785
+
786
+ **Note**: `uvx` is ideal for CI/CD as it automatically handles dependency isolation and cleanup.
787
+
788
+ ### Notes on parity
789
+
790
+ - Inputs, outputs, and environment usage match the shell action.
791
+ - The action assumes the same GitHub variables and secrets are present.
792
+ - Where the shell action uses tools such as `jq` and `gh`, the Python
793
+ version uses library calls and subprocess as appropriate, with retries
794
+ and clear logging.
795
+
796
+ ## License
797
+
798
+ Apache License 2.0. See `LICENSE` for details.