gerrit-clone 2.2.1__tar.gz → 2.2.2__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 (188) hide show
  1. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/.pre-commit-config.yaml +9 -8
  2. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/PKG-INFO +3 -3
  3. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/pyproject.toml +22 -1
  4. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/__init__.py +1 -0
  5. gerrit_clone-2.2.2/src/gerrit_clone/cli.py +48 -0
  6. gerrit_clone-2.2.2/src/gerrit_clone/cli_app.py +99 -0
  7. gerrit_clone-2.2.2/src/gerrit_clone/cli_clone.py +188 -0
  8. gerrit_clone-2.2.2/src/gerrit_clone/cli_clone_models.py +74 -0
  9. gerrit_clone-2.2.2/src/gerrit_clone/cli_clone_run.py +325 -0
  10. gerrit_clone-2.2.2/src/gerrit_clone/cli_clone_setup.py +416 -0
  11. gerrit_clone-2.2.2/src/gerrit_clone/cli_config.py +120 -0
  12. gerrit_clone-2.2.2/src/gerrit_clone/cli_hooks.py +67 -0
  13. gerrit_clone-2.2.2/src/gerrit_clone/cli_mirror.py +192 -0
  14. gerrit_clone-2.2.2/src/gerrit_clone/cli_mirror_models.py +53 -0
  15. gerrit_clone-2.2.2/src/gerrit_clone/cli_mirror_run.py +281 -0
  16. gerrit_clone-2.2.2/src/gerrit_clone/cli_mirror_setup.py +237 -0
  17. gerrit_clone-2.2.2/src/gerrit_clone/cli_options_clone.py +400 -0
  18. gerrit_clone-2.2.2/src/gerrit_clone/cli_options_mirror.py +259 -0
  19. gerrit_clone-2.2.2/src/gerrit_clone/cli_options_refresh.py +175 -0
  20. gerrit_clone-2.2.2/src/gerrit_clone/cli_options_reset.py +65 -0
  21. gerrit_clone-2.2.2/src/gerrit_clone/cli_refresh.py +133 -0
  22. gerrit_clone-2.2.2/src/gerrit_clone/cli_refresh_report.py +94 -0
  23. gerrit_clone-2.2.2/src/gerrit_clone/cli_refresh_run.py +352 -0
  24. gerrit_clone-2.2.2/src/gerrit_clone/cli_reset.py +110 -0
  25. gerrit_clone-2.2.2/src/gerrit_clone/cli_reset_run.py +223 -0
  26. gerrit_clone-2.2.2/src/gerrit_clone/cli_session.py +38 -0
  27. gerrit_clone-2.2.2/src/gerrit_clone/clone_conflicts.py +216 -0
  28. gerrit_clone-2.2.2/src/gerrit_clone/clone_diagnostics.py +252 -0
  29. gerrit_clone-2.2.2/src/gerrit_clone/clone_git_env.py +195 -0
  30. gerrit_clone-2.2.2/src/gerrit_clone/clone_locking.py +142 -0
  31. gerrit_clone-2.2.2/src/gerrit_clone/clone_manager.py +318 -0
  32. gerrit_clone-2.2.2/src/gerrit_clone/clone_nesting.py +302 -0
  33. gerrit_clone-2.2.2/src/gerrit_clone/clone_orchestrator.py +433 -0
  34. gerrit_clone-2.2.2/src/gerrit_clone/clone_ordering.py +295 -0
  35. gerrit_clone-2.2.2/src/gerrit_clone/clone_refresh.py +140 -0
  36. gerrit_clone-2.2.2/src/gerrit_clone/clone_reporting.py +222 -0
  37. gerrit_clone-2.2.2/src/gerrit_clone/clone_results.py +124 -0
  38. gerrit_clone-2.2.2/src/gerrit_clone/clone_retry_policy.py +310 -0
  39. gerrit_clone-2.2.2/src/gerrit_clone/clone_stages.py +202 -0
  40. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/clone_utils.py +133 -77
  41. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/concurrent_utils.py +1 -0
  42. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/config.py +4 -140
  43. gerrit_clone-2.2.2/src/gerrit_clone/config_env.py +161 -0
  44. gerrit_clone-2.2.2/src/gerrit_clone/config_errors.py +16 -0
  45. gerrit_clone-2.2.2/src/gerrit_clone/content_filter.py +427 -0
  46. gerrit_clone-2.2.2/src/gerrit_clone/content_patterns.py +178 -0
  47. gerrit_clone-2.2.2/src/gerrit_clone/content_redaction.py +178 -0
  48. gerrit_clone-2.2.2/src/gerrit_clone/content_removal.py +203 -0
  49. gerrit_clone-2.2.2/src/gerrit_clone/content_scan.py +379 -0
  50. gerrit_clone-2.2.2/src/gerrit_clone/content_worktree.py +311 -0
  51. gerrit_clone-2.2.2/src/gerrit_clone/error_collection.py +200 -0
  52. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/file_logging.py +87 -194
  53. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/gerrit_api.py +3 -1
  54. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/git_utils.py +5 -7
  55. gerrit_clone-2.2.2/src/gerrit_clone/github_api.py +403 -0
  56. gerrit_clone-2.2.2/src/gerrit_clone/github_async_pacing.py +144 -0
  57. gerrit_clone-2.2.2/src/gerrit_clone/github_async_repo.py +402 -0
  58. gerrit_clone-2.2.2/src/gerrit_clone/github_batch_support.py +182 -0
  59. gerrit_clone-2.2.2/src/gerrit_clone/github_clone_env.py +67 -0
  60. gerrit_clone-2.2.2/src/gerrit_clone/github_clone_results.py +52 -0
  61. gerrit_clone-2.2.2/src/gerrit_clone/github_clone_url.py +102 -0
  62. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/github_discovery.py +1 -1
  63. gerrit_clone-2.2.2/src/gerrit_clone/github_gh_cli.py +125 -0
  64. gerrit_clone-2.2.2/src/gerrit_clone/github_graphql.py +368 -0
  65. gerrit_clone-2.2.2/src/gerrit_clone/github_models.py +144 -0
  66. gerrit_clone-2.2.2/src/gerrit_clone/github_repo_ops.py +244 -0
  67. gerrit_clone-2.2.2/src/gerrit_clone/github_token_hygiene.py +98 -0
  68. gerrit_clone-2.2.2/src/gerrit_clone/github_transport.py +264 -0
  69. gerrit_clone-2.2.2/src/gerrit_clone/github_worker.py +225 -0
  70. gerrit_clone-2.2.2/src/gerrit_clone/mirror_branch_repair.py +264 -0
  71. gerrit_clone-2.2.2/src/gerrit_clone/mirror_cleanup.py +68 -0
  72. gerrit_clone-2.2.2/src/gerrit_clone/mirror_content_filters.py +186 -0
  73. gerrit_clone-2.2.2/src/gerrit_clone/mirror_default_branch.py +148 -0
  74. gerrit_clone-2.2.2/src/gerrit_clone/mirror_filtering.py +64 -0
  75. gerrit_clone-2.2.2/src/gerrit_clone/mirror_git_refs.py +59 -0
  76. gerrit_clone-2.2.2/src/gerrit_clone/mirror_manager.py +430 -0
  77. gerrit_clone-2.2.2/src/gerrit_clone/mirror_models.py +125 -0
  78. gerrit_clone-2.2.2/src/gerrit_clone/mirror_planning.py +282 -0
  79. gerrit_clone-2.2.2/src/gerrit_clone/mirror_push.py +148 -0
  80. gerrit_clone-2.2.2/src/gerrit_clone/mirror_result_builder.py +263 -0
  81. gerrit_clone-2.2.2/src/gerrit_clone/model_clone_results.py +213 -0
  82. gerrit_clone-2.2.2/src/gerrit_clone/model_config_validation.py +240 -0
  83. gerrit_clone-2.2.2/src/gerrit_clone/model_enums.py +69 -0
  84. gerrit_clone-2.2.2/src/gerrit_clone/model_project.py +80 -0
  85. gerrit_clone-2.2.2/src/gerrit_clone/model_project_filters.py +118 -0
  86. gerrit_clone-2.2.2/src/gerrit_clone/model_refresh_results.py +211 -0
  87. gerrit_clone-2.2.2/src/gerrit_clone/models.py +266 -0
  88. gerrit_clone-2.2.2/src/gerrit_clone/netrc.py +343 -0
  89. gerrit_clone-2.2.2/src/gerrit_clone/netrc_discovery.py +108 -0
  90. gerrit_clone-2.2.2/src/gerrit_clone/netrc_models.py +91 -0
  91. gerrit_clone-2.2.2/src/gerrit_clone/netrc_parser.py +364 -0
  92. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/output_utils.py +2 -6
  93. gerrit_clone-2.2.2/src/gerrit_clone/path_errors.py +22 -0
  94. gerrit_clone-2.2.2/src/gerrit_clone/path_naming.py +165 -0
  95. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/pathing.py +70 -167
  96. gerrit_clone-2.2.2/src/gerrit_clone/progress.py +386 -0
  97. gerrit_clone-2.2.2/src/gerrit_clone/progress_display.py +257 -0
  98. gerrit_clone-2.2.2/src/gerrit_clone/progress_live.py +194 -0
  99. gerrit_clone-2.2.2/src/gerrit_clone/progress_modes.py +22 -0
  100. gerrit_clone-2.2.2/src/gerrit_clone/progress_results.py +100 -0
  101. gerrit_clone-2.2.2/src/gerrit_clone/progress_summary.py +109 -0
  102. gerrit_clone-2.2.2/src/gerrit_clone/rate_limit.py +340 -0
  103. gerrit_clone-2.2.2/src/gerrit_clone/rate_limit_budget.py +336 -0
  104. gerrit_clone-2.2.2/src/gerrit_clone/rate_limit_helpers.py +96 -0
  105. gerrit_clone-2.2.2/src/gerrit_clone/rate_limit_progress.py +80 -0
  106. gerrit_clone-2.2.2/src/gerrit_clone/refresh_branch_repair.py +392 -0
  107. gerrit_clone-2.2.2/src/gerrit_clone/refresh_discovery.py +188 -0
  108. gerrit_clone-2.2.2/src/gerrit_clone/refresh_execution.py +351 -0
  109. gerrit_clone-2.2.2/src/gerrit_clone/refresh_force.py +405 -0
  110. gerrit_clone-2.2.2/src/gerrit_clone/refresh_git_env.py +218 -0
  111. gerrit_clone-2.2.2/src/gerrit_clone/refresh_manager.py +329 -0
  112. gerrit_clone-2.2.2/src/gerrit_clone/refresh_output.py +366 -0
  113. gerrit_clone-2.2.2/src/gerrit_clone/refresh_parallel.py +225 -0
  114. gerrit_clone-2.2.2/src/gerrit_clone/refresh_repo_state.py +374 -0
  115. gerrit_clone-2.2.2/src/gerrit_clone/refresh_worker.py +359 -0
  116. gerrit_clone-2.2.2/src/gerrit_clone/reset_confirmation.py +146 -0
  117. gerrit_clone-2.2.2/src/gerrit_clone/reset_deletion.py +93 -0
  118. gerrit_clone-2.2.2/src/gerrit_clone/reset_display.py +234 -0
  119. gerrit_clone-2.2.2/src/gerrit_clone/reset_manager.py +357 -0
  120. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/reset_models.py +1 -4
  121. gerrit_clone-2.2.2/src/gerrit_clone/rich_optional.py +90 -0
  122. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/rich_status.py +11 -11
  123. gerrit_clone-2.2.2/src/gerrit_clone/worker.py +439 -0
  124. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_cli_netrc_options.py +5 -8
  125. gerrit_clone-2.2.2/tests/test_clone_orchestrator_timeout.py +165 -0
  126. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_content_filter.py +1 -1
  127. gerrit_clone-2.2.2/tests/test_content_redaction.py +76 -0
  128. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_file_logging_changes.py +36 -0
  129. gerrit_clone-2.2.2/tests/test_rich_optional.py +76 -0
  130. gerrit_clone-2.2.1/src/gerrit_clone/cli.py +0 -2636
  131. gerrit_clone-2.2.1/src/gerrit_clone/clone_manager.py +0 -1230
  132. gerrit_clone-2.2.1/src/gerrit_clone/content_filter.py +0 -1290
  133. gerrit_clone-2.2.1/src/gerrit_clone/github_api.py +0 -1709
  134. gerrit_clone-2.2.1/src/gerrit_clone/github_worker.py +0 -519
  135. gerrit_clone-2.2.1/src/gerrit_clone/mirror_manager.py +0 -1276
  136. gerrit_clone-2.2.1/src/gerrit_clone/models.py +0 -1002
  137. gerrit_clone-2.2.1/src/gerrit_clone/netrc.py +0 -834
  138. gerrit_clone-2.2.1/src/gerrit_clone/progress.py +0 -867
  139. gerrit_clone-2.2.1/src/gerrit_clone/rate_limit.py +0 -825
  140. gerrit_clone-2.2.1/src/gerrit_clone/refresh_manager.py +0 -596
  141. gerrit_clone-2.2.1/src/gerrit_clone/refresh_worker.py +0 -2019
  142. gerrit_clone-2.2.1/src/gerrit_clone/reset_manager.py +0 -738
  143. gerrit_clone-2.2.1/src/gerrit_clone/worker.py +0 -1160
  144. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/.gitignore +0 -0
  145. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/IMPLEMENTATION.md +0 -0
  146. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/LICENSE +0 -0
  147. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/README.md +0 -0
  148. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/action.yaml +0 -0
  149. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/discovery.py +0 -0
  150. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/error_codes.py +0 -0
  151. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/git_comparison.py +0 -0
  152. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/logging.py +0 -0
  153. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/py.typed +0 -0
  154. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/retry.py +0 -0
  155. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/ssh_discovery.py +0 -0
  156. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/src/gerrit_clone/unified_discovery.py +0 -0
  157. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/__init__.py +0 -0
  158. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/conftest.py +0 -0
  159. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/integration/__init__.py +0 -0
  160. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/integration/test_discovery_integration.py +0 -0
  161. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/integration/test_github_clone.py +0 -0
  162. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_action_cli_alignment.py +0 -0
  163. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_clone_manager_github_refresh.py +0 -0
  164. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_clone_utils.py +0 -0
  165. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_config.py +0 -0
  166. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_gerrit_api.py +0 -0
  167. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_git_comparison.py +0 -0
  168. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_git_utils.py +0 -0
  169. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_github_api.py +0 -0
  170. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_logging.py +0 -0
  171. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_mirror_manager.py +0 -0
  172. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_models.py +0 -0
  173. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_netrc.py +0 -0
  174. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_output_utils.py +0 -0
  175. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_pathing.py +0 -0
  176. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_project_filtering.py +0 -0
  177. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_rate_limit.py +0 -0
  178. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_refresh_manager.py +0 -0
  179. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_refresh_worker.py +0 -0
  180. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_reset_manager.py +0 -0
  181. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_reset_models.py +0 -0
  182. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_retry.py +0 -0
  183. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/test_worker.py +0 -0
  184. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/unit/__init__.py +0 -0
  185. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/unit/test_discovery.py +0 -0
  186. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/unit/test_github_discovery.py +0 -0
  187. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/unit/test_github_worker.py +0 -0
  188. {gerrit_clone-2.2.1 → gerrit_clone-2.2.2}/tests/unit/test_unified_discovery.py +0 -0
