github2gerrit 1.3.3__tar.gz → 1.4.0__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.
Files changed (139) hide show
  1. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/.pre-commit-config.yaml +5 -5
  2. github2gerrit-1.4.0/PKG-INFO +386 -0
  3. github2gerrit-1.4.0/README.md +340 -0
  4. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/action.yaml +2 -2
  5. github2gerrit-1.4.0/docs/cli.md +319 -0
  6. github2gerrit-1.4.0/docs/development.md +161 -0
  7. github2gerrit-1.4.0/docs/features.md +731 -0
  8. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/pyproject.toml +0 -15
  9. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/cli.py +3 -2
  10. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_automation_only.py +24 -0
  11. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/uv.lock +75 -85
  12. github2gerrit-1.3.3/PKG-INFO +0 -1734
  13. github2gerrit-1.3.3/README.md +0 -1688
  14. github2gerrit-1.3.3/docs/COMPOSITE_ACTION_TESTING.md +0 -219
  15. github2gerrit-1.3.3/docs/PR_UPDATE_IMPLEMENTATION.md +0 -542
  16. github2gerrit-1.3.3/docs/RELEASE-v0.2.0.md +0 -630
  17. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/.editorconfig +0 -0
  18. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/.gitignore +0 -0
  19. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/.gitlint +0 -0
  20. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/.markdownlint.yaml +0 -0
  21. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/.readthedocs.yml +0 -0
  22. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/.yamllint +0 -0
  23. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/LICENSE +0 -0
  24. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/LICENSES/Apache-2.0.txt +0 -0
  25. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/REUSE.toml +0 -0
  26. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/SECURITY.md +0 -0
  27. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/docs/COMMIT_RULES.md +0 -0
  28. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/docs/github2gerrit_token_permissions_classic.png +0 -0
  29. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/sitecustomize.py +0 -0
  30. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/__init__.py +0 -0
  31. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/commit_normalization.py +0 -0
  32. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/commit_rules.py +0 -0
  33. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/config.py +0 -0
  34. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/constants.py +0 -0
  35. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/core.py +0 -0
  36. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/duplicate_detection.py +0 -0
  37. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/error_codes.py +0 -0
  38. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/external_api.py +0 -0
  39. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/gerrit_pr_closer.py +0 -0
  40. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/gerrit_query.py +0 -0
  41. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/gerrit_rest.py +0 -0
  42. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/gerrit_ssh.py +0 -0
  43. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/gerrit_urls.py +0 -0
  44. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/github_api.py +0 -0
  45. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/gitreview.py +0 -0
  46. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/gitutils.py +0 -0
  47. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/mapping_comment.py +0 -0
  48. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/models.py +0 -0
  49. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/netrc.py +0 -0
  50. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/orchestrator/__init__.py +0 -0
  51. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/orchestrator/reconciliation.py +0 -0
  52. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/pr_commands.py +0 -0
  53. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/pr_content_filter.py +0 -0
  54. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/reconcile_matcher.py +0 -0
  55. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/rich_display.py +0 -0
  56. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/rich_logging.py +0 -0
  57. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/similarity.py +0 -0
  58. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/ssh_agent_setup.py +0 -0
  59. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/ssh_common.py +0 -0
  60. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/ssh_config_parser.py +0 -0
  61. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/ssh_discovery.py +0 -0
  62. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/trailers.py +0 -0
  63. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/src/github2gerrit/utils.py +0 -0
  64. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/conftest.py +0 -0
  65. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/fixtures/__init__.py +0 -0
  66. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/fixtures/make_repo.py +0 -0
  67. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/fixtures/ssh_config_samples.py +0 -0
  68. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_action_environment_mapping.py +0 -0
  69. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_action_outputs.py +0 -0
  70. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_action_pr_number_handling.py +0 -0
  71. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_action_step_validation.py +0 -0
  72. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_change_id_deduplication.py +0 -0
  73. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_clean_squash_title.py +0 -0
  74. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_cli.py +0 -0
  75. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_cli_helpers.py +0 -0
  76. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_cli_netrc_options.py +0 -0
  77. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_cli_outputs_file.py +0 -0
  78. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_cli_url_and_dryrun.py +0 -0
  79. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_commit_normalization.py +0 -0
  80. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_commit_rules.py +0 -0
  81. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_composite_action_coverage.py +0 -0
  82. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_config_and_reviewers.py +0 -0
  83. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_config_helpers.py +0 -0
  84. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_core_close_pr_policy.py +0 -0
  85. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_core_config_and_errors.py +0 -0
  86. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_core_gerrit_backref_comment.py +0 -0
  87. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_core_gerrit_push_errors.py +0 -0
  88. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_core_gerrit_rest_results.py +0 -0
  89. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_core_integration_fixture_repo.py +0 -0
  90. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_core_prepare_commits.py +0 -0
  91. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_core_shallow_clone.py +0 -0
  92. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_core_ssh_setup.py +0 -0
  93. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_core_ssrf_protection.py +0 -0
  94. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_dependency_supersession.py +0 -0
  95. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_dns_validation_and_no_gerrit.py +0 -0
  96. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_duplicate_detection.py +0 -0
  97. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_email_case_normalization.py +0 -0
  98. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_error_codes.py +0 -0
  99. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_external_api_framework.py +0 -0
  100. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_force_flag_cli.py +0 -0
  101. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_gerrit_change_id_footer.py +0 -0
  102. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_gerrit_change_status_checks.py +0 -0
  103. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_gerrit_pr_closer.py +0 -0
  104. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_gerrit_rest_client.py +0 -0
  105. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_gerrit_ssh_abandon.py +0 -0
  106. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_gerrit_urls.py +0 -0
  107. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_gerrit_urls_more.py +0 -0
  108. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_ghe_and_gitreview_args.py +0 -0
  109. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_github_api_error_handling.py +0 -0
  110. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_github_api_helpers.py +0 -0
  111. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_github_api_retry_and_helpers.py +0 -0
  112. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_gitreview.py +0 -0
  113. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_gitutils_helpers.py +0 -0
  114. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_issue_157_regressions.py +0 -0
  115. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_mapping_comment_additional.py +0 -0
  116. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_mapping_comment_digest_and_backref.py +0 -0
  117. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_metadata_and_reconciliation.py +0 -0
  118. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_metadata_trailer_separation_bug.py +0 -0
  119. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_misc_small_coverage.py +0 -0
  120. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_netrc.py +0 -0
  121. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_orphan_rest_side_effects.py +0 -0
  122. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_pr_commands.py +0 -0
  123. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_pr_content_filter.py +0 -0
  124. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_pr_content_filter_integration.py +0 -0
  125. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_pr_update_detection.py +0 -0
  126. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_reconciliation_extracted_module.py +0 -0
  127. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_reconciliation_plan_and_orphans.py +0 -0
  128. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_reconciliation_scenarios.py +0 -0
  129. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_ssh_agent.py +0 -0
  130. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_ssh_agent_ownership.py +0 -0
  131. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_ssh_artifact_prevention.py +0 -0
  132. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_ssh_common.py +0 -0
  133. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_ssh_discovery.py +0 -0
  134. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_ssh_discovery_dry_run.py +0 -0
  135. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_trailers_additional.py +0 -0
  136. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_url_parser.py +0 -0
  137. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/test_utils.py +0 -0
  138. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/unit/test_config_integration.py +0 -0
  139. {github2gerrit-1.3.3 → github2gerrit-1.4.0}/tests/unit/test_ssh_config_parser.py +0 -0
