github2gerrit 2.2.1__tar.gz → 2.3.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 (152) hide show
  1. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/.pre-commit-config.yaml +32 -7
  2. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/PKG-INFO +17 -8
  3. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/README.md +16 -7
  4. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/action.yaml +3 -3
  5. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/docs/cli.md +2 -1
  6. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/docs/features.md +30 -5
  7. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/cli.py +232 -57
  8. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/config.py +211 -218
  9. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/config_ini.py +96 -4
  10. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/core.py +44 -16
  11. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/gitreview.py +8 -0
  12. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/pr_approval.py +52 -0
  13. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_action_environment_mapping.py +5 -2
  14. github2gerrit-2.3.0/tests/test_bulk_fan_out.py +964 -0
  15. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_cli_outputs_file.py +1 -0
  16. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_cli_url_and_dryrun.py +1 -0
  17. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_composite_action_coverage.py +2 -2
  18. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_config_helpers.py +293 -7
  19. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_core_integration_fixture_repo.py +88 -3
  20. github2gerrit-2.3.0/tests/test_fork_transfer_record.py +471 -0
  21. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_gitreview.py +3 -0
  22. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_pr_closed_handling.py +7 -3
  23. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_precommit_mypy_pins.py +11 -69
  24. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_project_names.py +3 -2
  25. github2gerrit-2.3.0/tests/test_sync_mypy_pins.py +310 -0
  26. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/uv.lock +19 -19
  27. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/.aislop/config.yml +0 -0
  28. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/.editorconfig +0 -0
  29. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/.gitignore +0 -0
  30. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/.gitlint +0 -0
  31. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/.markdownlint.yaml +0 -0
  32. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/.yamllint +0 -0
  33. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/LICENSE +0 -0
  34. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/LICENSES/Apache-2.0.txt +0 -0
  35. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/REUSE.toml +0 -0
  36. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/SECURITY.md +0 -0
  37. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/docs/COMMIT_RULES.md +0 -0
  38. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/docs/development.md +0 -0
  39. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/docs/github2gerrit_token_permissions_classic.png +0 -0
  40. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/pyproject.toml +0 -0
  41. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/sitecustomize.py +0 -0
  42. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/__init__.py +0 -0
  43. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/approvers.py +0 -0
  44. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/commit_normalization.py +0 -0
  45. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/commit_rules.py +0 -0
  46. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/constants.py +0 -0
  47. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/duplicate_detection.py +0 -0
  48. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/error_codes.py +0 -0
  49. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/external_api.py +0 -0
  50. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/gerrit_pr_closer.py +0 -0
  51. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/gerrit_query.py +0 -0
  52. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/gerrit_rest.py +0 -0
  53. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/gerrit_ssh.py +0 -0
  54. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/gerrit_urls.py +0 -0
  55. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/github_api.py +0 -0
  56. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/gitutils.py +0 -0
  57. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/mapping_comment.py +0 -0
  58. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/models.py +0 -0
  59. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/netrc.py +0 -0
  60. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/orchestrator/__init__.py +0 -0
  61. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/orchestrator/reconciliation.py +0 -0
  62. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/pr_commands.py +0 -0
  63. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/pr_content_filter.py +0 -0
  64. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/pr_directives.py +0 -0
  65. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/project_names.py +0 -0
  66. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/reconcile_matcher.py +0 -0
  67. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/rich_display.py +0 -0
  68. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/rich_logging.py +0 -0
  69. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/similarity.py +0 -0
  70. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/ssh_agent_setup.py +0 -0
  71. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/ssh_common.py +0 -0
  72. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/ssh_config_parser.py +0 -0
  73. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/ssh_discovery.py +0 -0
  74. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/trailers.py +0 -0
  75. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/trust.py +0 -0
  76. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/src/github2gerrit/utils.py +0 -0
  77. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/conftest.py +0 -0
  78. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/fixtures/__init__.py +0 -0
  79. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/fixtures/make_repo.py +0 -0
  80. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/fixtures/ssh_config_samples.py +0 -0
  81. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_action_outputs.py +0 -0
  82. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_action_pr_number_handling.py +0 -0
  83. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_action_step_validation.py +0 -0
  84. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_approver_sources.py +0 -0
  85. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_automation_only.py +0 -0
  86. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_cache_isolation.py +0 -0
  87. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_change_id_deduplication.py +0 -0
  88. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_clean_squash_title.py +0 -0
  89. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_cli.py +0 -0
  90. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_cli_helpers.py +0 -0
  91. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_cli_netrc_options.py +0 -0
  92. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_commit_normalization.py +0 -0
  93. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_commit_rules.py +0 -0
  94. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_config_and_reviewers.py +0 -0
  95. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_core_close_pr_policy.py +0 -0
  96. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_core_config_and_errors.py +0 -0
  97. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_core_gerrit_backref_comment.py +0 -0
  98. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_core_gerrit_push_errors.py +0 -0
  99. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_core_gerrit_rest_results.py +0 -0
  100. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_core_prepare_commits.py +0 -0
  101. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_core_shallow_clone.py +0 -0
  102. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_core_ssh_setup.py +0 -0
  103. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_core_ssrf_protection.py +0 -0
  104. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_dependency_supersession.py +0 -0
  105. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_dns_validation_and_no_gerrit.py +0 -0
  106. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_duplicate_detection.py +0 -0
  107. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_email_case_normalization.py +0 -0
  108. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_error_codes.py +0 -0
  109. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_external_api_framework.py +0 -0
  110. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_final_state_reconciliation.py +0 -0
  111. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_force_flag_cli.py +0 -0
  112. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_fork_approval_gate.py +0 -0
  113. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_fork_pr_hardening.py +0 -0
  114. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_gerrit_change_id_footer.py +0 -0
  115. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_gerrit_change_status_checks.py +0 -0
  116. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_gerrit_pr_closer.py +0 -0
  117. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_gerrit_rest_client.py +0 -0
  118. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_gerrit_ssh_abandon.py +0 -0
  119. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_gerrit_urls.py +0 -0
  120. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_gerrit_urls_more.py +0 -0
  121. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_ghe_and_gitreview_args.py +0 -0
  122. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_github_api_error_handling.py +0 -0
  123. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_github_api_helpers.py +0 -0
  124. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_github_api_retry_and_helpers.py +0 -0
  125. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_gitutils_helpers.py +0 -0
  126. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_issue_157_regressions.py +0 -0
  127. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_mapping_comment_additional.py +0 -0
  128. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_mapping_comment_digest_and_backref.py +0 -0
  129. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_metadata_and_reconciliation.py +0 -0
  130. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_metadata_trailer_separation_bug.py +0 -0
  131. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_misc_small_coverage.py +0 -0
  132. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_netrc.py +0 -0
  133. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_orphan_rest_side_effects.py +0 -0
  134. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_pr_command_authorisation.py +0 -0
  135. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_pr_commands.py +0 -0
  136. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_pr_content_filter.py +0 -0
  137. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_pr_content_filter_integration.py +0 -0
  138. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_pr_update_detection.py +0 -0
  139. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_reconciliation_extracted_module.py +0 -0
  140. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_reconciliation_plan_and_orphans.py +0 -0
  141. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_reconciliation_scenarios.py +0 -0
  142. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_ssh_agent.py +0 -0
  143. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_ssh_agent_ownership.py +0 -0
  144. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_ssh_artifact_prevention.py +0 -0
  145. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_ssh_common.py +0 -0
  146. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_ssh_discovery.py +0 -0
  147. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_ssh_discovery_dry_run.py +0 -0
  148. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_trailers_additional.py +0 -0
  149. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_url_parser.py +0 -0
  150. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/test_utils.py +0 -0
  151. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/unit/test_config_integration.py +0 -0
  152. {github2gerrit-2.2.1 → github2gerrit-2.3.0}/tests/unit/test_ssh_config_parser.py +0 -0