@@ -3,6 +3,7 @@
3
3
  # SPDX-FileCopyrightText: 2025 The Linux Foundation
4
4
 
5
5
  ci:
6
+ autofix_prs: false
6
7
  skip: [basedpyright, pytest, gha-workflow-linter]
7
8
  autofix_commit_msg: |
8
9
  Chore: pre-commit autofixes
@@ -51,7 +52,7 @@ repos:
51
52
  types: [yaml]
52
53
 
53
54
  - repo: https://github.com/astral-sh/ruff-pre-commit
54
- rev: 01a675ea018f2fb714478a5ffb83fcea8374bb06 # frozen: v0.15.21
55
+ rev: aab412d509121cb5f7533134b7e67f9fab59c682 # frozen: v0.16.4
55
56
  hooks:
56
57
  - id: ruff
57
58
  files: ^(scripts|tests|custom_components)/.+\.py$
@@ -60,7 +61,7 @@ repos:
60
61
  files: ^(scripts|tests|custom_components)/.+\.py$
61
62
 
62
63
  - repo: https://github.com/pre-commit/mirrors-mypy
63
- rev: 41e691678310dfd3833f7ab4e180ddb014310356 # frozen: v2.3.0
64
+ rev: 7ff8d35ae36a7d2b968f2f90b4c723e292e594ee # frozen: v2.3.1
64
65
  hooks:
65
66
  - id: mypy
66
67
  additional_dependencies:
@@ -79,12 +80,12 @@ repos:
79
80
  args: ["--no-adverb"]
80
81
 
81
82
  - repo: https://github.com/shellcheck-py/shellcheck-py
82
- rev: 745eface02aef23e168a8afb6b5737818efbea95 # frozen: v0.11.0.1
83
+ rev: a6564f5d57444e123433a5c9af733e3975c77229 # frozen: v0.11.0.1-1
83
84
  hooks:
84
85
  - id: shellcheck
85
86
 
86
87
  - repo: https://github.com/igorshubovych/markdownlint-cli
87
- rev: a4d5d37e66ebcd6b3705204a1d6dbb56dea66338 # frozen: v0.49.0
88
+ rev: 5b5dddc4fb0f83c3ea1fc5616fa63e115dce83e0 # frozen: v0.49.1
88
89
  hooks:
89
90
  - id: markdownlint
90
91
  args: ["--fix"]
@@ -103,23 +104,23 @@ repos:
103
104
 
104
105
  # Check for misspellings in documentation files
105
106
  - repo: https://github.com/codespell-project/codespell
106
- rev: 2ccb47ff45ad361a21071a7eedda4c37e6ae8c5a # frozen: v2.4.2
107
+ rev: 57b21406f092110c18776e39b0bda50d37c945c8 # frozen: v2.4.3
107
108
  hooks:
108
109
  - id: codespell
109
110
 
110
111
  # Requires a mirror, primary repo lacks .pre-commit-hooks.yaml
111
112
  - repo: https://github.com/DetachHead/basedpyright-prek-mirror
112
- rev: d55eabd2531b4f4a4c49c30fba627ce3a636ab79 # frozen: 1.39.9
113
+ rev: 3c94d276aa3005fa1f5a977946c9dc106135c083 # frozen: 1.39.10
113
114
  hooks:
114
115
  - id: basedpyright
115
116
 
116
117
  - repo: https://github.com/lfreleng-actions/gha-workflow-linter
117
- rev: 4c3079dcb6e9e3c295f961ce5bd5b8585db698ca # frozen: v1.2.2
118
+ rev: 42aa4db931ab4c9da0930ae5ca2259ab08da79cb # frozen: v1.5.2
118
119
  hooks:
119
120
  - id: gha-workflow-linter
120
121
 
121
122
  - repo: https://github.com/python-jsonschema/check-jsonschema
122
- rev: 1a4bb160cab6417b3045e1b37b6b72449243e658 # frozen: 0.37.4
123
+ rev: c4654a7e007c9619a5eb63c39a456572a0fa1851 # frozen: 0.38.0
123
124
  hooks:
124
125
  - id: check-github-actions
125
126
  - id: check-github-workflows
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: gerrit-clone
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: A multi-threaded CLI tool for bulk cloning repositories from Gerrit servers
5
5
  Project-URL: Homepage, https://github.com/lfreleng-actions/gerrit-clone-action