@@ -59,7 +59,7 @@ repos:
59
59
  types: [yaml]
60
60
 
61
61
  - repo: https://github.com/astral-sh/ruff-pre-commit
62
- rev: 3b3f7c3f57fe9925356faf5fe6230835138be230 # frozen: v0.15.17
62
+ rev: c59bba8fb259db0fec2bbb77ad8ba51ea7341b56 # frozen: v0.15.20
63
63
  hooks:
64
64
  - id: ruff
65
65
  files: ^(src|scripts|tests)/.+\.py$
@@ -89,7 +89,7 @@ repos:
89
89
  - id: shellcheck
90
90
 
91
91
  - repo: https://github.com/igorshubovych/markdownlint-cli
92
- rev: e72a3ca1632f0b11a07d171449fe447a7ff6795e # frozen: v0.48.0
92
+ rev: a4d5d37e66ebcd6b3705204a1d6dbb56dea66338 # frozen: v0.49.0
93
93
  hooks:
94
94
  - id: markdownlint
95
95
  args: ["--fix", "--config", ".markdownlint.yaml"]
@@ -115,18 +115,18 @@ repos:
115
115
 
116
116
  # Requires a mirror, primary repo lacks .pre-commit-hooks.yaml
117
117
  - repo: https://github.com/DetachHead/basedpyright-prek-mirror