@@ -64,7 +64,7 @@ repos:
64
64
  types: [yaml]
65
65
 
66
66
  - repo: https://github.com/astral-sh/ruff-pre-commit
67
- rev: e8f7d69b957a30acb2c875078d5fd012de24b64c # frozen: v0.16.7
67
+ rev: 2eeb5678de71a00c0902cbda7105d328432f72cb # frozen: v0.16.8
68
68
  hooks:
69
69
  - id: ruff
70
70
  files: ^(src|scripts|tests)/.+\.py$|^sitecustomize\.py$
@@ -72,6 +72,24 @@ repos:
72
72
  - id: ruff-format
73
73
  files: ^(src|scripts|tests)/.+\.py$|^sitecustomize\.py$
74
74
 
75
+ - repo: local
76
+ hooks:
77
+ - id: sync-mypy-pins
78
+ # Rewrites the mypy hook's exact pins below to the versions
79
+ # uv.lock records, so the two cannot drift. Ordered ahead of the
80
+ # mypy hook so the pins are corrected before mypy is reached,
81
+ # though pre-commit reads this file and builds hook environments
82
+ # before any hook runs: a rewrite fails this run, as any
83
+ # modifying hook does, and the corrected pins take effect on the
84
+ # rerun. Both files come from the same checkout, so the verdict
85
+ # is the same locally and in CI, and a Dependabot lockfile bump
86
+ # fails here on its own pull request rather than on main.
87
+ name: sync mypy hook pins with uv.lock
88
+ entry: python3 scripts/sync_mypy_pins.py
89
+ language: system
90
+ files: ^(\.pre-commit-config\.yaml|uv\.lock)$
91
+ pass_filenames: false
92
+
75
93
  - repo: https://github.com/pre-commit/mirrors-mypy
