github2gerrit 1.0.4__tar.gz → 1.0.6__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.
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/.pre-commit-config.yaml +3 -3
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/PKG-INFO +4 -3
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/README.md +2 -2
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/action.yaml +1 -1
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/pyproject.toml +3 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/cli.py +7 -5
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/core.py +292 -8
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/gerrit_pr_closer.py +10 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/gitutils.py +2 -2
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/pr_content_filter.py +19 -21
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/utils.py +10 -2
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_change_id_deduplication.py +1 -1
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_cli_outputs_file.py +1 -1
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_cli_url_and_dryrun.py +2 -2
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_core_close_pr_policy.py +1 -3
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_core_prepare_commits.py +1 -1
- github2gerrit-1.0.6/tests/test_core_shallow_clone.py +826 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_gerrit_change_id_footer.py +1 -1
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_gitutils_helpers.py +1 -1
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_utils.py +79 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/uv.lock +93 -86
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/.editorconfig +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/.gitignore +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/.gitlint +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/.markdownlint.yaml +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/.readthedocs.yml +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/.yamllint +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/LICENSE +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/LICENSES/Apache-2.0.txt +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/REUSE.toml +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/docs/COMPOSITE_ACTION_TESTING.md +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/docs/PR_UPDATE_IMPLEMENTATION.md +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/docs/RELEASE-v0.2.0.md +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/docs/github2gerrit_token_permissions_classic.png +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/sitecustomize.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/__init__.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/commit_normalization.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/config.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/constants.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/duplicate_detection.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/error_codes.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/external_api.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/gerrit_query.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/gerrit_rest.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/gerrit_urls.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/github_api.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/mapping_comment.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/models.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/netrc.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/orchestrator/__init__.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/orchestrator/reconciliation.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/reconcile_matcher.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/rich_display.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/rich_logging.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/similarity.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/ssh_agent_setup.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/ssh_common.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/ssh_config_parser.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/ssh_discovery.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/src/github2gerrit/trailers.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/conftest.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/fixtures/__init__.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/fixtures/make_repo.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/fixtures/ssh_config_samples.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_action_environment_mapping.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_action_outputs.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_action_pr_number_handling.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_action_step_validation.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_automation_only.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_cli.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_cli_helpers.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_cli_netrc_options.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_commit_normalization.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_composite_action_coverage.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_config_and_reviewers.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_config_helpers.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_core_config_and_errors.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_core_gerrit_backref_comment.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_core_gerrit_push_errors.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_core_gerrit_rest_results.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_core_integration_fixture_repo.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_core_ssh_setup.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_core_ssrf_protection.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_duplicate_detection.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_email_case_normalization.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_error_codes.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_external_api_framework.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_force_flag_cli.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_gerrit_change_status_checks.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_gerrit_pr_closer.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_gerrit_rest_client.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_gerrit_urls.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_gerrit_urls_more.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_ghe_and_gitreview_args.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_github_api_error_handling.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_github_api_helpers.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_github_api_retry_and_helpers.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_mapping_comment_additional.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_mapping_comment_digest_and_backref.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_metadata_and_reconciliation.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_metadata_trailer_separation_bug.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_misc_small_coverage.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_netrc.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_orphan_rest_side_effects.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_pr_content_filter.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_pr_content_filter_integration.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_pr_update_detection.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_reconciliation_extracted_module.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_reconciliation_plan_and_orphans.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_reconciliation_scenarios.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_ssh_agent.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_ssh_agent_ownership.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_ssh_artifact_prevention.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_ssh_common.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_ssh_discovery.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_ssh_discovery_dry_run.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_trailers_additional.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/test_url_parser.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/tests/unit/test_config_integration.py +0 -0
- {github2gerrit-1.0.4 → github2gerrit-1.0.6}/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:
|
|
62
|
+
rev: fa93bc3224c614a0e9786d3e2d3d48edcca246eb # frozen: v0.15.1
|
|
63
63
|
hooks:
|
|
64
64
|
- id: ruff
|
|
65
65
|
files: ^(src|scripts|tests)/.+\.py$
|
|
@@ -110,7 +110,7 @@ repos:
|
|
|
110
110
|
# Replaces: https://github.com/rhysd/actionlint
|
|
111
111
|
# Permits actionlint to run both locally and with precommit.ci/GitHub
|
|
112
112
|
- repo: https://github.com/Mateusz-Grzelinski/actionlint-py
|
|
113
|
-
rev:
|
|
113
|
+
rev: 694e2c0dfb4253d51f3c6c54b8f9fec0a16764dc # frozen: v1.7.11.24
|
|
114
114
|
hooks:
|
|
115
115
|
- id: actionlint
|
|
116
116
|
|
|
@@ -121,7 +121,7 @@ repos:
|
|
|
121
121
|
- id: codespell
|
|
122
122
|
|
|
123
123
|
- repo: https://github.com/python-jsonschema/check-jsonschema
|
|
124
|
-
rev:
|
|
124
|
+
rev: ec368acd16deee9c560c105ab6d27db4ee19a5ec # frozen: 0.36.2
|
|
125
125
|
hooks:
|
|
126
126
|
- id: check-github-actions
|
|
127
127
|
- id: check-github-workflows
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github2gerrit
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.6
|
|
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
|
|
@@ -22,6 +22,7 @@ Classifier: Topic :: Software Development :: Build Tools
|
|
|
22
22
|
Classifier: Topic :: Software Development :: Version Control
|
|
23
23
|
Classifier: Typing :: Typed
|
|
24
24
|
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: cryptography>=46.0.5
|
|
25
26
|
Requires-Dist: git-review>=2.5.0
|
|
26
27
|
Requires-Dist: pygerrit2>=2.0.15
|
|
27
28
|
Requires-Dist: pygithub>=2.8.1
|
|
@@ -991,7 +992,7 @@ Common issues and solutions:
|
|
|
991
992
|
The comprehensive [Inputs](#inputs) table above documents all environment variables.
|
|
992
993
|
Key variables for CLI usage include:
|
|
993
994
|
|
|
994
|
-
- `G2G_LOG_LEVEL`: Set to `DEBUG` for verbose output (default: `
|
|
995
|
+
- `G2G_LOG_LEVEL`: Set to `DEBUG` for verbose output (default: `WARNING`)
|
|
995
996
|
- `G2G_VERBOSE`: Set to `true` to enable debug logging (same as `--verbose` flag)
|
|
996
997
|
- `GERRIT_SSH_PRIVKEY_G2G`: SSH private key content
|
|
997
998
|
- `GERRIT_KNOWN_HOSTS`: SSH known hosts entries
|
|
@@ -1204,7 +1205,7 @@ The following environment variables control internal behavior but are not action
|
|
|
1204
1205
|
|
|
1205
1206
|
| Environment Variable | Description | Default |
|
|
1206
1207
|
| ---------------------------- | ---------------------------------------------- | ------------------------------------------ |
|
|
1207
|
-
| `G2G_LOG_LEVEL` | Logging level (DEBUG, INFO, WARNING, ERROR) | `"
|
|
1208
|
+
| `G2G_LOG_LEVEL` | Logging level (DEBUG, INFO, WARNING, ERROR) | `"WARNING"` |
|
|
1208
1209
|
| `G2G_ENABLE_DERIVATION` | Enable auto-derivation of Gerrit parameters | `"true"` |
|
|
1209
1210
|
| `G2G_CONFIG_PATH` | Path to organization configuration file | `~/.config/github2gerrit/config.ini` |
|
|
1210
1211
|
| `G2G_AUTO_SAVE_CONFIG` | Auto-save derived parameters to config | `"false"` (GitHub Actions), `"true"` (CLI) |
|
|
@@ -946,7 +946,7 @@ Common issues and solutions:
|
|
|
946
946
|
The comprehensive [Inputs](#inputs) table above documents all environment variables.
|
|
947
947
|
Key variables for CLI usage include:
|
|
948
948
|
|
|
949
|
-
- `G2G_LOG_LEVEL`: Set to `DEBUG` for verbose output (default: `
|
|
949
|
+
- `G2G_LOG_LEVEL`: Set to `DEBUG` for verbose output (default: `WARNING`)
|
|
950
950
|
- `G2G_VERBOSE`: Set to `true` to enable debug logging (same as `--verbose` flag)
|
|
951
951
|
- `GERRIT_SSH_PRIVKEY_G2G`: SSH private key content
|
|
952
952
|
- `GERRIT_KNOWN_HOSTS`: SSH known hosts entries
|
|
@@ -1159,7 +1159,7 @@ The following environment variables control internal behavior but are not action
|
|
|
1159
1159
|
|
|
1160
1160
|
| Environment Variable | Description | Default |
|
|
1161
1161
|
| ---------------------------- | ---------------------------------------------- | ------------------------------------------ |
|
|
1162
|
-
| `G2G_LOG_LEVEL` | Logging level (DEBUG, INFO, WARNING, ERROR) | `"
|
|
1162
|
+
| `G2G_LOG_LEVEL` | Logging level (DEBUG, INFO, WARNING, ERROR) | `"WARNING"` |
|
|
1163
1163
|
| `G2G_ENABLE_DERIVATION` | Enable auto-derivation of Gerrit parameters | `"true"` |
|
|
1164
1164
|
| `G2G_CONFIG_PATH` | Path to organization configuration file | `~/.config/github2gerrit/config.ini` |
|
|
1165
1165
|
| `G2G_AUTO_SAVE_CONFIG` | Auto-save derived parameters to config | `"false"` (GitHub Actions), `"true"` (CLI) |
|
|
@@ -164,7 +164,7 @@ runs:
|
|
|
164
164
|
|
|
165
165
|
- name: "Setup uv"
|
|
166
166
|
# yamllint disable-line rule:line-length
|
|
167
|
-
uses: astral-sh/setup-uv@
|
|
167
|
+
uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0
|
|
168
168
|
with:
|
|
169
169
|
enable-cache: false
|
|
170
170
|
|
|
@@ -283,7 +283,9 @@ def _extract_and_display_pr_info(
|
|
|
283
283
|
pr_info["Files Changed"] = "unknown"
|
|
284
284
|
|
|
285
285
|
# Display the PR information
|
|
286
|
-
display_pr_info(
|
|
286
|
+
display_pr_info(
|
|
287
|
+
pr_info, "Pull Request Details", progress_tracker=progress_tracker
|
|
288
|
+
)
|
|
287
289
|
|
|
288
290
|
except GitHub2GerritError:
|
|
289
291
|
# Let our structured errors propagate
|
|
@@ -1099,8 +1101,8 @@ def main(
|
|
|
1099
1101
|
|
|
1100
1102
|
|
|
1101
1103
|
def _setup_logging() -> logging.Logger:
|
|
1102
|
-
level_name = os.getenv("G2G_LOG_LEVEL", "
|
|
1103
|
-
level = getattr(logging, level_name, logging.
|
|
1104
|
+
level_name = os.getenv("G2G_LOG_LEVEL", "WARNING").upper()
|
|
1105
|
+
level = getattr(logging, level_name, logging.WARNING)
|
|
1104
1106
|
fmt = (
|
|
1105
1107
|
"%(asctime)s %(levelname)-8s %(name)s %(filename)s:%(lineno)d | "
|
|
1106
1108
|
"%(message)s"
|
|
@@ -1111,8 +1113,8 @@ def _setup_logging() -> logging.Logger:
|
|
|
1111
1113
|
|
|
1112
1114
|
def _reconfigure_logging() -> None:
|
|
1113
1115
|
"""Reconfigure logging level based on current environment variables."""
|
|
1114
|
-
level_name = os.getenv("G2G_LOG_LEVEL", "
|
|
1115
|
-
level = getattr(logging, level_name, logging.
|
|
1116
|
+
level_name = os.getenv("G2G_LOG_LEVEL", "WARNING").upper()
|
|
1117
|
+
level = getattr(logging, level_name, logging.WARNING)
|
|
1116
1118
|
logging.getLogger().setLevel(level)
|
|
1117
1119
|
for handler in logging.getLogger().handlers:
|
|
1118
1120
|
handler.setLevel(level)
|
|
@@ -2547,9 +2547,10 @@ class Orchestrator:
|
|
|
2547
2547
|
def _ensure_workspace_prepared(self, branch: str) -> None:
|
|
2548
2548
|
"""Ensure workspace is prepared with latest remote state.
|
|
2549
2549
|
|
|
2550
|
-
Performs a
|
|
2551
|
-
|
|
2552
|
-
|
|
2550
|
+
Performs a git fetch to get the latest branch state. Does NOT
|
|
2551
|
+
proactively unshallow to avoid performance impact on large repos.
|
|
2552
|
+
If checkout later fails due to missing commits in shallow clone,
|
|
2553
|
+
_checkout_with_unshallow_fallback() will handle it reactively.
|
|
2553
2554
|
|
|
2554
2555
|
Args:
|
|
2555
2556
|
branch: The branch to fetch from origin
|
|
@@ -2575,6 +2576,276 @@ class Orchestrator:
|
|
|
2575
2576
|
# Don't mark as prepared if fetch failed
|
|
2576
2577
|
raise
|
|
2577
2578
|
|
|
2579
|
+
def _is_shallow_clone(self) -> bool:
|
|
2580
|
+
"""Check if the current workspace is a shallow clone.
|
|
2581
|
+
|
|
2582
|
+
Returns:
|
|
2583
|
+
True if the repository is a shallow clone, False otherwise.
|
|
2584
|
+
"""
|
|
2585
|
+
shallow_file = self.workspace / ".git" / "shallow"
|
|
2586
|
+
if shallow_file.exists():
|
|
2587
|
+
return True
|
|
2588
|
+
# Also check via git command for edge cases (e.g., worktrees)
|
|
2589
|
+
try:
|
|
2590
|
+
result = run_cmd(
|
|
2591
|
+
["git", "rev-parse", "--is-shallow-repository"],
|
|
2592
|
+
cwd=self.workspace,
|
|
2593
|
+
check=False,
|
|
2594
|
+
)
|
|
2595
|
+
return result.stdout.strip().lower() == "true"
|
|
2596
|
+
except Exception:
|
|
2597
|
+
return False
|
|
2598
|
+
|
|
2599
|
+
def _unshallow_repository(self) -> bool:
|
|
2600
|
+
"""Unshallow the repository to get full history.
|
|
2601
|
+
|
|
2602
|
+
Returns:
|
|
2603
|
+
True if unshallowing succeeded or repo is already full,
|
|
2604
|
+
False if unshallowing failed.
|
|
2605
|
+
"""
|
|
2606
|
+
if not self._is_shallow_clone():
|
|
2607
|
+
log.debug("Repository is not shallow, no unshallow needed")
|
|
2608
|
+
return True
|
|
2609
|
+
|
|
2610
|
+
log.info("Unshallowing repository to fetch full history...")
|
|
2611
|
+
try:
|
|
2612
|
+
run_cmd(
|
|
2613
|
+
["git", "fetch", "--unshallow", "origin"],
|
|
2614
|
+
cwd=self.workspace,
|
|
2615
|
+
env=self._ssh_env(),
|
|
2616
|
+
)
|
|
2617
|
+
except CommandError as exc:
|
|
2618
|
+
log.warning("Failed to unshallow repository: %s", exc)
|
|
2619
|
+
return False
|
|
2620
|
+
else:
|
|
2621
|
+
log.debug("Repository unshallowed successfully")
|
|
2622
|
+
return True
|
|
2623
|
+
|
|
2624
|
+
def _deepen_repository(self, depth: int = 100) -> bool:
|
|
2625
|
+
"""Deepen the repository history by fetching more commits.
|
|
2626
|
+
|
|
2627
|
+
This is a lighter alternative to full unshallow, fetching only
|
|
2628
|
+
the specified number of additional commits.
|
|
2629
|
+
|
|
2630
|
+
Args:
|
|
2631
|
+
depth: Number of additional commits to fetch (default: 100)
|
|
2632
|
+
|
|
2633
|
+
Returns:
|
|
2634
|
+
True if deepening succeeded, False otherwise.
|
|
2635
|
+
"""
|
|
2636
|
+
if not self._is_shallow_clone():
|
|
2637
|
+
log.debug("Repository is not shallow, no deepening needed")
|
|
2638
|
+
return True
|
|
2639
|
+
|
|
2640
|
+
log.debug("Deepening repository by %d commits...", depth)
|
|
2641
|
+
try:
|
|
2642
|
+
run_cmd(
|
|
2643
|
+
["git", "fetch", f"--deepen={depth}", "origin"],
|
|
2644
|
+
cwd=self.workspace,
|
|
2645
|
+
env=self._ssh_env(),
|
|
2646
|
+
)
|
|
2647
|
+
except CommandError as exc:
|
|
2648
|
+
log.debug("Failed to deepen repository: %s", exc)
|
|
2649
|
+
return False
|
|
2650
|
+
else:
|
|
2651
|
+
log.debug("Repository deepened by %d commits", depth)
|
|
2652
|
+
return True
|
|
2653
|
+
|
|
2654
|
+
def _checkout_with_unshallow_fallback(
|
|
2655
|
+
self,
|
|
2656
|
+
branch_name: str,
|
|
2657
|
+
start_point: str,
|
|
2658
|
+
create_branch: bool = True,
|
|
2659
|
+
) -> None:
|
|
2660
|
+
"""Checkout a branch with graduated deepening fallback.
|
|
2661
|
+
|
|
2662
|
+
If the initial checkout fails because the start_point SHA is not
|
|
2663
|
+
available (common in shallow clones), this method will:
|
|
2664
|
+
1. First try to deepen the repository (fetch 100 more commits)
|
|
2665
|
+
2. If that fails, fully unshallow the repository
|
|
2666
|
+
3. Retry the checkout after each attempt
|
|
2667
|
+
|
|
2668
|
+
This graduated approach minimizes performance impact for most cases
|
|
2669
|
+
while still handling edge cases where full history is needed.
|
|
2670
|
+
|
|
2671
|
+
Args:
|
|
2672
|
+
branch_name: Name of the branch to checkout or create
|
|
2673
|
+
start_point: The SHA or ref to start the branch from
|
|
2674
|
+
create_branch: If True, create a new branch (-b flag)
|
|
2675
|
+
|
|
2676
|
+
Raises:
|
|
2677
|
+
CommandError: If checkout fails even after unshallowing
|
|
2678
|
+
"""
|
|
2679
|
+
cmd = ["git", "checkout"]
|
|
2680
|
+
if create_branch:
|
|
2681
|
+
cmd.extend(["-b", branch_name, start_point])
|
|
2682
|
+
else:
|
|
2683
|
+
cmd.append(branch_name)
|
|
2684
|
+
|
|
2685
|
+
checkout_exc: CommandError | None = None
|
|
2686
|
+
try:
|
|
2687
|
+
run_cmd(cmd, cwd=self.workspace)
|
|
2688
|
+
except CommandError as exc:
|
|
2689
|
+
checkout_exc = exc
|
|
2690
|
+
|
|
2691
|
+
if checkout_exc is None:
|
|
2692
|
+
return # Success on first attempt
|
|
2693
|
+
|
|
2694
|
+
# Analyze the failure
|
|
2695
|
+
error_msg = str(checkout_exc).lower()
|
|
2696
|
+
# Check if failure is due to missing commit (shallow clone issue)
|
|
2697
|
+
is_missing_commit = (
|
|
2698
|
+
"not a commit" in error_msg
|
|
2699
|
+
or "cannot be created from" in error_msg
|
|
2700
|
+
or "bad revision" in error_msg
|
|
2701
|
+
or "unknown revision" in error_msg
|
|
2702
|
+
or "invalid reference" in error_msg
|
|
2703
|
+
)
|
|
2704
|
+
|
|
2705
|
+
if not is_missing_commit:
|
|
2706
|
+
# Not a shallow clone issue, re-raise immediately
|
|
2707
|
+
raise checkout_exc
|
|
2708
|
+
|
|
2709
|
+
log.warning(
|
|
2710
|
+
"Checkout failed, SHA %s not available in shallow clone. "
|
|
2711
|
+
"Attempting graduated deepening...",
|
|
2712
|
+
start_point,
|
|
2713
|
+
)
|
|
2714
|
+
|
|
2715
|
+
# Step 1: Try deepening first (cheaper than full unshallow)
|
|
2716
|
+
if self._deepen_repository(depth=100):
|
|
2717
|
+
log.debug("Retrying checkout after deepening...")
|
|
2718
|
+
try:
|
|
2719
|
+
run_cmd(cmd, cwd=self.workspace)
|
|
2720
|
+
except CommandError as deepen_exc:
|
|
2721
|
+
log.debug(
|
|
2722
|
+
"Checkout still failed after deepening: %s", deepen_exc
|
|
2723
|
+
)
|
|
2724
|
+
else:
|
|
2725
|
+
log.info("Checkout succeeded after deepening repository")
|
|
2726
|
+
return
|
|
2727
|
+
|
|
2728
|
+
# Step 2: Full unshallow as last resort
|
|
2729
|
+
log.info("Deepening insufficient, performing full unshallow...")
|
|
2730
|
+
if not self._unshallow_repository():
|
|
2731
|
+
log.error(
|
|
2732
|
+
"Failed to unshallow repository. Cannot checkout SHA: %s",
|
|
2733
|
+
start_point,
|
|
2734
|
+
)
|
|
2735
|
+
raise checkout_exc
|
|
2736
|
+
|
|
2737
|
+
# Retry the checkout after full unshallow
|
|
2738
|
+
log.debug("Retrying checkout after full unshallow...")
|
|
2739
|
+
run_cmd(cmd, cwd=self.workspace)
|
|
2740
|
+
log.info("Checkout succeeded after full unshallow")
|
|
2741
|
+
|
|
2742
|
+
def _merge_squash_with_unshallow_fallback(self, head_sha: str) -> None:
|
|
2743
|
+
"""Perform git merge --squash with graduated deepening fallback.
|
|
2744
|
+
|
|
2745
|
+
If the initial merge fails because the shallow clone lacks a common
|
|
2746
|
+
ancestor between the base and head (causing "refusing to merge
|
|
2747
|
+
unrelated histories"), this method will:
|
|
2748
|
+
1. First try to deepen the repository (fetch 100 more commits)
|
|
2749
|
+
2. If that fails, fully unshallow the repository
|
|
2750
|
+
3. Retry the merge after each attempt
|
|
2751
|
+
|
|
2752
|
+
This mirrors the graduated approach used by
|
|
2753
|
+
``_checkout_with_unshallow_fallback`` but for merge operations,
|
|
2754
|
+
which are equally susceptible to shallow clone limitations.
|
|
2755
|
+
|
|
2756
|
+
Args:
|
|
2757
|
+
head_sha: The SHA to merge (PR head commit)
|
|
2758
|
+
|
|
2759
|
+
Raises:
|
|
2760
|
+
CommandError: If merge fails even after unshallowing, or if
|
|
2761
|
+
the failure is not related to shallow clone history
|
|
2762
|
+
"""
|
|
2763
|
+
merge_cmd = ["git", "merge", "--squash", head_sha]
|
|
2764
|
+
|
|
2765
|
+
merge_exc: CommandError | None = None
|
|
2766
|
+
try:
|
|
2767
|
+
run_cmd(merge_cmd, cwd=self.workspace)
|
|
2768
|
+
except CommandError as exc:
|
|
2769
|
+
merge_exc = exc
|
|
2770
|
+
|
|
2771
|
+
if merge_exc is None:
|
|
2772
|
+
return # Success on first attempt
|
|
2773
|
+
|
|
2774
|
+
# Check if the failure is due to unrelated histories in a shallow clone
|
|
2775
|
+
error_str = str(merge_exc).lower()
|
|
2776
|
+
stderr_str = (merge_exc.stderr or "").lower()
|
|
2777
|
+
combined = f"{error_str} {stderr_str}"
|
|
2778
|
+
|
|
2779
|
+
is_unrelated_histories = (
|
|
2780
|
+
"refusing to merge unrelated histories" in combined
|
|
2781
|
+
or "unrelated histories" in combined
|
|
2782
|
+
or "no common ancestor" in combined
|
|
2783
|
+
)
|
|
2784
|
+
|
|
2785
|
+
if not is_unrelated_histories or not self._is_shallow_clone():
|
|
2786
|
+
# Not a shallow clone issue — let the caller handle the error
|
|
2787
|
+
raise merge_exc
|
|
2788
|
+
|
|
2789
|
+
log.warning(
|
|
2790
|
+
"Merge --squash failed due to unrelated histories in shallow "
|
|
2791
|
+
"clone. Attempting graduated deepening to recover..."
|
|
2792
|
+
)
|
|
2793
|
+
|
|
2794
|
+
# Step 1: Try deepening first (cheaper than full unshallow)
|
|
2795
|
+
if self._deepen_repository(depth=100):
|
|
2796
|
+
log.debug("Retrying merge --squash after deepening...")
|
|
2797
|
+
# Reset the failed merge state before retrying
|
|
2798
|
+
run_cmd(
|
|
2799
|
+
["git", "merge", "--abort"],
|
|
2800
|
+
cwd=self.workspace,
|
|
2801
|
+
check=False,
|
|
2802
|
+
)
|
|
2803
|
+
try:
|
|
2804
|
+
run_cmd(merge_cmd, cwd=self.workspace)
|
|
2805
|
+
except CommandError as deepen_exc:
|
|
2806
|
+
log.debug(
|
|
2807
|
+
"Merge --squash still failed after deepening: %s",
|
|
2808
|
+
deepen_exc,
|
|
2809
|
+
)
|
|
2810
|
+
# Re-check whether this is still a shallow-history problem;
|
|
2811
|
+
# if the error has changed (e.g. real merge conflict), an
|
|
2812
|
+
# expensive full unshallow cannot help — propagate immediately.
|
|
2813
|
+
deepen_combined = (
|
|
2814
|
+
f"{deepen_exc} {deepen_exc.stderr or ''}".lower()
|
|
2815
|
+
)
|
|
2816
|
+
deepen_is_unrelated = (
|
|
2817
|
+
"refusing to merge unrelated histories" in deepen_combined
|
|
2818
|
+
or "unrelated histories" in deepen_combined
|
|
2819
|
+
or "no common ancestor" in deepen_combined
|
|
2820
|
+
)
|
|
2821
|
+
if not deepen_is_unrelated:
|
|
2822
|
+
raise
|
|
2823
|
+
else:
|
|
2824
|
+
log.info("Merge --squash succeeded after deepening repository")
|
|
2825
|
+
return
|
|
2826
|
+
|
|
2827
|
+
# Step 2: Full unshallow as last resort
|
|
2828
|
+
log.info(
|
|
2829
|
+
"Deepening insufficient, performing full unshallow for merge..."
|
|
2830
|
+
)
|
|
2831
|
+
# Reset the failed merge state before retrying
|
|
2832
|
+
run_cmd(
|
|
2833
|
+
["git", "merge", "--abort"],
|
|
2834
|
+
cwd=self.workspace,
|
|
2835
|
+
check=False,
|
|
2836
|
+
)
|
|
2837
|
+
if not self._unshallow_repository():
|
|
2838
|
+
log.error(
|
|
2839
|
+
"Failed to unshallow repository. Cannot merge SHA: %s",
|
|
2840
|
+
head_sha,
|
|
2841
|
+
)
|
|
2842
|
+
raise merge_exc
|
|
2843
|
+
|
|
2844
|
+
# Retry the merge after full unshallow
|
|
2845
|
+
log.debug("Retrying merge --squash after full unshallow...")
|
|
2846
|
+
run_cmd(merge_cmd, cwd=self.workspace)
|
|
2847
|
+
log.info("Merge --squash succeeded after full unshallow")
|
|
2848
|
+
|
|
2578
2849
|
def _cleanup_ssh(self) -> None:
|
|
2579
2850
|
"""Clean up temporary SSH files created by this tool.
|
|
2580
2851
|
|
|
@@ -2787,8 +3058,10 @@ class Orchestrator:
|
|
|
2787
3058
|
).stdout.strip()
|
|
2788
3059
|
tmp_branch = f"g2g_tmp_{gh.pr_number or 'pr'!s}_{os.getpid()}"
|
|
2789
3060
|
os.environ["G2G_TMP_BRANCH"] = tmp_branch
|
|
2790
|
-
|
|
2791
|
-
|
|
3061
|
+
self._checkout_with_unshallow_fallback(
|
|
3062
|
+
branch_name=tmp_branch,
|
|
3063
|
+
start_point=base_sha,
|
|
3064
|
+
create_branch=True,
|
|
2792
3065
|
)
|
|
2793
3066
|
change_ids: list[str] = []
|
|
2794
3067
|
for idx, csha in enumerate(commit_list):
|
|
@@ -2937,9 +3210,20 @@ class Orchestrator:
|
|
|
2937
3210
|
|
|
2938
3211
|
except Exception as debug_exc:
|
|
2939
3212
|
log.warning("Failed to analyze merge situation: %s", debug_exc)
|
|
3213
|
+
# Proactively deepen if merge-base fails in a shallow clone,
|
|
3214
|
+
# as this strongly indicates the shallow history is insufficient
|
|
3215
|
+
# for the upcoming merge --squash operation.
|
|
3216
|
+
if self._is_shallow_clone():
|
|
3217
|
+
log.info(
|
|
3218
|
+
"merge-base failed in shallow clone — proactively "
|
|
3219
|
+
"deepening repository to improve merge success chances"
|
|
3220
|
+
)
|
|
3221
|
+
self._deepen_repository(depth=100)
|
|
2940
3222
|
|
|
2941
|
-
|
|
2942
|
-
|
|
3223
|
+
self._checkout_with_unshallow_fallback(
|
|
3224
|
+
branch_name=tmp_branch,
|
|
3225
|
+
start_point=base_sha,
|
|
3226
|
+
create_branch=True,
|
|
2943
3227
|
)
|
|
2944
3228
|
|
|
2945
3229
|
# Show git status before attempting merge
|
|
@@ -2966,7 +3250,7 @@ class Orchestrator:
|
|
|
2966
3250
|
|
|
2967
3251
|
log.debug("About to run: git merge --squash %s", head_sha)
|
|
2968
3252
|
try:
|
|
2969
|
-
|
|
3253
|
+
self._merge_squash_with_unshallow_fallback(head_sha)
|
|
2970
3254
|
except CommandError as merge_exc:
|
|
2971
3255
|
# Enhanced error handling for git merge failures
|
|
2972
3256
|
error_details = self._analyze_merge_failure(
|
|
@@ -1492,6 +1492,16 @@ def cleanup_closed_github_prs(
|
|
|
1492
1492
|
)
|
|
1493
1493
|
continue
|
|
1494
1494
|
|
|
1495
|
+
except GerritRestError as exc:
|
|
1496
|
+
# Wrap in GitHub2GerritError to ensure SSL/connection errors
|
|
1497
|
+
# fail the workflow
|
|
1498
|
+
log.exception("Failed to perform Gerrit cleanup for closed GitHub PRs")
|
|
1499
|
+
raise GitHub2GerritError(
|
|
1500
|
+
ExitCode.GERRIT_CONNECTION_ERROR,
|
|
1501
|
+
message="❌ Gerrit REST API error during cleanup",
|
|
1502
|
+
details=str(exc),
|
|
1503
|
+
original_exception=exc,
|
|
1504
|
+
) from exc
|
|
1495
1505
|
except Exception:
|
|
1496
1506
|
log.exception("Failed to perform Gerrit cleanup for closed GitHub PRs")
|
|
1497
1507
|
return 0
|
|
@@ -51,8 +51,8 @@ _LOGGER_NAME = "github2gerrit.git"
|
|
|
51
51
|
log = logging.getLogger(_LOGGER_NAME)
|
|
52
52
|
if not log.handlers:
|
|
53
53
|
# Provide a minimal default if the app has not configured logging.
|
|
54
|
-
level_name = os.getenv("G2G_LOG_LEVEL", "
|
|
55
|
-
level = getattr(logging, level_name, logging.
|
|
54
|
+
level_name = os.getenv("G2G_LOG_LEVEL", "WARNING").upper()
|
|
55
|
+
level = getattr(logging, level_name, logging.WARNING)
|
|
56
56
|
fmt = (
|
|
57
57
|
"%(asctime)s %(levelname)-8s %(name)s %(filename)s:%(lineno)d | "
|
|
58
58
|
"%(message)s"
|
|
@@ -44,27 +44,6 @@ _MULTIPLE_NEWLINES_PATTERN = re.compile(r"\n{3,}")
|
|
|
44
44
|
_EMOJI_PATTERN = re.compile(r":[a-z_]+:") # GitHub emoji codes like :sparkles:
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
@dataclass
|
|
48
|
-
class FilterConfig:
|
|
49
|
-
"""Configuration for PR content filtering."""
|
|
50
|
-
|
|
51
|
-
# Global options
|
|
52
|
-
enabled: bool = True
|
|
53
|
-
remove_emoji_codes: bool = True
|
|
54
|
-
deduplicate_title_in_body: bool = True
|
|
55
|
-
|
|
56
|
-
# Author-specific filtering
|
|
57
|
-
author_rules: dict[str, str] = field(default_factory=dict)
|
|
58
|
-
|
|
59
|
-
# Rule-specific configurations
|
|
60
|
-
dependabot_config: DependabotConfig = field(
|
|
61
|
-
default_factory=lambda: DependabotConfig()
|
|
62
|
-
)
|
|
63
|
-
precommit_config: PrecommitConfig = field(
|
|
64
|
-
default_factory=lambda: PrecommitConfig()
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
|
|
68
47
|
@dataclass
|
|
69
48
|
class DependabotConfig:
|
|
70
49
|
"""Configuration for Dependabot PR filtering."""
|
|
@@ -85,6 +64,25 @@ class PrecommitConfig:
|
|
|
85
64
|
# Future: add pre-commit.ci specific options
|
|
86
65
|
|
|
87
66
|
|
|
67
|
+
@dataclass
|
|
68
|
+
class FilterConfig:
|
|
69
|
+
"""Configuration for PR content filtering."""
|
|
70
|
+
|
|
71
|
+
# Global options
|
|
72
|
+
enabled: bool = True
|
|
73
|
+
remove_emoji_codes: bool = True
|
|
74
|
+
deduplicate_title_in_body: bool = True
|
|
75
|
+
|
|
76
|
+
# Author-specific filtering
|
|
77
|
+
author_rules: dict[str, str] = field(default_factory=dict)
|
|
78
|
+
|
|
79
|
+
# Rule-specific configurations
|
|
80
|
+
dependabot_config: DependabotConfig = field(
|
|
81
|
+
default_factory=DependabotConfig
|
|
82
|
+
)
|
|
83
|
+
precommit_config: PrecommitConfig = field(default_factory=PrecommitConfig)
|
|
84
|
+
|
|
85
|
+
|
|
88
86
|
class FilterRule(ABC):
|
|
89
87
|
"""Abstract base class for PR content filtering rules."""
|
|
90
88
|
|
|
@@ -63,9 +63,17 @@ def is_verbose_mode() -> bool:
|
|
|
63
63
|
"""Check if verbose mode is enabled via environment variable.
|
|
64
64
|
|
|
65
65
|
Returns:
|
|
66
|
-
True if G2G_VERBOSE environment variable is set to a truthy value
|
|
66
|
+
True if G2G_VERBOSE environment variable is set to a truthy value,
|
|
67
|
+
or if GitHub Actions debug mode is enabled (RUNNER_DEBUG=1 or
|
|
68
|
+
ACTIONS_STEP_DEBUG=true)
|
|
67
69
|
"""
|
|
68
|
-
|
|
70
|
+
if os.getenv("G2G_VERBOSE", "").lower() in ("true", "1", "yes"):
|
|
71
|
+
return True
|
|
72
|
+
# GitHub Actions sets RUNNER_DEBUG=1 when re-running with debug logging
|
|
73
|
+
if os.getenv("RUNNER_DEBUG", "") == "1":
|
|
74
|
+
return True
|
|
75
|
+
# GitHub Actions also sets ACTIONS_STEP_DEBUG=true for step-level debugging
|
|
76
|
+
return os.getenv("ACTIONS_STEP_DEBUG", "").lower() == "true"
|
|
69
77
|
|
|
70
78
|
|
|
71
79
|
def log_exception_conditionally(
|
|
@@ -275,7 +275,7 @@ Change-Id: {reused_change_id}
|
|
|
275
275
|
monkeypatch.setattr("github2gerrit.core.run_cmd", mock_run_cmd)
|
|
276
276
|
|
|
277
277
|
# Mock GitHub API for Change-ID reuse
|
|
278
|
-
monkeypatch.setattr("github2gerrit.core.build_client",
|
|
278
|
+
monkeypatch.setattr("github2gerrit.core.build_client", object)
|
|
279
279
|
monkeypatch.setattr(
|
|
280
280
|
"github2gerrit.core.get_repo_from_env", lambda _: object()
|
|
281
281
|
)
|
|
@@ -232,7 +232,7 @@ def test_multi_pr_url_mode_writes_aggregated_outputs(
|
|
|
232
232
|
def __init__(self, number: int) -> None:
|
|
233
233
|
self.number = number
|
|
234
234
|
|
|
235
|
-
monkeypatch.setattr(cli_mod, "build_client",
|
|
235
|
+
monkeypatch.setattr(cli_mod, "build_client", object)
|
|
236
236
|
monkeypatch.setattr(cli_mod, "get_repo_from_env", lambda _client: object())
|
|
237
237
|
monkeypatch.setattr(
|
|
238
238
|
cli_mod,
|
|
@@ -168,7 +168,7 @@ def test_repo_url_dry_run_invokes_for_each_open_pr(
|
|
|
168
168
|
monkeypatch.setattr(cli_mod, "Orchestrator", _DummyOrchestrator)
|
|
169
169
|
|
|
170
170
|
# Patch PyGithub wrapper functions used by CLI bulk path
|
|
171
|
-
monkeypatch.setattr(cli_mod, "build_client",
|
|
171
|
+
monkeypatch.setattr(cli_mod, "build_client", object)
|
|
172
172
|
monkeypatch.setattr(cli_mod, "get_repo_from_env", lambda _client: object())
|
|
173
173
|
monkeypatch.setattr(
|
|
174
174
|
cli_mod, "iter_open_pulls", lambda _repo: iter(dummy_prs)
|
|
@@ -212,7 +212,7 @@ def test_url_mode_sets_environment_for_config_resolution(
|
|
|
212
212
|
monkeypatch.setattr(cli_mod, "Orchestrator", _DummyOrchestrator)
|
|
213
213
|
|
|
214
214
|
# Minimal patches for bulk flow
|
|
215
|
-
monkeypatch.setattr(cli_mod, "build_client",
|
|
215
|
+
monkeypatch.setattr(cli_mod, "build_client", object)
|
|
216
216
|
monkeypatch.setattr(cli_mod, "get_repo_from_env", lambda _client: object())
|
|
217
217
|
monkeypatch.setattr(
|
|
218
218
|
cli_mod,
|
|
@@ -102,9 +102,7 @@ def test_close_pr_invoked_for_pull_request_target_event(
|
|
|
102
102
|
self.closed_state: str | None = None
|
|
103
103
|
|
|
104
104
|
# Patch the GitHub helper functions used by the close path
|
|
105
|
-
monkeypatch.setattr(
|
|
106
|
-
"github2gerrit.core.build_client", lambda: DummyClient()
|
|
107
|
-
)
|
|
105
|
+
monkeypatch.setattr("github2gerrit.core.build_client", DummyClient)
|
|
108
106
|
monkeypatch.setattr(
|
|
109
107
|
"github2gerrit.core.get_repo_from_env", lambda _c: DummyRepo()
|
|
110
108
|
)
|
|
@@ -237,7 +237,7 @@ def test_prepare_squashed_commit_reuses_change_id_from_comments(
|
|
|
237
237
|
monkeypatch.setattr("github2gerrit.core.run_cmd", fake_run_cmd)
|
|
238
238
|
|
|
239
239
|
# GitHub API helpers used to fetch PR comments
|
|
240
|
-
monkeypatch.setattr("github2gerrit.core.build_client",
|
|
240
|
+
monkeypatch.setattr("github2gerrit.core.build_client", object)
|
|
241
241
|
monkeypatch.setattr(
|
|
242
242
|
"github2gerrit.core.get_repo_from_env", lambda _c: object()
|
|
243
243
|
)
|