118
- rev: 5f6f2cb9fa8aec15105f77fd21e8dfe29838b16d # frozen: 1.39.8
118
+ rev: d55eabd2531b4f4a4c49c30fba627ce3a636ab79 # frozen: 1.39.9
119
119
  hooks:
120
120
  - id: basedpyright
121
121
  files: ^src/.+\.py$
122
122
 
123
123
  - repo: https://github.com/lfreleng-actions/gha-workflow-linter
124
- rev: 1a307fd9eed98268b11300ab86b1a107e1d3d1ae # frozen: v1.1.1
124
+ rev: 4c3079dcb6e9e3c295f961ce5bd5b8585db698ca # frozen: v1.2.2
125
125
  hooks:
126
126
  - id: gha-workflow-linter
127
127
 
128
128
  - repo: https://github.com/python-jsonschema/check-jsonschema
129
- rev: 8ef330cbb7204d388aa7a620f9549bcea8009663 # frozen: 0.37.3
129
+ rev: 1a4bb160cab6417b3045e1b37b6b72449243e658 # frozen: 0.37.4
130
130
  hooks:
131
131
  - id: check-github-actions
132
132
  - id: check-github-workflows
@@ -0,0 +1,386 @@
1
+ Metadata-Version: 2.4
2
+ Name: github2gerrit
3
+ Version: 1.4.0
4
+ Summary: Submit a GitHub pull request to a Gerrit repository.
5
+ Project-URL: Homepage, https://github.com/lfreleng-actions/github2gerrit-action
6
+ Project-URL: Repository, https://github.com/lfreleng-actions/github2gerrit-action
7
+ Project-URL: Issues, https://github.com/lfreleng-actions/github2gerrit-action/issues
8
+ Author-email: Matthew Watkins <mwatkins@linuxfoundation.org>
9
+ License-Expression: Apache-2.0
10
+ License-File: LICENSE
11
+ Keywords: actions,ci,cli,gerrit,github,typer
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development :: Build Tools
22
+ Classifier: Topic :: Software Development :: Version Control
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: click>=8.1.7
26
+ Requires-Dist: cryptography>=48.0.1
27
+ Requires-Dist: git-review>=2.5.0
28
+ Requires-Dist: pygerrit2>=2.0.15
29
+ Requires-Dist: pygithub>=2.8.1
30
+ Requires-Dist: pynacl>=1.6.2
31
+ Requires-Dist: pyyaml>=6.0.3
32
+ Requires-Dist: rich>=14.2.0
33
+ Requires-Dist: typer>=0.20.1
34
+ Requires-Dist: urllib3>=2.6.3
35
+ Provides-Extra: dev
36
+ Requires-Dist: coverage[toml]>=7.10.6; extra == 'dev'
37
+ Requires-Dist: mypy>=1.17.1; extra == 'dev'
38
+ Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
39
+ Requires-Dist: pytest-mock>=3.15.1; extra == 'dev'
40
+ Requires-Dist: pytest>=9.0.2; extra == 'dev'
41
+ Requires-Dist: responses>=0.25.8; extra == 'dev'
42
+ Requires-Dist: ruff>=0.6.3; extra == 'dev'
43
+ Requires-Dist: types-requests>=2.31.0; extra == 'dev'
44
+ Requires-Dist: types-urllib3>=1.26.25.14; extra == 'dev'
45
+ Description-Content-Type: text/markdown
46
+
47
+ <!--
48
+ SPDX-License-Identifier: Apache-2.0
49
+ SPDX-FileCopyrightText: 2025 The Linux Foundation
50
+ -->
51
+
52
+ # github2gerrit
53
+
54
+ Mirror GitHub pull requests into Gerrit changes.
55
+
56
+ github2gerrit serves projects where Gerrit is the source of truth and
57
+ GitHub hosts a read-only mirror. Automation tools such as Dependabot
58
+ raise pull requests against the GitHub mirror; this action translates
59
+ those pull requests into Gerrit changes, keeping the two systems in
60
+ sync across the entire lifecycle: creation, updates/rebases, metadata
61
+ edits, closure, and cleanup.
62
+
63
+ The implementation is a Python CLI tool (`github2gerrit`, published to
64
+ PyPI) wrapped in a GitHub composite action, plus a reusable workflow
65
+ for straightforward deployment in consuming repositories.
66
+
67
+ ## Goals and purpose
68
+
69
+ - Let Gerrit-based projects receive dependency updates (Dependabot)
70
+ and other automated changes raised against a GitHub mirror.
71
+ - Keep GitHub PRs and Gerrit changes synchronized in both directions:
72
+ PR updates become new patchsets, merged/abandoned changes close
73
+ their source PRs, and closed PRs abandon their Gerrit changes.
74
+ - Avoid duplicate Gerrit changes through Change-Id reuse and
75
+ reconciliation when automation rebases or re-raises PRs.
76
+
77
+ ## How it works
78
+
79
+ ```mermaid
80
+ flowchart TD
81
+ A[PR event on GitHub mirror] --> B[github2gerrit action]
82
+ B --> C{Operation mode}
83
+ C -->|opened| D[Create Gerrit change]
84
+ C -->|synchronize| E[New patchset on existing change]
85
+ C -->|edited| F[Sync PR metadata to Gerrit]
86
+ C -->|closed| G[Abandon Gerrit change]
87
+ D --> H[Comment Gerrit URL on PR]
88
+ E --> H
89
+ ```
90
+
91
+ In more detail, a run:
92
+
93
+ 1. Reads PR context and inputs; detects the operation mode
94
+ (CREATE, UPDATE, EDIT, CLOSE) from the triggering event.
95
+ 2. Reads `.gitreview` for the Gerrit host, port, and project
96
+ (or uses explicit `GERRIT_SERVER` / `GERRIT_PROJECT` inputs).
97
+ 3. Sets up git and SSH for Gerrit, derives missing credentials from
98
+ the organization name where possible.
99
+ 4. Prepares commits: squashed single commit (default), one-by-one
100
+ cherry-picks (`SUBMIT_SINGLE_COMMITS`), or PR title/body as the
101
+ commit message (`USE_PR_AS_COMMIT`). Reuses existing Change-Id
102
+ trailers on updates so pushes create new patchsets, not new
103
+ changes.
104
+ 5. Pushes to `refs/for/<branch>` with a Gerrit topic derived from the
105
+ project and PR number (prefix configurable via `G2G_TOPIC_PREFIX`,
106
+ default `GH`), queries Gerrit for the resulting URL/number/SHA, and
107
+ cross-links: a back-reference comment in Gerrit and the change
108
+ URL(s) on the PR.
109
+
110
+ See [docs/features.md](docs/features.md) for detailed feature
111
+ documentation: PR update handling, comment commands, duplicate
112
+ detection, reconciliation, cleanup, commit normalization,
113
+ configuration precedence, and credential derivation.
114
+
115
+ ## Quick start
116
+
117
+ ### Prerequisites
118
+
119
+ - A Gerrit account for the automation user, with SSH access and
120
+ permission to push to `refs/for/*` on the target project.
121
+ - The SSH private key stored as a repository or organization secret:
122
+ `GERRIT_SSH_PRIVKEY_G2G`.
123
+ - A `.gitreview` file in the repository (recommended). Without it,
124
+ pass `GERRIT_SERVER`, `GERRIT_SERVER_PORT`, and `GERRIT_PROJECT`
125
+ explicitly.
126
+ - Optional repository/organization variables: `GERRIT_KNOWN_HOSTS`,
127
+ `GERRIT_SSH_USER_G2G`, `GERRIT_SSH_USER_G2G_EMAIL`. The tool
128
+ derives missing values from the organization name and populates
129
+ known hosts automatically on first run.
130
+
131
+ ### Option A: reusable workflow (recommended)
132
+
133
+ Add a thin caller workflow to the consuming repository:
134
+
135
+ ```yaml
136
+ # .github/workflows/github2gerrit.yaml
137
+ name: github2gerrit
138
+
139
+ on:
140
+ pull_request_target:
141
+ types: [opened, reopened, edited, synchronize, closed]
142
+ push:
143
+ branches: [main, master]
144
+ workflow_dispatch:
145
+ inputs:
146
+ PR_NUMBER:
147
+ description: "PR number to process; 0 processes all open"
148
+ required: false
149
+ default: "0"
150
+ type: string
151
+
152
+ permissions: {}
153
+
154
+ jobs:
155
+ github2gerrit:
156
+ permissions:
157
+ contents: read
158
+ pull-requests: write
159
+ issues: write
160
+ # yamllint disable-line rule:line-length
161
+ uses: lfreleng-actions/github2gerrit-action/.github/workflows/github2gerrit.yaml@main
162
+ with:
163
+ GERRIT_KNOWN_HOSTS: ${{ vars.GERRIT_KNOWN_HOSTS }}
164
+ GERRIT_SSH_USER_G2G: ${{ vars.GERRIT_SSH_USER_G2G }}
165
+ GERRIT_SSH_USER_G2G_EMAIL: ${{ vars.GERRIT_SSH_USER_G2G_EMAIL }}
166
+ PR_NUMBER: ${{ inputs.PR_NUMBER || '0' }}
167
+ secrets:
168
+ GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
169
+ ```
170
+
171
+ The `push` trigger enables closing PRs whose Gerrit changes have
172
+ merged; `workflow_dispatch` enables manual processing. Repositories
173
+ using the Gerrit-side dispatch integration should also declare
174
+ `GERRIT_CHANGE_URL`, `GERRIT_EVENT_TYPE`, and `GERRIT_BRANCH` as
175
+ dispatch inputs and forward them the same way.
176
+
177
+ Pin `@main` to a release tag or commit SHA for production use.
178
+
179
+ ### Option B: composite action
180
+
181
+ Call the action directly for full control over all inputs:
182
+
183
+ ```yaml
184
+ name: github2gerrit
185
+
186
+ on:
187
+ pull_request_target:
188
+ types: [opened, reopened, edited, synchronize, closed]
189
+ workflow_dispatch:
190
+
191
+ permissions:
192
+ contents: read
193
+ pull-requests: write
194
+ issues: write
195
+
196
+ jobs:
197
+ submit-to-gerrit:
198
+ runs-on: ubuntu-latest
199
+ steps:
200
+ - name: Submit PR to Gerrit
201
+ id: g2g
202
+ uses: lfreleng-actions/github2gerrit-action@main
203
+ with:
204
+ GERRIT_KNOWN_HOSTS: ${{ vars.GERRIT_KNOWN_HOSTS }}
205
+ GERRIT_SSH_PRIVKEY_G2G: ${{ secrets.GERRIT_SSH_PRIVKEY_G2G }}
206
+ GERRIT_SSH_USER_G2G: ${{ vars.GERRIT_SSH_USER_G2G }}
207
+ GERRIT_SSH_USER_G2G_EMAIL: ${{ vars.GERRIT_SSH_USER_G2G_EMAIL }}
208
+ ```
209
+
210
+ ### Option C: command-line tool
211
+
212
+ The underlying Python CLI supports local and ad-hoc use (for example,
213
+ processing a single PR URL or bulk-processing a repository). This is
214
+ a secondary use case; see [docs/cli.md](docs/cli.md).
215
+
216
+ ```bash
217
+ uvx github2gerrit https://github.com/onap/portal-ng-bff/pull/33
218
+ ```
219
+
220
+ ## Action inputs
221
+
222
+ <!-- markdownlint-disable MD013 -->
223
+
224
+ | Input | Required | Default | Description |
225
+ | --------------------------- | -------- | ---------------- | -------------------------------------------------------------- |
226
+ | `GERRIT_SSH_PRIVKEY_G2G` | Yes | — | SSH private key content used to authenticate to Gerrit |
227
+ | `GERRIT_KNOWN_HOSTS` | No | — | Known hosts entries for Gerrit SSH (auto-populated when empty) |
228
+ | `GERRIT_SSH_USER_G2G` | No | `""` | Gerrit SSH username; derived when not supplied |
229
+ | `GERRIT_SSH_USER_G2G_EMAIL` | No | `""` | Gerrit user email address; derived when not supplied |
230
+ | `GERRIT_SERVER` | No | `""` | Gerrit server hostname; `.gitreview` preferred |
231
+ | `GERRIT_SERVER_PORT` | No | `"29418"` | Gerrit SSH port |
232
+ | `GERRIT_PROJECT` | No | `""` | Gerrit project name; `.gitreview` preferred |
233
+ | `GERRIT_HTTP_BASE_PATH` | No | `""` | HTTP base path for Gerrit REST API (e.g. `/r`) |
234
+ | `GERRIT_HTTP_USER` | No | `""` | Gerrit HTTP user for REST queries |
235
+ | `GERRIT_HTTP_PASSWORD` | No | `""` | Gerrit HTTP password/token for REST queries |
236
+ | `ORGANIZATION` | No | repository owner | GitHub organization/owner used for credential derivation |
237
+ | `PR_NUMBER` | No | `"0"` | PR number to process; `0` processes all open PRs (dispatch) |
238
+ | `FETCH_DEPTH` | No | `"10"` | Fetch depth for checkout |
239
+ | `SUBMIT_SINGLE_COMMITS` | No | `"false"` | Submit one commit at a time to Gerrit |
240
+ | `USE_PR_AS_COMMIT` | No | `"false"` | Use PR title and body as the commit message |
241
+ | `PRESERVE_GITHUB_PRS` | No | `"true"` | Do not close GitHub PRs after pushing to Gerrit |
242
+ | `CLOSE_MERGED_PRS` | No | `"true"` | Close GitHub PRs when their Gerrit change merges |
243
+ | `CLEANUP_ABANDONED` | No | `"true"` | Close GitHub PRs for abandoned Gerrit changes |
244
+ | `CLEANUP_GERRIT` | No | `"true"` | Abandon Gerrit changes when their GitHub PR closes |
245
+ | `CREATE_MISSING` | No | `"false"` | Create a new change when UPDATE finds no existing change |
246
+ | `ALLOW_DUPLICATES` | No | `"true"` | Allow submitting duplicate changes without error |
247
+ | `DUPLICATE_TYPES` | No | `"open"` | Comma-separated Gerrit states checked for duplicates |
248
+ | `AUTOMATION_ONLY` | No | `"true"` | Accept PRs from known automation tools only |
249
+ | `NORMALISE_COMMIT` | No | `"false"` | Normalize commit messages to conventional commit format |
250
+ | `COMMIT_RULES_JSON` | No | `""` | JSON commit message validation rules (see docs) |
251
+ | `ISSUE_ID` | No | `""` | Issue ID trailer to include (e.g. `ABC-123`) |
252
+ | `ISSUE_ID_LOOKUP_JSON` | No | `"[]"` | JSON array mapping GitHub actors to Issue IDs |
253
+ | `REVIEWERS_EMAIL` | No | `""` | Comma-separated reviewer emails |
254
+ | `DRY_RUN` | No | `"false"` | Check settings and PR metadata; do not write to Gerrit |
255
+ | `FORCE` | No | `"false"` | Force PR closure regardless of Gerrit change status |
256
+ | `G2G_USE_SSH_AGENT` | No | `"true"` | Use SSH agent instead of file-based keys |
257
+ | `G2G_NO_GERRIT` | No | `"false"` | Run the pipeline without contacting Gerrit (forces dry-run) |
258
+ | `G2G_DISABLED` | No | `""` | Kill switch: skip all processing when `true` |
259
+ | `ALLOW_GHE_URLS` | No | `"false"` | Allow GitHub Enterprise URLs in direct URL mode |
260
+ | `VERBOSE` | No | `"false"` | Verbose output (sets log level to DEBUG) |
261
+ | `CI_TESTING` | No | `"false"` | CI testing mode; overrides `.gitreview` |
262
+ | `USE_LOCAL_ACTION` | No | `"false"` | Use local repository code instead of the PyPI package |
263
+
264
+ <!-- markdownlint-enable MD013 -->
265
+
266
+ Every input maps to an environment variable of the same name
267
+ (`VERBOSE` maps to `G2G_VERBOSE`), and most have matching CLI
268
+ flags. Reconciliation tuning (`SIMILARITY_SUBJECT`,
269
+ `SIMILARITY_UPDATE_FACTOR`, `SIMILARITY_FILES`, `REUSE_STRATEGY`) is
270
+ available through environment variables and CLI flags only; set these
271
+ via `env:` on the action step when needed. See
272
+ [docs/cli.md](docs/cli.md) for the full option reference and
273
+ [docs/features.md](docs/features.md) for feature-specific settings.
274
+
275
+ ## Action outputs
276
+
277
+ <!-- markdownlint-disable MD013 -->
278
+
279
+ | Output | Description |
280
+ | --------------------------- | ------------------------------------------ |
281
+ | `gerrit_change_request_url` | Gerrit change URL(s), newline-separated |
282
+ | `gerrit_change_request_num` | Gerrit change number(s), newline-separated |
283
+ | `gerrit_commit_sha` | Patch set commit SHA(s), newline-separated |
284
+
285
+ <!-- markdownlint-enable MD013 -->
286
+
287
+ Access outputs in later steps with
288
+ `${{ steps.<step-id>.outputs.<output-name> }}`. The reusable workflow
289
+ re-exports all three outputs to callers.
290
+
291
+ ## Reusable workflow interface
292
+
293
+ The reusable workflow (`.github/workflows/github2gerrit.yaml`) wraps
294
+ the composite action for `workflow_call`, supporting caller triggers
295
+ `pull_request_target`, `push` (close PRs for merged Gerrit changes),
296
+ and `workflow_dispatch` (manual runs and Gerrit-event dispatches).
297
+ Input defaults match the composite action defaults.
298
+
299
+ <!-- markdownlint-disable MD013 -->
300
+
301
+ | Input | Type | Default | Description |
302
+ | --------------------------- | ------- | ---------------- | ------------------------------------------------ |
303
+ | `GERRIT_KNOWN_HOSTS` | string | `""` | Known hosts entries for Gerrit SSH |
304
+ | `GERRIT_SSH_USER_G2G` | string | `""` | Gerrit SSH username |
305
+ | `GERRIT_SSH_USER_G2G_EMAIL` | string | `""` | Gerrit user email address |
306
+ | `GERRIT_SERVER` | string | `""` | Gerrit server hostname |
307
+ | `GERRIT_SERVER_PORT` | string | `"29418"` | Gerrit SSH port |
308
+ | `GERRIT_PROJECT` | string | `""` | Gerrit project name |
309
+ | `GERRIT_HTTP_BASE_PATH` | string | `""` | HTTP base path for Gerrit REST |
310
+ | `GERRIT_HTTP_USER` | string | `""` | Gerrit HTTP user for REST queries |
311
+ | `GERRIT_HTTP_PASSWORD` | string | `""` | Gerrit HTTP password/token for REST queries |
312
+ | `G2G_USE_SSH_AGENT` | boolean | `true` | Use SSH agent instead of file-based keys |
313
+ | `ORGANIZATION` | string | repository owner | GitHub organization/owner |
314
+ | `PR_NUMBER` | string | `"0"` | PR to process on dispatch; `0` processes all |
315
+ | `FETCH_DEPTH` | string | `"10"` | Fetch depth for checkout |
316
+ | `SUBMIT_SINGLE_COMMITS` | boolean | `false` | Submit one commit at a time |
317
+ | `USE_PR_AS_COMMIT` | boolean | `false` | Use PR title and body as the commit message |
318
+ | `PRESERVE_GITHUB_PRS` | boolean | `true` | Do not close GitHub PRs after pushing |
319
+ | `CLOSE_MERGED_PRS` | boolean | `true` | Close GitHub PRs when their Gerrit change merges |
320
+ | `CLEANUP_ABANDONED` | boolean | `true` | Close GitHub PRs for abandoned Gerrit changes |
321
+ | `CLEANUP_GERRIT` | boolean | `true` | Abandon Gerrit changes when their PR closes |
322
+ | `CREATE_MISSING` | boolean | `false` | Create a change when UPDATE finds none |
323
+ | `AUTOMATION_ONLY` | boolean | `true` | Accept PRs from known automation tools only |
324
+ | `NORMALISE_COMMIT` | boolean | `false` | Normalize commit messages |
325
+ | `COMMIT_RULES_JSON` | string | `""` | JSON commit message validation rules |
326
+ | `ALLOW_DUPLICATES` | boolean | `true` | Allow submitting duplicate changes |
327
+ | `DUPLICATE_TYPES` | string | `"open"` | Gerrit states checked for duplicates |
328
+ | `FORCE` | boolean | `false` | Force PR closure regardless of change status |
329
+ | `VERBOSE` | boolean | `false` | Verbose output (DEBUG log level) |
330
+ | `ALLOW_GHE_URLS` | boolean | `false` | Allow GitHub Enterprise URLs |
331
+ | `DRY_RUN` | boolean | `false` | Check only; do not write to Gerrit |
332
+ | `ISSUE_ID` | string | `""` | Issue ID trailer to include |
333
+ | `ISSUE_ID_LOOKUP_JSON` | string | `"[]"` | JSON array mapping GitHub actors to Issue IDs |
334
+ | `REVIEWERS_EMAIL` | string | `""` | Comma-separated reviewer emails |
335
+ | `GERRIT_CHANGE_URL` | string | `""` | Gerrit change URL from a Gerrit event dispatch¹ |
336
+ | `GERRIT_EVENT_TYPE` | string | `""` | Gerrit event type (e.g. `change-merged`)¹ |
337
+ | `GERRIT_BRANCH` | string | `""` | Target branch override (Gerrit event dispatch)¹ |
338
+
339
+ | Secret | Required | Description |
340
+ | ------------------------ | -------- | ---------------------------------------------- |
341
+ | `GERRIT_SSH_PRIVKEY_G2G` | Yes | SSH private key for the Gerrit automation user |
342
+
343
+ | Output | Description |
344
+ | --------------------------- | ------------------------------------------ |
345
+ | `gerrit_change_request_url` | Gerrit change URL(s), newline-separated |
346
+ | `gerrit_change_request_num` | Gerrit change number(s), newline-separated |
347
+ | `gerrit_commit_sha` | Patch set commit SHA(s), newline-separated |
348
+
349
+ <!-- markdownlint-enable MD013 -->
350
+
351
+ ¹ Gerrit → GitHub reverse flow: when Gerrit-side automation
352
+ dispatches the caller workflow to report a merged or abandoned
353
+ change, forward these dispatch inputs and the tool closes the source
354
+ GitHub PR instead of processing pull requests.
355
+
356
+ Setting the repository variable `G2G_NO_GERRIT` to `true` makes runs
357
+ skip Gerrit interaction. Test-only settings (`CI_TESTING`,
358
+ `USE_LOCAL_ACTION`) remain composite-action-only by design.
359
+
360
+ ## Documentation
361
+
362
+ <!-- markdownlint-disable MD013 -->
363
+
364
+ | Document | Contents |
365
+ | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
366
+ | [docs/features.md](docs/features.md) | Feature reference: PR updates, comment commands, cleanup, duplicate detection, reconciliation, normalization, configuration |
367
+ | [docs/cli.md](docs/cli.md) | CLI installation, options, environment variables, exit codes, debugging |
368
+ | [docs/COMMIT_RULES.md](docs/COMMIT_RULES.md) | Commit message validation rules and `COMMIT_RULES_JSON` format |
369
+ | [docs/development.md](docs/development.md) | Contributor guide: local setup, testing, composite action test suite |
370
+
371
+ <!-- markdownlint-enable MD013 -->
372
+
373
+ ## Security notes
374
+
375
+ - Do not hardcode secrets or keys. Provide the private key through
376
+ workflow secrets and known hosts through repository or organization
377
+ variables.
378
+ - SSH handling is non-invasive: the tool creates temporary SSH files
379
+ in the workspace without modifying user SSH configuration or keys,
380
+ and cleans them up after execution.
381
+ - SSH connections use `IdentitiesOnly=yes` to avoid unintended key
382
+ usage (e.g. signing keys requiring biometric authentication).
383
+
384
+ ## License
385
+
386
+ Apache License 2.0. See [LICENSE](LICENSE).