github2gerrit 1.0.8__tar.gz → 1.1.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 (129) hide show
  1. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/.pre-commit-config.yaml +3 -3
  2. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/PKG-INFO +8 -3
  3. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/README.md +7 -1
  4. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/action.yaml +23 -9
  5. github2gerrit-1.1.0/docs/COMMIT_RULES.md +255 -0
  6. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/pyproject.toml +0 -2
  7. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/cli.py +123 -31
  8. github2gerrit-1.1.0/src/github2gerrit/commit_rules.py +518 -0
  9. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/config.py +44 -3
  10. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/core.py +273 -183
  11. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/duplicate_detection.py +26 -60
  12. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/error_codes.py +15 -11
  13. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/gerrit_pr_closer.py +13 -10
  14. github2gerrit-1.1.0/src/github2gerrit/gitreview.py +592 -0
  15. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/models.py +1 -0
  16. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/orchestrator/reconciliation.py +6 -12
  17. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/rich_display.py +8 -9
  18. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/rich_logging.py +2 -7
  19. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/ssh_discovery.py +12 -12
  20. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/conftest.py +4 -2
  21. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_change_id_deduplication.py +1 -0
  22. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_cli.py +9 -0
  23. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_cli_outputs_file.py +5 -0
  24. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_cli_url_and_dryrun.py +3 -0
  25. github2gerrit-1.1.0/tests/test_commit_rules.py +1029 -0
  26. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_core_config_and_errors.py +2 -1
  27. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_core_integration_fixture_repo.py +10 -2
  28. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_core_prepare_commits.py +1 -0
  29. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_core_ssh_setup.py +5 -0
  30. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_core_ssrf_protection.py +32 -12
  31. github2gerrit-1.1.0/tests/test_dns_validation_and_no_gerrit.py +475 -0
  32. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_force_flag_cli.py +1 -0
  33. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_gerrit_change_id_footer.py +1 -0
  34. github2gerrit-1.1.0/tests/test_gitreview.py +1011 -0
  35. github2gerrit-1.1.0/tests/test_issue_157_regressions.py +512 -0
  36. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_metadata_trailer_separation_bug.py +1 -0
  37. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_pr_commands.py +3 -0
  38. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_pr_content_filter_integration.py +1 -0
  39. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_pr_update_detection.py +2 -0
  40. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/uv.lock +24 -35
  41. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/.editorconfig +0 -0
  42. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/.gitignore +0 -0
  43. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/.gitlint +0 -0
  44. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/.markdownlint.yaml +0 -0
  45. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/.readthedocs.yml +0 -0
  46. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/.yamllint +0 -0
  47. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/LICENSE +0 -0
  48. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/LICENSES/Apache-2.0.txt +0 -0
  49. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/REUSE.toml +0 -0
  50. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/docs/COMPOSITE_ACTION_TESTING.md +0 -0
  51. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/docs/PR_UPDATE_IMPLEMENTATION.md +0 -0
  52. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/docs/RELEASE-v0.2.0.md +0 -0
  53. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/docs/github2gerrit_token_permissions_classic.png +0 -0
  54. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/sitecustomize.py +0 -0
  55. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/__init__.py +0 -0
  56. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/commit_normalization.py +0 -0
  57. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/constants.py +0 -0
  58. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/external_api.py +0 -0
  59. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/gerrit_query.py +0 -0
  60. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/gerrit_rest.py +0 -0
  61. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/gerrit_urls.py +0 -0
  62. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/github_api.py +0 -0
  63. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/gitutils.py +0 -0
  64. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/mapping_comment.py +0 -0
  65. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/netrc.py +0 -0
  66. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/orchestrator/__init__.py +0 -0
  67. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/pr_commands.py +0 -0
  68. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/pr_content_filter.py +0 -0
  69. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/reconcile_matcher.py +0 -0
  70. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/similarity.py +0 -0
  71. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/ssh_agent_setup.py +0 -0
  72. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/ssh_common.py +0 -0
  73. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/ssh_config_parser.py +0 -0
  74. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/trailers.py +0 -0
  75. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/src/github2gerrit/utils.py +0 -0
  76. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/fixtures/__init__.py +0 -0
  77. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/fixtures/make_repo.py +0 -0
  78. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/fixtures/ssh_config_samples.py +0 -0
  79. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_action_environment_mapping.py +0 -0
  80. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_action_outputs.py +0 -0
  81. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_action_pr_number_handling.py +0 -0
  82. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_action_step_validation.py +0 -0
  83. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_automation_only.py +0 -0
  84. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_cli_helpers.py +0 -0
  85. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_cli_netrc_options.py +0 -0
  86. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_commit_normalization.py +0 -0
  87. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_composite_action_coverage.py +0 -0
  88. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_config_and_reviewers.py +0 -0
  89. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_config_helpers.py +0 -0
  90. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_core_close_pr_policy.py +0 -0
  91. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_core_gerrit_backref_comment.py +0 -0
  92. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_core_gerrit_push_errors.py +0 -0
  93. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_core_gerrit_rest_results.py +0 -0
  94. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_core_shallow_clone.py +0 -0
  95. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_duplicate_detection.py +0 -0
  96. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_email_case_normalization.py +0 -0
  97. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_error_codes.py +0 -0
  98. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_external_api_framework.py +0 -0
  99. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_gerrit_change_status_checks.py +0 -0
  100. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_gerrit_pr_closer.py +0 -0
  101. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_gerrit_rest_client.py +0 -0
  102. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_gerrit_urls.py +0 -0
  103. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_gerrit_urls_more.py +0 -0
  104. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_ghe_and_gitreview_args.py +0 -0
  105. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_github_api_error_handling.py +0 -0
  106. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_github_api_helpers.py +0 -0
  107. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_github_api_retry_and_helpers.py +0 -0
  108. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_gitutils_helpers.py +0 -0
  109. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_mapping_comment_additional.py +0 -0
  110. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_mapping_comment_digest_and_backref.py +0 -0
  111. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_metadata_and_reconciliation.py +0 -0
  112. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_misc_small_coverage.py +0 -0
  113. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_netrc.py +0 -0
  114. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_orphan_rest_side_effects.py +0 -0
  115. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_pr_content_filter.py +0 -0
  116. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_reconciliation_extracted_module.py +0 -0
  117. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_reconciliation_plan_and_orphans.py +0 -0
  118. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_reconciliation_scenarios.py +0 -0
  119. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_ssh_agent.py +0 -0
  120. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_ssh_agent_ownership.py +0 -0
  121. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_ssh_artifact_prevention.py +0 -0
  122. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_ssh_common.py +0 -0
  123. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_ssh_discovery.py +0 -0
  124. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_ssh_discovery_dry_run.py +0 -0
  125. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_trailers_additional.py +0 -0
  126. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_url_parser.py +0 -0
  127. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/test_utils.py +0 -0
  128. {github2gerrit-1.0.8 → github2gerrit-1.1.0}/tests/unit/test_config_integration.py +0 -0
  129. {github2gerrit-1.0.8 → github2gerrit-1.1.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: a27a2e47c7751b639d2b5badf0ef6ff11fee893f # frozen: v0.15.4
62
+ rev: b969e2851312ca2b24bbec879ba4954341d1bd12 # frozen: v0.15.5
63
63
  hooks:
64
64
  - id: ruff
65
65
  files: ^(src|scripts|tests)/.+\.py$
@@ -96,7 +96,7 @@ repos:
96
96
  - id: shellcheck
97
97
 
98
98
  - repo: https://github.com/igorshubovych/markdownlint-cli
99
- rev: 76b3d32d3f4b965e1d6425253c59407420ae2c43 # frozen: v0.47.0
99
+ rev: e72a3ca1632f0b11a07d171449fe447a7ff6795e # frozen: v0.48.0
100
100
  hooks:
101
101
  - id: markdownlint
102
102
  args: ["--fix", "--config", ".markdownlint.yaml"]
@@ -116,7 +116,7 @@ repos:
116
116
 
117
117
  # Check for misspellings in documentation files
118
118
  - repo: https://github.com/codespell-project/codespell
119
- rev: 63c8f8312b7559622c0d82815639671ae42132ac # frozen: v2.4.1
119
+ rev: 2ccb47ff45ad361a21071a7eedda4c37e6ae8c5a # frozen: v2.4.2
120
120
  hooks:
121
121
  - id: codespell
122
122
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github2gerrit
3
- Version: 1.0.8
3
+ Version: 1.1.0
4
4
  Summary: Submit a GitHub pull request to a Gerrit repository.
5
5
  Project-URL: Homepage, https://github.com/lfreleng-actions/github2gerrit-action
6
6
  Project-URL: Repository, https://github.com/lfreleng-actions/github2gerrit-action
@@ -39,7 +39,6 @@ Requires-Dist: pytest-mock>=3.15.1; extra == 'dev'
39
39
  Requires-Dist: pytest>=9.0.2; extra == 'dev'
40
40
  Requires-Dist: responses>=0.25.8; extra == 'dev'
41
41
  Requires-Dist: ruff>=0.6.3; extra == 'dev'
42
- Requires-Dist: types-click>=7.1.8; extra == 'dev'
43
42
  Requires-Dist: types-requests>=2.31.0; extra == 'dev'
44
43
  Requires-Dist: types-urllib3>=1.26.25.14; extra == 'dev'
45
44
  Description-Content-Type: text/markdown
@@ -1637,7 +1636,9 @@ requiring manual configuration per PR or user.
1637
1636
  - `src/github2gerrit/gitutils.py` (subprocess and git helpers)
1638
1637
  - Linting and type checking
1639
1638
  - Ruff and MyPy use settings in `pyproject.toml`.
1640
- - Run from pre‑commit hooks and CI.
1639
+ - Run from [prek](https://github.com/j178/prek) hooks and CI.
1640
+ - prek is a faster, Rust-based drop-in replacement for pre-commit
1641
+ that reads the existing `.pre-commit-config.yaml` unchanged.
1641
1642
  - Tests
1642
1643
  - Pytest with coverage targets around 80%.
1643
1644
  - Add unit and integration tests for each feature.
@@ -1647,6 +1648,10 @@ requiring manual configuration per PR or user.
1647
1648
  - Install `uv` and run:
1648
1649
  - `uv pip install --system .`
1649
1650
  - `uv run github2gerrit --help`
1651
+ - Install prek hooks:
1652
+ - `uv tool install prek && prek install -f`
1653
+ - Run all checks (including tests) manually:
1654
+ - `prek run --all-files`
1650
1655
  - Run tests:
1651
1656
  - `uv run pytest -q`
1652
1657
  - Lint and type check:
@@ -1591,7 +1591,9 @@ requiring manual configuration per PR or user.
1591
1591
  - `src/github2gerrit/gitutils.py` (subprocess and git helpers)
1592
1592
  - Linting and type checking
1593
1593
  - Ruff and MyPy use settings in `pyproject.toml`.
1594
- - Run from pre‑commit hooks and CI.
1594
+ - Run from [prek](https://github.com/j178/prek) hooks and CI.
1595
+ - prek is a faster, Rust-based drop-in replacement for pre-commit
1596
+ that reads the existing `.pre-commit-config.yaml` unchanged.
1595
1597
  - Tests
1596
1598
  - Pytest with coverage targets around 80%.
1597
1599
  - Add unit and integration tests for each feature.
@@ -1601,6 +1603,10 @@ requiring manual configuration per PR or user.
1601
1603
  - Install `uv` and run:
1602
1604
  - `uv pip install --system .`
1603
1605
  - `uv run github2gerrit --help`
1606
+ - Install prek hooks:
1607
+ - `uv tool install prek && prek install -f`
1608
+ - Run all checks (including tests) manually:
1609
+ - `prek run --all-files`
1604
1610
  - Run tests:
1605
1611
  - `uv run pytest -q`
1606
1612
  - Lint and type check:
@@ -69,6 +69,10 @@ inputs:
69
69
  description: "Enable CI testing mode; overrides .gitreview, creates orphan commits"
70
70
  required: false
71
71
  default: "false"
72
+ G2G_NO_GERRIT:
73
+ description: "Run full pipeline without contacting Gerrit (forces DRY_RUN, suppresses cleanup)"
74
+ required: false
75
+ default: "false"
72
76
  FORCE:
73
77
  description: "Force PR closure regardless of Gerrit change status (abandoned, etc)"
74
78
  required: false
@@ -129,6 +133,14 @@ inputs:
129
133
  (format: [{"key": "username", "value": "ISSUE-ID"}])
130
134
  required: false
131
135
  default: "[]"
136
+ COMMIT_RULES_JSON:
137
+ description: >-
138
+ JSON object defining commit message rules with per-project and
139
+ per-actor overrides. Supports arbitrary label-value pairs placed
140
+ in the commit body or trailer block.
141
+ (see: docs/COMMIT_RULES.md)
142
+ required: false
143
+ default: ""
132
144
  AUTOMATION_ONLY:
133
145
  description: "Only accept pull requests from known automation tools"
134
146
  required: false
@@ -160,6 +172,14 @@ outputs:
160
172
  runs:
161
173
  using: "composite"
162
174
  steps:
175
+ - name: "Checkout repository"
176
+ # yamllint disable-line rule:line-length
177
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
178
+ with:
179
+ fetch-depth: ${{ inputs.FETCH_DEPTH }}
180
+ # Ensure we are on the PR's head SHA when triggered by PR events
181
+ ref: ${{ github.event.pull_request.head.sha || github.sha }}
182
+
163
183
  - name: "Setup Python"
164
184
  # yamllint disable-line rule:line-length
165
185
  uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
@@ -168,18 +188,10 @@ runs:
168
188
 
169
189
  - name: "Setup uv"
170
190
  # yamllint disable-line rule:line-length
171
- uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
191
+ uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
172
192
  with:
173
193
  enable-cache: false
174
194
 
175
- - name: "Checkout repository"
176
- # yamllint disable-line rule:line-length
177
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
178
- with:
179
- fetch-depth: ${{ inputs.FETCH_DEPTH }}
180
- # Ensure we are on the PR's head SHA when triggered by PR events
181
- ref: ${{ github.event.pull_request.head.sha || github.sha }}
182
-
183
195
  - name: "Setup github2gerrit"
184
196
  shell: bash
185
197
  env:
@@ -294,6 +306,7 @@ runs:
294
306
  ALLOW_DUPLICATES: ${{ inputs.ALLOW_DUPLICATES }}
295
307
  ISSUE_ID: ${{ inputs.ISSUE_ID }}
296
308
  ISSUE_ID_LOOKUP_JSON: ${{ inputs.ISSUE_ID_LOOKUP_JSON }}
309
+ COMMIT_RULES_JSON: ${{ inputs.COMMIT_RULES_JSON }}
297
310
  CI_TESTING: ${{ inputs.CI_TESTING }}
298
311
  CLOSE_MERGED_PRS: ${{ inputs.CLOSE_MERGED_PRS }}
299
312
  FORCE: ${{ inputs.FORCE }}
@@ -329,6 +342,7 @@ runs:
329
342
  SYNC_ALL_OPEN_PRS: ${{ env.SYNC_ALL_OPEN_PRS }}
330
343
  PR_NUMBER: ${{ env.PR_NUMBER }}
331
344
  G2G_TEST_MODE: "false"
345
+ G2G_NO_GERRIT: ${{ inputs.G2G_NO_GERRIT }}
332
346
  run: |
333
347
  # Run github2gerrit Python CLI
334
348
  set -euo pipefail
@@ -0,0 +1,255 @@
1
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
2
+ <!-- SPDX-FileCopyrightText: 2025 The Linux Foundation -->
3
+
4
+ # Commit Rules (`COMMIT_RULES_JSON`)
5
+
6
+ The **commit rules** feature provides a flexible, JSON-driven mechanism for
7
+ injecting arbitrary lines into commit messages submitted to Gerrit. It
8
+ generalises the existing `ISSUE_ID` / `ISSUE_ID_LOOKUP_JSON` support to handle
9
+ per-project requirements such as FD.io VPP's mandatory `Type:` field.
10
+
11
+ ## Quick Start
12
+
13
+ Set the `COMMIT_RULES_JSON` GitHub Actions variable (organisation or
14
+ repository level) to a JSON object describing the rules:
15
+
16
+ ```yaml
17
+ # .github/workflows/g2g.yml
18
+ jobs:
19
+ submit:
20
+ steps:
21
+ - uses: lfreleng-actions/github2gerrit-action@main
22
+ with:
23
+ COMMIT_RULES_JSON: ${{ vars.COMMIT_RULES_JSON }}
24
+ # ... other inputs ...
25
+ ```
26
+
27
+ ## JSON Schema
28
+
29
+ The top-level object has three optional sections:
30
+
31
+ | Section | Type | Description |
32
+ |------------|-------------------------------|------------------------------------------------|
33
+ | `defaults` | `array` of rule objects | Baseline rules applied to every commit. |
34
+ | `projects` | `object` (project → rules[]) | Per-Gerrit-project overrides. |
35
+ | `actors` | `object` (actor → rules[]) | Per-GitHub-actor overrides (e.g. bots). |
36
+
37
+ ### Rule Object
38
+
39
+ Each rule object describes a single line to insert into the commit message:
40
+
41
+ | Field | Type | Required | Default | Description |
42
+ |-------------|----------|----------|----------------|----------------------------------------------------------------------------|
43
+ | `key` | `string` | Yes | — | The label name (e.g. `Type`, `Issue-ID`, `Ticket`). |
44
+ | `value` | `string` | Yes | — | The value to insert. |
45
+ | `location` | `string` | No | `"trailer"` | Where to place the line — `"trailer"` or `"body"`. |
46
+ | `separator` | `string` | No | `"blank_line"` | Separation style when `location` is `"body"` — `"blank_line"` or `"none"`. |
47
+
48
+ ### Locations
49
+
50
+ - **`trailer`** — places the line in the Git trailer block at the end of
51
+ the commit message, alongside `Change-Id`, `Signed-off-by`, etc.
52
+ - **`body`** — places the line in the commit body, before the trailer
53
+ block. Fields like VPP's `Type:` need this location because Gerrit
54
+ server-side hooks expect them in the body rather than the trailer section.
55
+
56
+ ### Separators (body location only)
57
+
58
+ - **`blank_line`** (default) — inserts a blank line before the new
59
+ content, matching the conventional VPP commit style.
60
+ - **`none`** — appends the line directly after the existing body text
61
+ without extra blank lines.
62
+
63
+ ## Resolution Precedence
64
+
65
+ The engine resolves rules in this order when building the commit message
66
+ (last writer wins for a given `key`):
67
+
68
+ 1. **`defaults`** — baseline rules for all projects and actors.
69
+ 2. **`projects[<gerrit_project>]`** — overrides defaults for the matching
70
+ Gerrit project (from `.gitreview` or `GERRIT_PROJECT`).
71
+ 3. **`actors[<github_actor>]`** — overrides everything for the matching
72
+ GitHub actor (from `GITHUB_ACTOR`).
73
+
74
+ The existing `ISSUE_ID` input always takes priority over any `Issue-ID`
75
+ rule from commit rules. Both mechanisms can coexist safely.
76
+
77
+ ## Examples
78
+
79
+ ### FD.io (VPP + CSIT on the same Gerrit server)
80
+
81
+ VPP requires a `Type:` field in the commit body; CSIT does not.
82
+ Both projects need `Issue-ID` in the trailer block.
83
+
84
+ ```json
85
+ {
86
+ "defaults": [
87
+ {
88
+ "key": "Issue-ID",
89
+ "value": "CIMAN-33",
90
+ "location": "trailer"
91
+ }
92
+ ],
93
+ "projects": {
94
+ "vpp": [
95
+ {
96
+ "key": "Type",
97
+ "value": "ci",
98
+ "location": "body",
99
+ "separator": "blank_line"
100
+ },
101
+ {
102
+ "key": "Issue-ID",
103
+ "value": "CIMAN-33",
104
+ "location": "trailer"
105
+ }
106
+ ],
107
+ "hicn": [
108
+ {
109
+ "key": "Type",
110
+ "value": "ci",
111
+ "location": "body",
112
+ "separator": "blank_line"
113
+ }
114
+ ]
115
+ },
116
+ "actors": {
117
+ "dependabot[bot]": [
118
+ {
119
+ "key": "Type",
120
+ "value": "ci",
121
+ "location": "body"
122
+ },
123
+ {
124
+ "key": "Issue-ID",
125
+ "value": "CIMAN-33",
126
+ "location": "trailer"
127
+ }
128
+ ],
129
+ "renovate[bot]": [
130
+ {
131
+ "key": "Issue-ID",
132
+ "value": "CIMAN-44",
133
+ "location": "trailer"
134
+ }
135
+ ]
136
+ }
137
+ }
138
+ ```
139
+
140
+ **Result for VPP + dependabot:**
141
+
142
+ ```text
143
+ gha: update actions/checkout from v3 to v4
144
+
145
+ Type: ci
146
+
147
+ Issue-ID: CIMAN-33
148
+ Change-Id: I1234567890abcdef...
149
+ Signed-off-by: dependabot[bot] <support@github.com>
150
+ ```
151
+
152
+ **Result for CSIT + human user:**
153
+
154
+ ```text
155
+ fix: correct test assertion
156
+
157
+ Issue-ID: CIMAN-33
158
+ Change-Id: I1234567890abcdef...
159
+ Signed-off-by: Jane Doe <jane@example.com>
160
+ ```
161
+
162
+ ### ONAP (Issue-ID only)
163
+
164
+ ONAP projects only need `Issue-ID` in the trailer:
165
+
166
+ ```json
167
+ {
168
+ "actors": {
169
+ "dependabot[bot]": [
170
+ {
171
+ "key": "Issue-ID",
172
+ "value": "CIMAN-33"
173
+ }
174
+ ]
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### Extra body fields
180
+
181
+ Some projects need more than one body field:
182
+
183
+ ```json
184
+ {
185
+ "projects": {
186
+ "vpp": [
187
+ {
188
+ "key": "Type",
189
+ "value": "ci",
190
+ "location": "body",
191
+ "separator": "blank_line"
192
+ },
193
+ {
194
+ "key": "Ticket",
195
+ "value": "VPP-2088",
196
+ "location": "body",
197
+ "separator": "none"
198
+ }
199
+ ]
200
+ }
201
+ }
202
+ ```
203
+
204
+ **Result:**
205
+
206
+ ```text
207
+ gha: update dependency versions
208
+
209
+ Type: ci
210
+ Ticket: VPP-2088
211
+
212
+ Change-Id: I1234567890abcdef...
213
+ Signed-off-by: bot <bot@example.com>
214
+ ```
215
+
216
+ ## CLI Usage
217
+
218
+ You can also pass the commit rules JSON via the command line:
219
+
220
+ ```bash
221
+ github2gerrit --commit-rules '{"defaults": [...]}' \
222
+ https://github.com/org/repo/pull/123
223
+ ```
224
+
225
+ Or via the environment variable:
226
+
227
+ ```bash
228
+ export COMMIT_RULES_JSON='{"defaults": [...]}'
229
+ github2gerrit https://github.com/org/repo/pull/123
230
+ ```
231
+
232
+ ## Interaction with ISSUE_ID / ISSUE_ID_LOOKUP_JSON
233
+
234
+ The existing `ISSUE_ID` and `ISSUE_ID_LOOKUP_JSON` inputs continue to
235
+ work unchanged. When both mechanisms specify an `Issue-ID`:
236
+
237
+ 1. An explicit `ISSUE_ID` input (or a value resolved from
238
+ `ISSUE_ID_LOOKUP_JSON`) **always wins**.
239
+ 2. If `ISSUE_ID` is empty, the engine applies the `Issue-ID` rule from
240
+ `COMMIT_RULES_JSON` instead.
241
+
242
+ This means you can safely enable `COMMIT_RULES_JSON` for an organisation
243
+ without breaking workflows that already set `ISSUE_ID` directly.
244
+
245
+ ## Validation and Error Handling
246
+
247
+ - Invalid JSON produces a warning but does **not** fail the workflow
248
+ (matching the existing `ISSUE_ID_LOOKUP_JSON` convention).
249
+ - Individual rule entries with missing or invalid `key`/`value` fields
250
+ produce a warning and the engine skips them; valid entries in the same
251
+ document still apply.
252
+ - Unknown `location` values default to `"trailer"` with a warning.
253
+ - Unknown `separator` values default to `"blank_line"` with a warning.
254
+ - Duplicate lines are automatically detected and skipped (both in body
255
+ and trailer locations).
@@ -102,7 +102,6 @@ dev = [
102
102
  # Type checking helpers
103
103
  "pytest-mock>=3.15.1",
104
104
  "types-requests>=2.31.0",
105
- "types-click>=7.1.8",
106
105
  "types-urllib3>=1.26.25.14",
107
106
  ]
108
107
 
@@ -230,7 +229,6 @@ directory = "coverage_html_report"
230
229
  minversion = "8.0"
231
230
  addopts = "-ra -q --cov=github2gerrit --cov-report=term-missing --cov-report=html"
232
231
  testpaths = ["tests"]
233
- asyncio_default_fixture_loop_scope = "function"
234
232
  markers = [
235
233
  "integration: marks tests as integration tests (deselect with '-m \"not integration\"')",
236
234
  ]