76
94
  rev: 7ff8d35ae36a7d2b968f2f90b4c723e292e594ee # frozen: v2.3.1
77
95
  hooks:
@@ -100,10 +118,16 @@ repos:
100
118
  # nobody runs locally. That drift is not theoretical: CI once
101
119
  # resolved typer 0.27.2 against a lockfile holding 0.27.1, and the
102
120
  # two disagreed about which module typer.Exit lives in.
103
- # Every version here must equal the one uv.lock records for that
104
- # package, so update both together (after `uv lock --upgrade`, for
105
- # instance). tests/test_precommit_mypy_pins.py compares the two
106
- # files and fails if they diverge in either direction.
121
+ # The versions are not maintained by hand: the sync-mypy-pins hook
122
+ # above rewrites them from uv.lock, so after `uv lock --upgrade` a
123
+ # `prek run sync-mypy-pins --all-files` brings them into step
124
+ # (--all-files, because neither file is staged at that point and
125
+ # the hook would otherwise not be selected). The tests in
126
+ # tests/test_precommit_mypy_pins.py check the list is exact and
127
+ # complete against the imports; they deliberately do not compare
128
+ # versions to the lockfile, since a pull request is tested as
129
+ # merged into main and would otherwise fail for a dependency that
130
+ # moved there, not for anything on the branch.
107
131
  #
108
132
  # These pins do not freeze the whole resolved closure: pip still
109
133
  # picks transitive versions at build time, and listing every
@@ -119,8 +143,9 @@ repos:
119
143
  # runs, and nothing otherwise ties it to the locked one, so an
120
144
  # autoupdate of the mirror or a lockfile-only mypy upgrade would
121
145
  # leave the hook running a different checker in silence. With the
122
- # pin present, the test compares it against uv.lock, and a mirror
123
- # whose rev disagrees fails to install rather than quietly winning.
146
+ # pin present, the sync hook keeps it at the locked version, and a
147
+ # mirror whose rev disagrees fails to install rather than quietly
148
+ # winning.
124
149
  additional_dependencies:
125
150
  - mypy==2.3.1
126
151
  - click==8.5.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: github2gerrit
3
- Version: 2.2.1
3
+ Version: 2.3.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
@@ -195,11 +195,14 @@ as dispatch inputs and forward them the same way.
195
195
 
196
196
  Pin `@main` to a release tag or commit SHA for production use.
197
197
 