6
6
  Project-URL: Documentation, https://github.com/lfreleng-actions/gerrit-clone-action#readme
@@ -30,7 +30,7 @@ Requires-Python: <3.14,>=3.11
30
30
  Requires-Dist: httpx<0.29.0,>=0.28.1
31
31
  Requires-Dist: pyyaml<7.0.0,>=6.0.3
32
32
  Requires-Dist: rich<16.0.0,>=14.2.0
33
- Requires-Dist: typer<0.27.0,>=0.21.1
33
+ Requires-Dist: typer<0.28.0,>=0.21.1
34
34
  Provides-Extra: dev
35
35
  Requires-Dist: pytest-asyncio<1.5.0,>=0.25.3; extra == 'dev'
36
36
  Requires-Dist: pytest-cov<8.0.0,>=6.3.0; extra == 'dev'
@@ -45,7 +45,7 @@ classifiers = [
45
45
  ]
46
46
  requires-python = ">=3.11,<3.14"
47
47
  dependencies = [
48
- "typer>=0.21.1,<0.27.0",
48
+ "typer>=0.21.1,<0.28.0",
49
49
  "rich>=14.2.0,<16.0.0",
50
50
  "httpx>=0.28.1,<0.29.0",
51
51
  "pyyaml>=6.0.3,<7.0.0",
@@ -192,11 +192,32 @@ select = [
192
192
  ignore = [
193
193
  "E501", # line too long, handled by formatter
194
194
  "PLR0913", # too many arguments
195
+ "PLR0917", # too many positional arguments — see note below
195
196
  "PLR0912", # too many branches
196
197
  "PLR0915", # too many statements — CLI commands and managers are complex by design
197
198
  "PLR2004", # magic value used in comparison
198
199
  ]
199
200
 
201
+ # PLR0917 was stabilised in ruff 0.16.0. This project already selects
202
+ # the "PL" category, so a routine pre-commit autoupdate crossing that
203
+ # release began failing on code nobody had touched.
204
+ #
205
+ # It is ignored globally rather than only under tests because both
206
+ # call sites are legitimate:
207
+ #
208
+ # - tests/ stack @patch decorators, and unittest.mock injects each
209
+ # mock positionally, so a keyword-only signature is impossible
210
+ # rather than merely inconvenient.
211
+ # - src/gerrit_clone/refresh_worker.py declares RefreshWorker.__init__
212
+ # with eleven defaulted parameters. The closely related PLR0913
213
+ # (too many arguments) is already ignored directly above for exactly
214
+ # that constructor. PLR0917 counts only those arguments that may be
215
+ # passed positionally, so it is the narrower of the two; ignoring one
216
+ # while enforcing the other would be inconsistent.
217
+ #
218
+ # Scoping it to tests alone would leave src/ latently failing the moment
219
+ # the ruff hook's `files:` pattern is corrected to include src/.
220
+
200
221
  [tool.ruff.lint.per-file-ignores]
201
222
  "tests/**/*" = ["ARG", "S101", "PLR2004"]
202
223
  "src/gerrit_clone/cli.py" = ["B008"] # Typer requires function calls in defaults
@@ -5,6 +5,7 @@
5
5
 
6
6
  try:
7
7
  from importlib.metadata import version
8
+
8
9
  __version__ = version("gerrit-clone")
9
10
  except ImportError:
10
11
  # Fallback for development/editable installs
@@ -0,0 +1,48 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # SPDX-FileCopyrightText: 2025 Matthew Watkins <mwatkins@linuxfoundation.org>
3
+
4
+ """Typer-based CLI for gerrit-clone tool.
5
+
6
+ This module is the public entry point for the command line interface. It
7
+ assembles the Typer application by importing every command module and
8
+ re-exports the collaborators that the command bodies resolve at call time, so
9
+ that ``gerrit_clone.cli.<name>`` remains the single place to substitute them.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from gerrit_clone.cli_app import app, main, version_callback
15
+ from gerrit_clone.cli_clone import clone
16
+ from gerrit_clone.cli_config import show_config
17
+ from gerrit_clone.cli_mirror import mirror
18
+ from gerrit_clone.cli_refresh import refresh
19
+ from gerrit_clone.cli_reset import reset
20
+ from gerrit_clone.clone_manager import clone_repositories
21
+ from gerrit_clone.netrc import resolve_gerrit_credentials
22
+ from gerrit_clone.unified_discovery import discover_projects
23
+
24
+ # Registered explicitly rather than by decorator so that the order the
25
+ # commands appear in ``--help`` does not depend on import order.
26
+ app.command()(clone)
27
+ app.command()(refresh)
28
+ app.command(name="mirror")(mirror)
29
+ app.command()(reset)
30
+ app.command(name="config")(show_config)
31
+
32
+ __all__ = [
33
+ "app",
34
+ "clone",
35
+ "clone_repositories",
36
+ "discover_projects",
37
+ "main",
38
+ "mirror",
39
+ "refresh",
40
+ "reset",
41
+ "resolve_gerrit_credentials",
42
+ "show_config",
43
+ "version_callback",
44
+ ]
45
+
46
+
47
+ if __name__ == "__main__":
48
+ app()
@@ -0,0 +1,99 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # SPDX-FileCopyrightText: 2026 The Linux Foundation
3
+
4
+ """Typer application object shared by every gerrit-clone command module.
5
+
6
+ The application lives here rather than in :mod:`gerrit_clone.cli` so that the
7
+ per-command modules can register themselves against it without importing the
8
+ public facade that aggregates them.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import os
14
+ import sys
15
+
16
+ import typer
17
+ from rich.console import Console
18
+
19
+ from gerrit_clone import __version__
20
+ from gerrit_clone.logging import get_logger
21
+
22
+ logger = get_logger(__name__)
23
+
24
+
25
+ def is_github_actions_context() -> bool:
26
+ """Detect if running in GitHub Actions environment."""
27
+ return (
28
+ os.getenv("GITHUB_ACTIONS") == "true"
29
+ or os.getenv("GITHUB_EVENT_NAME", "").strip() != ""
30
+ )
31
+
32
+
33
+ def format_version_string(command: str = "", styled: bool = True) -> str:
34
+ """Format version string with consistent styling.
35
+
36
+ Args:
37
+ command: Optional command name to include (e.g., "mirror")
38
+ styled: Whether to include Rich markup styling
39
+
40
+ Returns:
41
+ Formatted version string
42
+ """
43
+ if styled:
44
+ if command:
45
+ return f"🏷️ [bold]gerrit-clone {command}[/bold] version [cyan]{__version__}[/cyan]"
46
+ return f"🏷️ gerrit-clone version [cyan]{__version__}[/cyan]"
47
+ else:
48
+ if command:
49
+ return f"🏷️ gerrit-clone {command} version {__version__}"
50
+ return f"🏷️ gerrit-clone version {__version__}"
51
+
52
+
53
+ # Show version information when --help is used.
54
+ #
55
+ # This runs at import time, before Typer takes over, so it writes to
56
+ # stdout directly: the Rich console the commands share is not built yet,
57
+ # and this is user-facing CLI output rather than diagnostics, so routing
58
+ # it through the logger (stderr, silenceable by level) would be wrong.
59
+ if "--help" in sys.argv:
60
+ try:
61
+ sys.stdout.write(f"{format_version_string(styled=False)}\n")
62
+ except Exception as exc:
63
+ logger.debug("Failed to format version string: %s", exc, exc_info=True)
64
+ sys.stdout.write(
65
+ "\u26a0\ufe0f gerrit-clone version information not available\n"
66
+ )
67
+
68
+
69
+ def version_callback(value: bool) -> None:
70
+ """Show version information."""
71
+ if value:
72
+ console = Console()
73
+ console.print(format_version_string())
74
+ raise typer.Exit()
75
+
76
+
77
+ app = typer.Typer(
78
+ name="gerrit-clone",
79
+ help="A multi-threaded CLI tool for bulk cloning repositories from Gerrit servers.",
80
+ no_args_is_help=True,
81
+ rich_markup_mode="rich",
82
+ add_completion=True,
83
+ )
84
+
85
+ VERSION = typer.Option(
86
+ None,
87
+ "--version",
88
+ callback=version_callback,
89
+ is_eager=True,
90
+ help="Show version information",
91
+ )
92
+
93
+
94
+ @app.callback()
95
+ def main(
96
+ version: bool | None = VERSION,
97
+ ) -> None:
98
+ """Main CLI entry point with top-level options."""
99
+ pass
@@ -0,0 +1,188 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # SPDX-FileCopyrightText: 2026 The Linux Foundation
3
+
4
+ """Definition of the ``clone`` command.
5
+
6
+ Declares the command line surface and hands the parsed arguments to
7
+ :mod:`gerrit_clone.cli_clone_run`, which performs the work.
8
+
9
+ Unlike the rest of the package this module deliberately omits
10
+ ``from __future__ import annotations``: Typer resolves the command
11
+ signature's annotations at runtime to derive each parameter type.
12
+ """
13
+
14
+ from pathlib import Path
15
+
16
+ import typer
17
+ from rich.console import Console
18
+
19
+ from gerrit_clone import cli_options_clone as opts
20
+ from gerrit_clone.cli_clone_models import CloneRequest
21
+ from gerrit_clone.cli_clone_run import handle_crash, handle_interrupt, run_clone
22
+ from gerrit_clone.cli_session import CliSession
23
+ from gerrit_clone.concurrent_utils import handle_sigint_gracefully
24
+
25
+
26
+ def clone(
27
+ host: str = opts.HOST,
28
+ source_type: str | None = opts.SOURCE_TYPE,
29
+ github_token: str | None = opts.GITHUB_TOKEN,
30
+ github_org: str | None = opts.GITHUB_ORG,
31
+ use_gh_cli: bool = opts.USE_GH_CLI,
32
+ port: int | None = opts.PORT,
33
+ base_url: str | None = opts.BASE_URL,
34
+ ssh_user: str | None = opts.SSH_USER,
35
+ ssh_identity_file: Path | None = opts.SSH_IDENTITY_FILE,
36
+ output_path: Path = opts.OUTPUT_PATH,
37
+ skip_archived: bool = opts.SKIP_ARCHIVED,
38
+ include_projects: list[str] | None = opts.INCLUDE_PROJECTS,
39
+ exclude_projects: list[str] | None = opts.EXCLUDE_PROJECTS,
40
+ ssh_debug: bool = opts.SSH_DEBUG,
41
+ discovery_method: str | None = opts.DISCOVERY_METHOD,
42
+ allow_nested_git: bool = opts.ALLOW_NESTED_GIT,
43
+ nested_protection: bool = opts.NESTED_PROTECTION,
44
+ move_conflicting: bool = opts.MOVE_CONFLICTING,
45
+ threads: int | None = opts.THREADS,
46
+ depth: int | None = opts.DEPTH,
47
+ branch: str | None = opts.BRANCH,
48
+ mirror: bool | None = opts.MIRROR,
49
+ use_https: bool = opts.USE_HTTPS,
50
+ keep_remote_protocol: bool = opts.KEEP_REMOTE_PROTOCOL,
51
+ strict_host_checking: bool = opts.STRICT_HOST_CHECKING,
52
+ clone_timeout: int = opts.CLONE_TIMEOUT,
53
+ retry_attempts: int = opts.RETRY_ATTEMPTS,
54
+ retry_base_delay: float = opts.RETRY_BASE_DELAY,
55
+ retry_factor: float = opts.RETRY_FACTOR,
56
+ retry_max_delay: float = opts.RETRY_MAX_DELAY,
57
+ manifest_filename: str = opts.MANIFEST_FILENAME,
58
+ config_file: Path | None = opts.CONFIG_FILE,
59
+ verbose: bool = opts.VERBOSE,
60
+ quiet: bool = opts.QUIET,
61
+ cleanup: bool = opts.CLEANUP,
62
+ no_refresh: bool = opts.NO_REFRESH,
63
+ force: bool = opts.FORCE,
64
+ fetch_only: bool = opts.FETCH_ONLY,
65
+ skip_conflicts: bool = opts.SKIP_CONFLICTS,
66
+ exit_on_error: bool = opts.EXIT_ON_ERROR,
67
+ log_file: Path | None = opts.LOG_FILE,
68
+ disable_log_file: bool = opts.DISABLE_LOG_FILE,
69
+ log_level: str = opts.LOG_LEVEL,
70
+ http_user: str | None = opts.HTTP_USER,
71
+ http_password: str | None = opts.HTTP_PASSWORD,
72
+ no_netrc: bool = opts.NO_NETRC,
73
+ netrc_file: Path | None = opts.NETRC_FILE,
74
+ netrc_optional: bool = opts.NETRC_OPTIONAL,
75
+ remove_files: str | None = opts.REMOVE_FILES,
76
+ git_filter: str | None = opts.GIT_FILTER,
77
+ redact_secrets: bool = opts.REDACT_SECRETS,
78
+ ) -> None:
79
+ """Clone all repositories from a Gerrit server or GitHub organization.
80
+
81
+ This command discovers all projects/repositories from the specified source and clones
82
+ them in parallel while preserving the project hierarchy. For Gerrit, repositories are
83
+ cloned over SSH by default. For GitHub, SSH is also default (HTTPS with --https).
84
+
85
+ By default, existing repositories are refreshed (git pull) instead of skipped.
86
+ Use --no-refresh to skip existing repositories without updating them.
87
+
88
+ Examples:
89
+
90
+ # Clone all active repositories from Gerrit server
91
+ gerrit-clone clone --host gerrit.example.org
92
+
93
+ # Clone all repositories from GitHub organization (auto-refresh existing)
94
+ gerrit-clone clone --host github.com/lfreleng-actions
95
+
96
+ # Clone without refreshing existing repos
97
+ gerrit-clone clone --host github.com/myorg --no-refresh
98
+
99
+ # Force refresh existing repos (stash local changes)
100
+ gerrit-clone clone --host github.com/myorg --force
101
+
102
+ # Clone GitHub org with gh CLI (preserves upstream/origin)
103
+ gerrit-clone clone --host github.com/myorg --use-gh-cli
104
+
105
+ # Clone to specific directory with custom threads
106
+ gerrit-clone clone --host gerrit.example.org --output-path ./repos --threads 8
107
+
108
+ # Clone with shallow depth and specific branch
109
+ gerrit-clone clone --host gerrit.example.org --no-mirror --depth 10 --branch main
110
+
111
+ # Clone with explicit HTTP credentials (highest priority)
112
+ gerrit-clone clone --host gerrit.example.org --https --http-user myuser --http-password mypass
113
+
114
+ # Clone with credentials from specific .netrc file
115
+ gerrit-clone clone --host gerrit.example.org --netrc-file ~/.netrc.gerrit
116
+
117
+ # Clone requiring .netrc credentials (fail if not found)
118
+ gerrit-clone clone --host gerrit.example.org --netrc-required
119
+ """
120
+ # Configure graceful interrupt handling for multi-threaded operations
121
+ handle_sigint_gracefully()
122
+
123
+ console = Console(stderr=True)
124
+ session = CliSession(console=console)
125
+ request = CloneRequest(
126
+ host=host,
127
+ source_type=source_type,
128
+ github_token=github_token,
129
+ github_org=github_org,
130
+ use_gh_cli=use_gh_cli,
131
+ port=port,
132
+ base_url=base_url,
133
+ ssh_user=ssh_user,
134
+ ssh_identity_file=ssh_identity_file,
135
+ output_path=output_path,
136
+ skip_archived=skip_archived,
137
+ include_projects=include_projects,
138
+ exclude_projects=exclude_projects,
139
+ ssh_debug=ssh_debug,
140
+ discovery_method=discovery_method,
141
+ allow_nested_git=allow_nested_git,
142
+ nested_protection=nested_protection,
143
+ move_conflicting=move_conflicting,
144
+ threads=threads,
145
+ depth=depth,
146
+ branch=branch,
147
+ mirror=mirror,
148
+ use_https=use_https,
149
+ keep_remote_protocol=keep_remote_protocol,
150
+ strict_host_checking=strict_host_checking,
151
+ clone_timeout=clone_timeout,
152
+ retry_attempts=retry_attempts,
153
+ retry_base_delay=retry_base_delay,
154
+ retry_factor=retry_factor,
155
+ retry_max_delay=retry_max_delay,
156
+ manifest_filename=manifest_filename,
157
+ config_file=config_file,
158
+ verbose=verbose,
159
+ quiet=quiet,
160
+ cleanup=cleanup,
161
+ no_refresh=no_refresh,
162
+ force=force,
163
+ fetch_only=fetch_only,
164
+ skip_conflicts=skip_conflicts,
165
+ exit_on_error=exit_on_error,
166
+ log_file=log_file,
167
+ disable_log_file=disable_log_file,
168
+ log_level=log_level,
169
+ http_user=http_user,
170
+ http_password=http_password,
171
+ no_netrc=no_netrc,
172
+ netrc_file=netrc_file,
173
+ netrc_optional=netrc_optional,
174
+ remove_files=remove_files,
175
+ git_filter=git_filter,
176
+ redact_secrets=redact_secrets,
177
+ )
178
+
179
+ try:
180
+ run_clone(request, session)
181
+ except KeyboardInterrupt:
182
+ handle_interrupt(session)
183
+ except typer.Exit:
184
+ # Re-raise typer.Exit exceptions without catching them as generic exceptions
185
+ session.write_summary()
186
+ raise
187
+ except Exception as e:
188
+ handle_crash(session, e, verbose=verbose)
@@ -0,0 +1,74 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # SPDX-FileCopyrightText: 2026 The Linux Foundation
3
+
4
+ """The parsed ``clone`` command line.
5
+
6
+ ``CloneRequest`` carries the command's arguments unchanged between the
7
+ pipeline steps in :mod:`gerrit_clone.cli_clone_setup` and
8
+ :mod:`gerrit_clone.cli_clone_run`.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from dataclasses import dataclass
14
+ from typing import TYPE_CHECKING
15
+
16
+ if TYPE_CHECKING:
17
+ from pathlib import Path
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class CloneRequest:
22
+ """Command line arguments supplied to the ``clone`` command."""
23
+
24
+ host: str
25
+ source_type: str | None
26
+ github_token: str | None
27
+ github_org: str | None
28
+ use_gh_cli: bool
29
+ port: int | None
30
+ base_url: str | None
31
+ ssh_user: str | None
32
+ ssh_identity_file: Path | None
33
+ output_path: Path
34
+ skip_archived: bool
35
+ include_projects: list[str] | None
36
+ exclude_projects: list[str] | None
37
+ ssh_debug: bool
38
+ discovery_method: str | None
39
+ allow_nested_git: bool
40
+ nested_protection: bool
41
+ move_conflicting: bool
42
+ threads: int | None
43
+ depth: int | None
44
+ branch: str | None
45
+ mirror: bool | None
46
+ use_https: bool
47
+ keep_remote_protocol: bool
48
+ strict_host_checking: bool
49
+ clone_timeout: int
50
+ retry_attempts: int
51
+ retry_base_delay: float
52
+ retry_factor: float
53
+ retry_max_delay: float
54
+ manifest_filename: str
55
+ config_file: Path | None
56
+ verbose: bool
57
+ quiet: bool
58
+ cleanup: bool
59
+ no_refresh: bool
60
+ force: bool
61
+ fetch_only: bool
62
+ skip_conflicts: bool
63
+ exit_on_error: bool
64
+ log_file: Path | None
65
+ disable_log_file: bool
66
+ log_level: str
67
+ http_user: str | None
68
+ http_password: str | None
69
+ no_netrc: bool
70
+ netrc_file: Path | None
71
+ netrc_optional: bool
72
+ remove_files: str | None
73
+ git_filter: str | None
74
+ redact_secrets: bool