github2gerrit 1.3.1__tar.gz → 1.3.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.
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/PKG-INFO +1 -1
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/sitecustomize.py +6 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/cli.py +16 -4
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/core.py +0 -17
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/duplicate_detection.py +0 -9
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/external_api.py +2 -2
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/gerrit_rest.py +0 -13
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/github_api.py +22 -12
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/gitreview.py +0 -5
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/gitutils.py +2 -1
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/ssh_discovery.py +0 -1
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_external_api_framework.py +2 -2
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_gitutils_helpers.py +6 -4
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/.editorconfig +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/.gitignore +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/.gitlint +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/.markdownlint.yaml +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/.pre-commit-config.yaml +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/.readthedocs.yml +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/.yamllint +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/LICENSE +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/LICENSES/Apache-2.0.txt +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/README.md +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/REUSE.toml +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/SECURITY.md +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/action.yaml +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/docs/COMMIT_RULES.md +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/docs/COMPOSITE_ACTION_TESTING.md +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/docs/PR_UPDATE_IMPLEMENTATION.md +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/docs/RELEASE-v0.2.0.md +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/docs/github2gerrit_token_permissions_classic.png +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/pyproject.toml +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/__init__.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/commit_normalization.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/commit_rules.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/config.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/constants.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/error_codes.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/gerrit_pr_closer.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/gerrit_query.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/gerrit_ssh.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/gerrit_urls.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/mapping_comment.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/models.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/netrc.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/orchestrator/__init__.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/orchestrator/reconciliation.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/pr_commands.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/pr_content_filter.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/reconcile_matcher.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/rich_display.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/rich_logging.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/similarity.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/ssh_agent_setup.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/ssh_common.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/ssh_config_parser.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/trailers.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/utils.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/conftest.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/fixtures/__init__.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/fixtures/make_repo.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/fixtures/ssh_config_samples.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_action_environment_mapping.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_action_outputs.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_action_pr_number_handling.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_action_step_validation.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_automation_only.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_change_id_deduplication.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_clean_squash_title.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_cli.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_cli_helpers.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_cli_netrc_options.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_cli_outputs_file.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_cli_url_and_dryrun.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_commit_normalization.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_commit_rules.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_composite_action_coverage.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_config_and_reviewers.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_config_helpers.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_core_close_pr_policy.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_core_config_and_errors.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_core_gerrit_backref_comment.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_core_gerrit_push_errors.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_core_gerrit_rest_results.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_core_integration_fixture_repo.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_core_prepare_commits.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_core_shallow_clone.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_core_ssh_setup.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_core_ssrf_protection.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_dependency_supersession.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_dns_validation_and_no_gerrit.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_duplicate_detection.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_email_case_normalization.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_error_codes.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_force_flag_cli.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_gerrit_change_id_footer.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_gerrit_change_status_checks.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_gerrit_pr_closer.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_gerrit_rest_client.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_gerrit_ssh_abandon.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_gerrit_urls.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_gerrit_urls_more.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_ghe_and_gitreview_args.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_github_api_error_handling.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_github_api_helpers.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_github_api_retry_and_helpers.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_gitreview.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_issue_157_regressions.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_mapping_comment_additional.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_mapping_comment_digest_and_backref.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_metadata_and_reconciliation.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_metadata_trailer_separation_bug.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_misc_small_coverage.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_netrc.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_orphan_rest_side_effects.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_pr_commands.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_pr_content_filter.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_pr_content_filter_integration.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_pr_update_detection.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_reconciliation_extracted_module.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_reconciliation_plan_and_orphans.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_reconciliation_scenarios.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_ssh_agent.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_ssh_agent_ownership.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_ssh_artifact_prevention.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_ssh_common.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_ssh_discovery.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_ssh_discovery_dry_run.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_trailers_additional.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_url_parser.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_utils.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/unit/test_config_integration.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/unit/test_ssh_config_parser.py +0 -0
- {github2gerrit-1.3.1 → github2gerrit-1.3.2}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github2gerrit
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.2
|
|
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
|
|
@@ -57,6 +57,8 @@ def _dbg(msg: str) -> None:
|
|
|
57
57
|
try:
|
|
58
58
|
print(f"[sitecustomize] {msg}", file=sys.stderr)
|
|
59
59
|
except Exception:
|
|
60
|
+
# Debug logging must never disrupt interpreter startup; if
|
|
61
|
+
# writing to stderr fails, silently drop the message.
|
|
60
62
|
pass
|
|
61
63
|
|
|
62
64
|
|
|
@@ -125,6 +127,8 @@ def _collect_base_dirs(repo_root: Path) -> set[Path]:
|
|
|
125
127
|
try:
|
|
126
128
|
bases.add(Path.cwd())
|
|
127
129
|
except Exception:
|
|
130
|
+
# CWD may be unavailable (e.g. deleted); skip it and continue
|
|
131
|
+
# collecting the remaining base directories.
|
|
128
132
|
pass
|
|
129
133
|
# Repository root (directory containing this file)
|
|
130
134
|
bases.add(repo_root)
|
|
@@ -134,6 +138,8 @@ def _collect_base_dirs(repo_root: Path) -> set[Path]:
|
|
|
134
138
|
try:
|
|
135
139
|
bases.add(Path(gw))
|
|
136
140
|
except Exception:
|
|
141
|
+
# A malformed GITHUB_WORKSPACE value should not abort cleanup;
|
|
142
|
+
# skip it and continue with the other base directories.
|
|
137
143
|
pass
|
|
138
144
|
return bases
|
|
139
145
|
|
|
@@ -385,12 +385,15 @@ else:
|
|
|
385
385
|
|
|
386
386
|
|
|
387
387
|
class _FormatterProto(Protocol):
|
|
388
|
-
def write_usage(self, prog: str, args: str, prefix: str = ...) -> None:
|
|
388
|
+
def write_usage(self, prog: str, args: str, prefix: str = ...) -> None:
|
|
389
|
+
"""Write the program usage line."""
|
|
389
390
|
|
|
390
391
|
|
|
391
392
|
class _ContextProto(Protocol):
|
|
392
393
|
@property
|
|
393
|
-
def command_path(self) -> str:
|
|
394
|
+
def command_path(self) -> str:
|
|
395
|
+
"""Return the full command path."""
|
|
396
|
+
raise NotImplementedError
|
|
394
397
|
|
|
395
398
|
|
|
396
399
|
class _SingleUsageGroup(BaseGroup):
|
|
@@ -471,14 +474,23 @@ def _resolve_issue_id_from_json(json_str: str, github_actor: str) -> str:
|
|
|
471
474
|
return ""
|
|
472
475
|
|
|
473
476
|
|
|
474
|
-
|
|
475
|
-
|
|
477
|
+
def _print_version_banner() -> None:
|
|
478
|
+
"""Print the resolved package version, or a fallback notice.
|
|
479
|
+
|
|
480
|
+
Defined as a function so the ``print`` calls do not execute at module
|
|
481
|
+
scope during import; the banner is only emitted when explicitly invoked.
|
|
482
|
+
"""
|
|
476
483
|
try:
|
|
477
484
|
app_version = get_version("github2gerrit")
|
|
478
485
|
print(f"🏷️ github2gerrit version {app_version}")
|
|
479
486
|
except Exception:
|
|
480
487
|
print("⚠️ github2gerrit version information not available")
|
|
481
488
|
|
|
489
|
+
|
|
490
|
+
# Show version information when --help is used or in GitHub Actions mode
|
|
491
|
+
if "--help" in sys.argv or _is_github_actions_context():
|
|
492
|
+
_print_version_banner()
|
|
493
|
+
|
|
482
494
|
app: typer.Typer = typer.Typer(
|
|
483
495
|
add_completion=False,
|
|
484
496
|
no_args_is_help=False,
|
|
@@ -80,19 +80,10 @@ from .utils import is_verbose_mode
|
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
try:
|
|
83
|
-
from pygerrit2 import GerritRestAPI
|
|
84
|
-
from pygerrit2 import HTTPBasicAuth
|
|
85
|
-
except ImportError:
|
|
86
|
-
GerritRestAPI = None
|
|
87
|
-
HTTPBasicAuth = None
|
|
88
|
-
|
|
89
|
-
try:
|
|
90
|
-
from .ssh_discovery import SSHDiscoveryError
|
|
91
83
|
from .ssh_discovery import auto_discover_gerrit_host_keys
|
|
92
84
|
except ImportError:
|
|
93
85
|
# Fallback if ssh_discovery module is not available
|
|
94
86
|
auto_discover_gerrit_host_keys = None # type: ignore[assignment]
|
|
95
|
-
SSHDiscoveryError = Exception # type: ignore[misc,assignment]
|
|
96
87
|
|
|
97
88
|
try:
|
|
98
89
|
from .ssh_agent_setup import SSHAgentManager
|
|
@@ -113,7 +104,6 @@ log = logging.getLogger("github2gerrit.core")
|
|
|
113
104
|
|
|
114
105
|
|
|
115
106
|
# Error message constants to comply with TRY003
|
|
116
|
-
_MSG_ISSUE_ID_MULTILINE = "Issue ID must be single line"
|
|
117
107
|
_MSG_MISSING_PR_CONTEXT = "missing PR context"
|
|
118
108
|
_MSG_BAD_REPOSITORY_CONTEXT = "bad repository context"
|
|
119
109
|
_MSG_MISSING_GERRIT_SERVER = (
|
|
@@ -121,10 +111,6 @@ _MSG_MISSING_GERRIT_SERVER = (
|
|
|
121
111
|
"input/environment variable, .gitreview file, or action configuration."
|
|
122
112
|
)
|
|
123
113
|
_MSG_MISSING_GERRIT_PROJECT = "missing GERRIT_PROJECT"
|
|
124
|
-
_MSG_PYGERRIT2_REQUIRED_REST = "pygerrit2 is required to query Gerrit REST API"
|
|
125
|
-
_MSG_PYGERRIT2_REQUIRED_AUTH = "pygerrit2 is required for HTTP authentication"
|
|
126
|
-
_MSG_PYGERRIT2_MISSING = "pygerrit2 missing"
|
|
127
|
-
_MSG_PYGERRIT2_AUTH_MISSING = "pygerrit2 auth missing"
|
|
128
114
|
_MSG_DNS_RESOLUTION_FAILED = "DNS resolution failed for '%s'"
|
|
129
115
|
|
|
130
116
|
|
|
@@ -4429,7 +4415,6 @@ class Orchestrator:
|
|
|
4429
4415
|
List of email addresses that were not found in Gerrit
|
|
4430
4416
|
"""
|
|
4431
4417
|
combined_output = f"{exc.stdout}\n{exc.stderr}"
|
|
4432
|
-
import re
|
|
4433
4418
|
|
|
4434
4419
|
# Pattern to match: Account 'email@domain.com' not found
|
|
4435
4420
|
pattern = r"Account\s+'([^']+)'\s+not\s+found"
|
|
@@ -4903,7 +4888,6 @@ class Orchestrator:
|
|
|
4903
4888
|
# Extract specific rejection reason from output
|
|
4904
4889
|
# Handle multiline rejection messages by looking in normalized
|
|
4905
4890
|
# output
|
|
4906
|
-
import re
|
|
4907
4891
|
|
|
4908
4892
|
# Look for the rejection pattern in the normalized output
|
|
4909
4893
|
rejection_match = re.search(
|
|
@@ -5299,7 +5283,6 @@ class Orchestrator:
|
|
|
5299
5283
|
self, workspace: Path, gh: GitHubContext, inputs: Inputs
|
|
5300
5284
|
) -> None:
|
|
5301
5285
|
"""Fallback to GitHub API archive download (ported from CLI)."""
|
|
5302
|
-
import json
|
|
5303
5286
|
import zipfile
|
|
5304
5287
|
|
|
5305
5288
|
repo_full = gh.repository.strip() if gh.repository else ""
|
|
@@ -32,15 +32,6 @@ from .rich_display import safe_console_print
|
|
|
32
32
|
from .trailers import extract_github_metadata
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
# Optional Gerrit REST API support
|
|
36
|
-
try:
|
|
37
|
-
from pygerrit2 import GerritRestAPI
|
|
38
|
-
from pygerrit2 import HTTPBasicAuth
|
|
39
|
-
except ImportError:
|
|
40
|
-
GerritRestAPI = None
|
|
41
|
-
HTTPBasicAuth = None
|
|
42
|
-
|
|
43
|
-
|
|
44
35
|
log = logging.getLogger(__name__)
|
|
45
36
|
|
|
46
37
|
__all__ = [
|
|
@@ -327,7 +327,7 @@ def external_api_call(
|
|
|
327
327
|
policy=policy,
|
|
328
328
|
)
|
|
329
329
|
|
|
330
|
-
last_exc:
|
|
330
|
+
last_exc: Exception | None = None
|
|
331
331
|
|
|
332
332
|
for attempt in range(1, policy.max_attempts + 1):
|
|
333
333
|
context.attempt = attempt
|
|
@@ -347,7 +347,7 @@ def external_api_call(
|
|
|
347
347
|
|
|
348
348
|
# Call the actual function
|
|
349
349
|
result = func(*args, **kwargs)
|
|
350
|
-
except
|
|
350
|
+
except Exception as exc:
|
|
351
351
|
last_exc = exc
|
|
352
352
|
duration = time.time() - context.start_time
|
|
353
353
|
|
|
@@ -68,19 +68,6 @@ _MSG_PYGERRIT2_REQUIRED_AUTH: Final[str] = (
|
|
|
68
68
|
"pygerrit2 is required for HTTP authentication"
|
|
69
69
|
)
|
|
70
70
|
|
|
71
|
-
_TRANSIENT_ERR_SUBSTRINGS: Final[tuple[str, ...]] = (
|
|
72
|
-
"timed out",
|
|
73
|
-
"temporarily unavailable",
|
|
74
|
-
"temporary failure",
|
|
75
|
-
"connection reset",
|
|
76
|
-
"connection aborted",
|
|
77
|
-
"broken pipe",
|
|
78
|
-
"connection refused",
|
|
79
|
-
"bad gateway",
|
|
80
|
-
"service unavailable",
|
|
81
|
-
"gateway timeout",
|
|
82
|
-
)
|
|
83
|
-
|
|
84
71
|
# HTTP status codes that indicate an authentication/authorization problem
|
|
85
72
|
# rather than a transient fault or a bug. These are expected when no
|
|
86
73
|
# Gerrit REST credentials are available (or they are insufficient for the
|
|
@@ -23,7 +23,6 @@ from collections.abc import Iterable
|
|
|
23
23
|
from importlib import import_module
|
|
24
24
|
from typing import Any
|
|
25
25
|
from typing import Protocol
|
|
26
|
-
from typing import TypeVar
|
|
27
26
|
from typing import cast
|
|
28
27
|
|
|
29
28
|
from .error_codes import ExitCode
|
|
@@ -35,8 +34,6 @@ from .external_api import external_api_call
|
|
|
35
34
|
|
|
36
35
|
# Error message constants to comply with TRY003
|
|
37
36
|
_MSG_PYGITHUB_REQUIRED = "PyGithub required"
|
|
38
|
-
_MSG_MISSING_GITHUB_TOKEN = "missing GITHUB_TOKEN" # noqa: S105
|
|
39
|
-
_MSG_BAD_GITHUB_REPOSITORY = "bad GITHUB_REPOSITORY"
|
|
40
37
|
|
|
41
38
|
|
|
42
39
|
class GithubExceptionType(Exception):
|
|
@@ -82,8 +79,12 @@ class GhIssueComment(Protocol):
|
|
|
82
79
|
|
|
83
80
|
|
|
84
81
|
class GhIssue(Protocol):
|
|
85
|
-
def get_comments(self) -> Iterable[GhIssueComment]:
|
|
86
|
-
|
|
82
|
+
def get_comments(self) -> Iterable[GhIssueComment]:
|
|
83
|
+
"""Return the comments on the issue."""
|
|
84
|
+
raise NotImplementedError
|
|
85
|
+
|
|
86
|
+
def create_comment(self, body: str) -> None:
|
|
87
|
+
"""Create a new comment on the issue."""
|
|
87
88
|
|
|
88
89
|
|
|
89
90
|
class GhPullRequest(Protocol):
|
|
@@ -91,17 +92,28 @@ class GhPullRequest(Protocol):
|
|
|
91
92
|
title: str | None
|
|
92
93
|
body: str | None
|
|
93
94
|
|
|
94
|
-
def as_issue(self) -> GhIssue:
|
|
95
|
-
|
|
95
|
+
def as_issue(self) -> GhIssue:
|
|
96
|
+
"""Return the issue view of this pull request."""
|
|
97
|
+
raise NotImplementedError
|
|
98
|
+
|
|
99
|
+
def edit(self, *, state: str) -> None:
|
|
100
|
+
"""Edit the pull request state."""
|
|
96
101
|
|
|
97
102
|
|
|
98
103
|
class GhRepository(Protocol):
|
|
99
|
-
def get_pull(self, number: int) -> GhPullRequest:
|
|
100
|
-
|
|
104
|
+
def get_pull(self, number: int) -> GhPullRequest:
|
|
105
|
+
"""Return the pull request with the given number."""
|
|
106
|
+
raise NotImplementedError
|
|
107
|
+
|
|
108
|
+
def get_pulls(self, state: str) -> Iterable[GhPullRequest]:
|
|
109
|
+
"""Return the pull requests with the given state."""
|
|
110
|
+
raise NotImplementedError
|
|
101
111
|
|
|
102
112
|
|
|
103
113
|
class GhClient(Protocol):
|
|
104
|
-
def get_repo(self, full: str) -> GhRepository:
|
|
114
|
+
def get_repo(self, full: str) -> GhRepository:
|
|
115
|
+
"""Return the repository for the given full name."""
|
|
116
|
+
raise NotImplementedError
|
|
105
117
|
|
|
106
118
|
|
|
107
119
|
__all__ = [
|
|
@@ -120,8 +132,6 @@ __all__ = [
|
|
|
120
132
|
|
|
121
133
|
log = logging.getLogger("github2gerrit.github_api")
|
|
122
134
|
|
|
123
|
-
_T = TypeVar("_T")
|
|
124
|
-
|
|
125
135
|
|
|
126
136
|
def _getenv_str(name: str) -> str:
|
|
127
137
|
val = os.getenv(name, "")
|
|
@@ -151,11 +151,6 @@ def derive_base_path(host: str) -> str | None:
|
|
|
151
151
|
return _KNOWN_BASE_PATHS.get(host.lower().strip())
|
|
152
152
|
|
|
153
153
|
|
|
154
|
-
# Keep a private alias so internal callers don't break if they were
|
|
155
|
-
# referencing the underscore-prefixed name during development.
|
|
156
|
-
_derive_base_path = derive_base_path
|
|
157
|
-
|
|
158
|
-
|
|
159
154
|
# ───────────────────────────────────────────────────────────────────────
|
|
160
155
|
# Pure parser
|
|
161
156
|
# ───────────────────────────────────────────────────────────────────────
|
|
@@ -555,6 +555,8 @@ def git_commit_amend(
|
|
|
555
555
|
if committer_email and _has_committer_signoff(body):
|
|
556
556
|
effective_signoff = False
|
|
557
557
|
except GitError:
|
|
558
|
+
# Unable to read the current commit body (e.g. no HEAD yet);
|
|
559
|
+
# fall back to honoring the requested signoff setting.
|
|
558
560
|
pass
|
|
559
561
|
except Exception:
|
|
560
562
|
# Best effort only; default to requested signoff
|
|
@@ -613,7 +615,6 @@ def git_commit_new(
|
|
|
613
615
|
_tf.flush()
|
|
614
616
|
tmp_path = Path(_tf.name)
|
|
615
617
|
message_file = tmp_path
|
|
616
|
-
message = None
|
|
617
618
|
|
|
618
619
|
# Determine whether to add -s; only suppress if message already has a
|
|
619
620
|
# sign-off for current committer
|
|
@@ -379,7 +379,6 @@ def save_host_keys_to_config(
|
|
|
379
379
|
new_lines.append(f"[{organization}]")
|
|
380
380
|
escaped_keys = host_keys.replace("\n", "\\n")
|
|
381
381
|
new_lines.append(f'GERRIT_KNOWN_HOSTS = "{escaped_keys}"')
|
|
382
|
-
gerrit_known_hosts_updated = True
|
|
383
382
|
|
|
384
383
|
# If section existed but didn't have GERRIT_KNOWN_HOSTS, add it
|
|
385
384
|
elif not gerrit_known_hosts_updated:
|
|
@@ -222,6 +222,8 @@ def test_curl_download_success(
|
|
|
222
222
|
output_path = Path(cmd[o_index + 1])
|
|
223
223
|
output_path.write_text("downloaded content")
|
|
224
224
|
except (ValueError, IndexError):
|
|
225
|
+
# No "-o" flag (or no value after it) in the mocked curl
|
|
226
|
+
# command; nothing to write, so behave like a no-op download.
|
|
225
227
|
pass
|
|
226
228
|
return MockCompletedProcess()
|
|
227
229
|
|
|
@@ -278,8 +280,6 @@ def test_log_api_metrics_summary(
|
|
|
278
280
|
monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture
|
|
279
281
|
) -> None:
|
|
280
282
|
"""Test API metrics summary logging."""
|
|
281
|
-
import logging
|
|
282
|
-
|
|
283
283
|
# Set up some metrics
|
|
284
284
|
reset_api_metrics()
|
|
285
285
|
|
|
@@ -222,7 +222,7 @@ def test_git_last_commit_trailers_parsing_edge_cases(
|
|
|
222
222
|
) -> None:
|
|
223
223
|
# Patch git_show to return a crafted commit message body with various
|
|
224
224
|
# trailer forms.
|
|
225
|
-
|
|
225
|
+
from github2gerrit.gitutils import git_last_commit_trailers
|
|
226
226
|
|
|
227
227
|
body = (
|
|
228
228
|
"Subject line\n\n"
|
|
@@ -235,10 +235,12 @@ def test_git_last_commit_trailers_parsing_edge_cases(
|
|
|
235
235
|
"Change-Id: Iabc123abc123abc123abc123abc123abc123ab\n"
|
|
236
236
|
)
|
|
237
237
|
|
|
238
|
-
monkeypatch.setattr(
|
|
238
|
+
monkeypatch.setattr(
|
|
239
|
+
"github2gerrit.gitutils.git_show", lambda rev, **kw: body
|
|
240
|
+
)
|
|
239
241
|
|
|
240
242
|
# Without filter: expect only proper footer trailers collected.
|
|
241
|
-
trailers_all =
|
|
243
|
+
trailers_all = git_last_commit_trailers()
|
|
242
244
|
# Body "Key:" lines should not be extracted as trailers
|
|
243
245
|
assert "Key" not in trailers_all
|
|
244
246
|
# 'Empty' should be ignored due to empty value
|
|
@@ -254,7 +256,7 @@ def test_git_last_commit_trailers_parsing_edge_cases(
|
|
|
254
256
|
]
|
|
255
257
|
|
|
256
258
|
# With filter keys: only Change-Id should be returned.
|
|
257
|
-
trailers_change =
|
|
259
|
+
trailers_change = git_last_commit_trailers(keys=["Change-Id"])
|
|
258
260
|
assert list(trailers_change.keys()) == ["Change-Id"]
|
|
259
261
|
assert trailers_change["Change-Id"] == [
|
|
260
262
|
"Ideadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{github2gerrit-1.3.1 → github2gerrit-1.3.2}/docs/github2gerrit_token_permissions_classic.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{github2gerrit-1.3.1 → github2gerrit-1.3.2}/src/github2gerrit/orchestrator/reconciliation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{github2gerrit-1.3.1 → github2gerrit-1.3.2}/tests/test_mapping_comment_digest_and_backref.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|