198
- A bulk `workflow_dispatch` (`PR_NUMBER` of `0`) processes every open
199
- pull request in one run, which does not serialise against the
200
- per-pull-request runs that events start. Avoid triggering one while
201
- pull request activity is in flight; see
202
- [#422](https://github.com/lfreleng-actions/github2gerrit-action/issues/422).
198
+ A bulk `workflow_dispatch` (`PR_NUMBER` of `0`) fans out: the reusable
199
+ workflow lists the open pull requests and runs one job per pull request,
200
+ four at a time, each in that pull request's own concurrency group, so a sweep
201
+ queues behind the runs that events start for the same pull request
202
+ instead of racing them. One further job runs the repository-wide cleanup once.
203
+ A sweep covers at most 255 open pull requests, one fewer than GitHub's 256-job
204
+ matrix limit; beyond that it fails, and you dispatch individual `PR_NUMBER`
205
+ values instead. A bulk dispatch sets no workflow outputs.
203
206
 
204
207
  ### Option B: composite action
205
208
 
@@ -256,6 +259,12 @@ jobs:
256
259
  AUTOMATION_ONLY: false
257
260
  ```
258
261
 
262
+ A composite action cannot start jobs, so here a bulk `workflow_dispatch`
263
+ (`PR_NUMBER` of `0`) still processes every open pull request in one job. That
264
+ job does not serialise against the per-pull-request runs events start, so
265
+ avoid triggering one while pull request activity is in flight, or use the
266
+ reusable workflow, which fans the sweep out.
267
+
259
268
  ### Option C: command-line tool
260
269
 
261
270
  The underlying Python CLI supports local and ad-hoc use (for example,
@@ -277,7 +286,7 @@ uvx github2gerrit https://github.com/onap/portal-ng-bff/pull/33
277
286
  | `GERRIT_SSH_USER_G2G` | No | `""` | Gerrit SSH username; derived when not supplied |
278
287
  | `GERRIT_SSH_USER_G2G_EMAIL` | No | `""` | Gerrit user email address; derived when not supplied |
279
288
  | `GERRIT_SERVER` | No | `""` | Gerrit server hostname; overrides `.gitreview` when set |
280
- | `GERRIT_SERVER_PORT` | No | `"29418"` | Gerrit SSH port |
289
+ | `GERRIT_SERVER_PORT` | No | `""` | Gerrit SSH port; `.gitreview`'s when unset, else 29418 |
281
290
  | `GERRIT_PROJECT` | No | `""` | Gerrit project name; overrides `.gitreview` when set |
282
291
  | `GERRIT_HTTP_BASE_PATH` | No | `""` | HTTP base path for Gerrit REST API (e.g. `/r`) |
283
292
  | `GERRIT_HTTP_USER` | No | `""` | Gerrit HTTP user for REST queries |
@@ -377,7 +386,7 @@ Input defaults match the composite action defaults.
377
386
  | `GERRIT_SSH_USER_G2G` | string | `""` | Gerrit SSH username |
378
387
  | `GERRIT_SSH_USER_G2G_EMAIL` | string | `""` | Gerrit user email address |
379
388
  | `GERRIT_SERVER` | string | `""` | Gerrit server hostname |
380
- | `GERRIT_SERVER_PORT` | string | `"29418"` | Gerrit SSH port |
389
+ | `GERRIT_SERVER_PORT` | string | `""` | Gerrit SSH port; `.gitreview`'s when unset |
381
390
  | `GERRIT_PROJECT` | string | `""` | Gerrit project name |
382
391
  | `GERRIT_HTTP_BASE_PATH` | string | `""` | HTTP base path for Gerrit REST |
383
392
  | `GERRIT_HTTP_USER` | string | `""` | Gerrit HTTP user for REST queries |
@@ -148,11 +148,14 @@ as dispatch inputs and forward them the same way.
148
148
 
149
149
  Pin `@main` to a release tag or commit SHA for production use.
150
150
 
151
- A bulk `workflow_dispatch` (`PR_NUMBER` of `0`) processes every open
152
- pull request in one run, which does not serialise against the
153
- per-pull-request runs that events start. Avoid triggering one while
154
- pull request activity is in flight; see
155
- [#422](https://github.com/lfreleng-actions/github2gerrit-action/issues/422).
151
+ A bulk `workflow_dispatch` (`PR_NUMBER` of `0`) fans out: the reusable
152
+ workflow lists the open pull requests and runs one job per pull request,
153
+ four at a time, each in that pull request's own concurrency group, so a sweep
154
+ queues behind the runs that events start for the same pull request
155
+ instead of racing them. One further job runs the repository-wide cleanup once.
156
+ A sweep covers at most 255 open pull requests, one fewer than GitHub's 256-job
157
+ matrix limit; beyond that it fails, and you dispatch individual `PR_NUMBER`
158
+ values instead. A bulk dispatch sets no workflow outputs.
156
159
 
157
160
  ### Option B: composite action
158
161
 
@@ -209,6 +212,12 @@ jobs:
209
212
  AUTOMATION_ONLY: false
210
213
  ```
211
214
 
215
+ A composite action cannot start jobs, so here a bulk `workflow_dispatch`
216
+ (`PR_NUMBER` of `0`) still processes every open pull request in one job. That
217
+ job does not serialise against the per-pull-request runs events start, so
218
+ avoid triggering one while pull request activity is in flight, or use the
219
+ reusable workflow, which fans the sweep out.
220
+
212
221
  ### Option C: command-line tool
213
222
 
214
223
  The underlying Python CLI supports local and ad-hoc use (for example,
@@ -230,7 +239,7 @@ uvx github2gerrit https://github.com/onap/portal-ng-bff/pull/33
230
239
  | `GERRIT_SSH_USER_G2G` | No | `""` | Gerrit SSH username; derived when not supplied |
231
240
  | `GERRIT_SSH_USER_G2G_EMAIL` | No | `""` | Gerrit user email address; derived when not supplied |
232
241
  | `GERRIT_SERVER` | No | `""` | Gerrit server hostname; overrides `.gitreview` when set |
233
- | `GERRIT_SERVER_PORT` | No | `"29418"` | Gerrit SSH port |
242
+ | `GERRIT_SERVER_PORT` | No | `""` | Gerrit SSH port; `.gitreview`'s when unset, else 29418 |
234
243
  | `GERRIT_PROJECT` | No | `""` | Gerrit project name; overrides `.gitreview` when set |
235
244
  | `GERRIT_HTTP_BASE_PATH` | No | `""` | HTTP base path for Gerrit REST API (e.g. `/r`) |
236
245
  | `GERRIT_HTTP_USER` | No | `""` | Gerrit HTTP user for REST queries |
@@ -330,7 +339,7 @@ Input defaults match the composite action defaults.
330
339
  | `GERRIT_SSH_USER_G2G` | string | `""` | Gerrit SSH username |
331
340
  | `GERRIT_SSH_USER_G2G_EMAIL` | string | `""` | Gerrit user email address |
332
341
  | `GERRIT_SERVER` | string | `""` | Gerrit server hostname |
333
- | `GERRIT_SERVER_PORT` | string | `"29418"` | Gerrit SSH port |
342
+ | `GERRIT_SERVER_PORT` | string | `""` | Gerrit SSH port; `.gitreview`'s when unset |
334
343
  | `GERRIT_PROJECT` | string | `""` | Gerrit project name |
335
344
  | `GERRIT_HTTP_BASE_PATH` | string | `""` | HTTP base path for Gerrit REST |
336
345
  | `GERRIT_HTTP_USER` | string | `""` | Gerrit HTTP user for REST queries |
@@ -133,9 +133,9 @@ inputs:
133
133
  required: false
134
134
  default: ""
135
135
  GERRIT_SERVER_PORT:
136
- description: "Gerrit server SSH TCP port"
136
+ description: "Gerrit server SSH TCP port; .gitreview's when unset, else 29418"
137
137
  required: false
138
- default: "29418"
138
+ default: ""
139
139
  GERRIT_PROJECT:
140
140
  description: "Gerrit project; optional if .gitreview exists"
141
141
  required: false
@@ -266,7 +266,7 @@ runs:
266
266
  - name: "Setup uv"
267
267
  if: steps.disabled-check.outputs.disabled != 'true'
268
268
  # yamllint disable-line rule:line-length
269
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
269
+ uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
270
270
  with:
271
271
  enable-cache: false
272
272
 
@@ -101,7 +101,7 @@ set by GitHub Actions) and undergo proper boolean parsing.
101
101
  | Flag(s) | Env var | Default | Description |
102
102
  | ------------------------------------ | --------------------------- | ------- | ------------------------------------------------------------ |
103
103
  | `--gerrit-server TEXT` | `GERRIT_SERVER` | `""` | Gerrit server hostname (optional; overrides `.gitreview`) |
104
- | `--gerrit-server-port INTEGER` | `GERRIT_SERVER_PORT` | `29418` | Gerrit SSH port |
104
+ | `--gerrit-server-port INTEGER` | `GERRIT_SERVER_PORT` | unset | Gerrit SSH port; `.gitreview`'s when unset, else 29418 |
105
105
  | `--gerrit-project TEXT` | `GERRIT_PROJECT` | `""` | Gerrit project (optional; overrides `.gitreview` when set) |
106
106
  | `--gerrit-ssh-user-g2g TEXT` | `GERRIT_SSH_USER_G2G` | `""` | Gerrit SSH username (e.g., automation bot account) |
107
107
  | `--gerrit-ssh-user-g2g-email TEXT` | `GERRIT_SSH_USER_G2G_EMAIL` | `""` | Email address for the Gerrit SSH user |
@@ -206,6 +206,7 @@ forwarded setting treats blank as unset and keeps its documented default.
206
206
  | `CLEANUP_GERRIT` | `true` | Abandon Gerrit changes for closed GitHub PRs |
207
207
  | `PR_NUMBER` | unset | Pull request number to process in CI/CD mode (`0` means bulk mode) |
208
208
  | `SYNC_ALL_OPEN_PRS` | `false` | Process all open PRs in the repository (bulk mode) |
209
+ | `G2G_SWEEP_LEG` | `false` | Set by the reusable workflow on each job of a fanned-out bulk sweep |
209
210
  | `GERRIT_HTTP_USER` | unset | Username for the Gerrit REST API (when required) |
210
211
  | `GERRIT_HTTP_PASSWORD` | unset | HTTP password/token for the Gerrit REST API |
211
212
  | `GERRIT_HTTP_BASE_PATH` | unset | Gerrit REST base path for non-standard deployments (e.g., `/r`) |
@@ -403,8 +403,12 @@ signal never earns a fork unwarranted trust.
403
403
 
404
404
  Resolution order for a fork pull request:
405
405
 
406
- 1. Explicit `GERRIT_SERVER` / `GERRIT_SERVER_PORT` / `GERRIT_PROJECT` inputs,
407
- each for its own field — an operator configured them for this run
406
+ 1. Explicit `GERRIT_SERVER` / `GERRIT_SERVER_PORT` / `GERRIT_PROJECT`
407
+ inputs, each for its own field — an operator configured them for this
408
+ run. The port input has no default: the action and the CLI pass none
409
+ when the caller gave none, so a set port is distinguishable from an
410
+ unset one. 29418 applies only when neither an input nor `.gitreview`
411
+ names a port.
408
412
  2. `.gitreview` from the base repository at the pull request's base branch,
409
413
  via the GitHub API or `raw.githubusercontent.com`
410
414
  3. Per-organization configuration file
@@ -530,8 +534,10 @@ nothing to unblock.
530
534
  A zero-touch variant — a periodic sweep that notices the approval without
531
535
  anyone commenting — remains open as
532
536
  [#421](https://github.com/lfreleng-actions/github2gerrit-action/issues/421).
533
- A repository-wide job needs cross-run serialisation that GitHub's per-job
534
- concurrency groups cannot express, so this mechanism deliberately omits it.
537
+ It can build on two pieces that bulk dispatch now uses: a job per pull
538
+ request, so each transfer takes that pull request's own lock, and the
539
+ transfer record described below, so an already-transferred head gets no
540
+ second visit.
535
541
 
536
542
  `pull_request_review` should be **removed** from any workflow that still
537
543
  carries it. It can no longer transfer anything: on a fork pull request it runs
@@ -588,7 +594,26 @@ covers an earlier commit, the comment says so, so a maintainer who did approve
588
594
  is not told that nobody has.
589
595
 
590
596
  Once approval arrives, the tool edits that comment again to record it, so a
591
- transferred pull request does not keep displaying a stale block.
597
+ transferred pull request does not keep displaying a stale block. After the
598
+ transfer succeeds it edits the comment once more to say so, recording the
599
+ transferred commit in a hidden marker.
600
+
601
+ A bulk sweep (`PR_NUMBER` of `0`) reads that marker and passes over a pull
602
+ request whose current head it names, rather than submitting the same commit
603
+ again. Through the reusable workflow each pull request in a sweep runs as a
604
+ job of its own, and the marker behaves the same there. Anything less means the sweep processes the pull request as before:
605
+ no comment, no marker, a comment it cannot read, or a head that has moved
606
+ since. Only a run that pushes records anything: a dry run does not, nor does
607
+ one that finds the pull request's changes already merged or abandoned and
608
+ acts on GitHub instead. Neither does a pull request approved before its
609
+ first run, which never had a comment to edit. Only sweeps consult
610
+ the marker. A dispatch naming the pull request, a push and a
611
+ `@github2gerrit check` comment transfer whatever it says.
612
+
613
+ The marker proves nothing about who wrote it, and the tool does not assume it
614
+ did. Believing a pasted copy is harmless: skipping transfers nothing, it
615
+ delays only the sweep, and the tool reads the marker only on pull requests
616
+ the gate applies to.
592
617
 
593
618
  #### If the head moves mid-run
594
619