github2gerrit 0.1.12__tar.gz → 0.1.14__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-0.1.12 → github2gerrit-0.1.14}/PKG-INFO +1 -1
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/action.yaml +8 -2
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/cli.py +1 -1
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/core.py +66 -12
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/ssh_discovery.py +131 -9
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_action_step_validation.py +4 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/.editorconfig +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/.gitignore +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/.gitlint +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/.markdownlint.yaml +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/.pre-commit-config.yaml +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/.readthedocs.yml +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/.yamllint +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/LICENSE +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/LICENSES/Apache-2.0.txt +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/README.md +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/REUSE.toml +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/REVISION_PLAN.md +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/docs/COMPOSITE_ACTION_TESTING.md +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/docs/github2gerrit_token_permissions_classic.png +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/pyproject.toml +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/sitecustomize.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/__init__.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/commit_normalization.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/config.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/duplicate_detection.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/external_api.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/gerrit_query.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/gerrit_rest.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/gerrit_urls.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/github_api.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/gitutils.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/mapping_comment.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/models.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/orchestrator/__init__.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/orchestrator/reconciliation.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/pr_content_filter.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/reconcile_matcher.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/rich_display.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/rich_logging.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/similarity.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/ssh_agent_setup.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/ssh_common.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/trailers.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/src/github2gerrit/utils.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/conftest.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/fixtures/__init__.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/fixtures/make_repo.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_action_environment_mapping.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_action_outputs.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_action_pr_number_handling.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_change_id_deduplication.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_cli.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_cli_helpers.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_cli_outputs_file.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_cli_url_and_dryrun.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_commit_normalization.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_composite_action_coverage.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_config_and_reviewers.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_config_helpers.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_core_close_pr_policy.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_core_config_and_errors.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_core_gerrit_backref_comment.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_core_gerrit_push_errors.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_core_gerrit_rest_results.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_core_integration_fixture_repo.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_core_prepare_commits.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_core_ssh_setup.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_duplicate_detection.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_email_case_normalization.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_external_api_framework.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_gerrit_change_id_footer.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_gerrit_rest_client.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_gerrit_urls.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_gerrit_urls_more.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_ghe_and_gitreview_args.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_github_api_helpers.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_github_api_retry_and_helpers.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_gitutils_helpers.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_mapping_comment_additional.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_mapping_comment_digest_and_backref.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_metadata_and_reconciliation.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_misc_small_coverage.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_orphan_rest_side_effects.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_pr_content_filter.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_pr_content_filter_integration.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_reconciliation_extracted_module.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_reconciliation_plan_and_orphans.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_reconciliation_scenarios.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_ssh_agent.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_ssh_common.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_ssh_discovery.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_trailers_additional.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_url_parser.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/tests/test_utils.py +0 -0
- {github2gerrit-0.1.12 → github2gerrit-0.1.14}/uv.lock +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: github2gerrit
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.14
|
4
4
|
Summary: Submit a GitHub pull request to a Gerrit repository.
|
5
5
|
Project-URL: Homepage, https://github.com/lfreleng-actions/github2gerrit
|
6
6
|
Project-URL: Repository, https://github.com/lfreleng-actions/github2gerrit
|
@@ -186,8 +186,14 @@ runs:
|
|
186
186
|
run: |
|
187
187
|
set -euo pipefail
|
188
188
|
uv --version
|
189
|
-
# Install
|
190
|
-
|
189
|
+
# Install from PyPI when called from external repos, local source for self-testing
|
190
|
+
if [[ "${{ github.repository }}" == "modeseven-lfreleng-actions/github2gerrit-action" ]]; then
|
191
|
+
echo "Installing from local source (self-testing)"
|
192
|
+
uv pip install --system ${{ github.action_path }}
|
193
|
+
else
|
194
|
+
echo "Installing from PyPI (external repository)"
|
195
|
+
uv pip install --system github2gerrit
|
196
|
+
fi
|
191
197
|
|
192
198
|
- name: Validate PR_NUMBER usage (non-dispatch)
|
193
199
|
# yamllint disable-line rule:line-length
|
@@ -525,7 +525,7 @@ def main(
|
|
525
525
|
if _is_github_actions_context():
|
526
526
|
try:
|
527
527
|
app_version = get_version("github2gerrit")
|
528
|
-
log.
|
528
|
+
log.debug("github2gerrit version %s", app_version)
|
529
529
|
except Exception:
|
530
530
|
log.warning("Version information not available")
|
531
531
|
|
@@ -1115,6 +1115,41 @@ class Orchestrator:
|
|
1115
1115
|
log.debug("SSH private key not provided, skipping SSH setup")
|
1116
1116
|
return
|
1117
1117
|
|
1118
|
+
# Check for ssh-keyscan availability early if auto-discovery needed
|
1119
|
+
if (
|
1120
|
+
auto_discover_gerrit_host_keys is not None
|
1121
|
+
and not inputs.gerrit_known_hosts
|
1122
|
+
):
|
1123
|
+
import shutil
|
1124
|
+
|
1125
|
+
keyscan_path = shutil.which("ssh-keyscan")
|
1126
|
+
if not keyscan_path:
|
1127
|
+
log.error(
|
1128
|
+
"❌ ssh-keyscan not found in PATH but is required for SSH "
|
1129
|
+
"host key auto-discovery"
|
1130
|
+
)
|
1131
|
+
log.error(
|
1132
|
+
"Available tools in PATH: %s",
|
1133
|
+
", ".join(
|
1134
|
+
[
|
1135
|
+
tool
|
1136
|
+
for tool in [
|
1137
|
+
"ssh",
|
1138
|
+
"ssh-keygen",
|
1139
|
+
"ssh-add",
|
1140
|
+
"ssh-agent",
|
1141
|
+
"ssh-keyscan",
|
1142
|
+
]
|
1143
|
+
if shutil.which(tool)
|
1144
|
+
]
|
1145
|
+
),
|
1146
|
+
)
|
1147
|
+
log.error("To fix this issue:")
|
1148
|
+
log.error("1. Install openssh-client package, OR")
|
1149
|
+
log.error("2. Provide GERRIT_KNOWN_HOSTS manually")
|
1150
|
+
else:
|
1151
|
+
log.debug("✅ ssh-keyscan found at: %s", keyscan_path)
|
1152
|
+
|
1118
1153
|
# Auto-discover or augment host keys (merge missing
|
1119
1154
|
# types/[host]:port entries)
|
1120
1155
|
effective_known_hosts = inputs.gerrit_known_hosts
|
@@ -1122,9 +1157,18 @@ class Orchestrator:
|
|
1122
1157
|
try:
|
1123
1158
|
if not effective_known_hosts:
|
1124
1159
|
log.info(
|
1125
|
-
"GERRIT_KNOWN_HOSTS not provided, attempting "
|
1126
|
-
"auto-discovery..."
|
1160
|
+
"🔍 GERRIT_KNOWN_HOSTS not provided, attempting "
|
1161
|
+
"auto-discovery for %s:%d...",
|
1162
|
+
gerrit.host,
|
1163
|
+
gerrit.port,
|
1127
1164
|
)
|
1165
|
+
log.debug(
|
1166
|
+
"Auto-discovery params: host=%s, port=%d, org=%s",
|
1167
|
+
gerrit.host,
|
1168
|
+
gerrit.port,
|
1169
|
+
inputs.organization,
|
1170
|
+
)
|
1171
|
+
|
1128
1172
|
discovered_keys = auto_discover_gerrit_host_keys(
|
1129
1173
|
gerrit_hostname=gerrit.host,
|
1130
1174
|
gerrit_port=gerrit.port,
|
@@ -1134,15 +1178,18 @@ class Orchestrator:
|
|
1134
1178
|
if discovered_keys:
|
1135
1179
|
effective_known_hosts = discovered_keys
|
1136
1180
|
log.info(
|
1137
|
-
"Successfully auto-discovered SSH host keys for "
|
1181
|
+
"✅ Successfully auto-discovered SSH host keys for "
|
1138
1182
|
"%s:%d",
|
1139
1183
|
gerrit.host,
|
1140
1184
|
gerrit.port,
|
1141
1185
|
)
|
1142
1186
|
else:
|
1143
|
-
log.
|
1144
|
-
"Auto-discovery failed
|
1145
|
-
"
|
1187
|
+
log.error(
|
1188
|
+
"❌ Auto-discovery failed for %s:%d - SSH host key "
|
1189
|
+
"verification will likely fail. Check network "
|
1190
|
+
"connectivity and ssh-keyscan availability.",
|
1191
|
+
gerrit.host,
|
1192
|
+
gerrit.port,
|
1146
1193
|
)
|
1147
1194
|
else:
|
1148
1195
|
# Provided known_hosts exists; ensure it contains
|
@@ -1191,15 +1238,22 @@ class Orchestrator:
|
|
1191
1238
|
"Auto-discovery returned no keys; known_hosts "
|
1192
1239
|
"not augmented"
|
1193
1240
|
)
|
1194
|
-
except Exception
|
1195
|
-
log.
|
1196
|
-
"SSH host key auto-discovery/augmentation failed
|
1241
|
+
except Exception:
|
1242
|
+
log.exception(
|
1243
|
+
"❌ SSH host key auto-discovery/augmentation failed "
|
1244
|
+
"for %s:%d",
|
1245
|
+
gerrit.host,
|
1246
|
+
gerrit.port,
|
1197
1247
|
)
|
1198
1248
|
|
1199
1249
|
if not effective_known_hosts:
|
1200
|
-
log.
|
1201
|
-
"No SSH host keys available (manual or auto-discovered)
|
1202
|
-
"
|
1250
|
+
log.warning(
|
1251
|
+
"⚠️ No SSH host keys available (manual or auto-discovered) "
|
1252
|
+
"for %s:%d. SSH connections may fail due to host key "
|
1253
|
+
"verification. Consider setting GERRIT_KNOWN_HOSTS or ensure "
|
1254
|
+
"ssh-keyscan is available.",
|
1255
|
+
gerrit.host,
|
1256
|
+
gerrit.port,
|
1203
1257
|
)
|
1204
1258
|
return
|
1205
1259
|
|
@@ -13,6 +13,7 @@ from __future__ import annotations
|
|
13
13
|
|
14
14
|
import logging
|
15
15
|
import os
|
16
|
+
import shutil
|
16
17
|
import socket
|
17
18
|
from pathlib import Path
|
18
19
|
|
@@ -55,6 +56,18 @@ _MSG_UNEXPECTED_ERROR = (
|
|
55
56
|
_MSG_SAVE_FAILED = (
|
56
57
|
"Failed to save host keys to configuration file {config_file}: {error}"
|
57
58
|
)
|
59
|
+
_MSG_KEYSCAN_NOT_FOUND = (
|
60
|
+
"ssh-keyscan command not found in PATH. This tool is required for SSH "
|
61
|
+
"host key auto-discovery."
|
62
|
+
)
|
63
|
+
_MSG_KEYSCAN_CHECK_FAILED = (
|
64
|
+
"Failed to check for ssh-keyscan availability: {error}"
|
65
|
+
)
|
66
|
+
|
67
|
+
|
68
|
+
def _raise_keyscan_not_found() -> None:
|
69
|
+
"""Helper function to raise keyscan not found error."""
|
70
|
+
raise SSHDiscoveryError(_MSG_KEYSCAN_NOT_FOUND)
|
58
71
|
|
59
72
|
|
60
73
|
def is_host_reachable(hostname: str, port: int, timeout: int = 5) -> bool:
|
@@ -84,13 +97,36 @@ def fetch_ssh_host_keys(
|
|
84
97
|
Raises:
|
85
98
|
SSHDiscoveryError: If the host keys cannot be fetched
|
86
99
|
"""
|
87
|
-
log.
|
100
|
+
log.info("🔍 Starting SSH host key discovery for %s:%d", hostname, port)
|
101
|
+
|
102
|
+
# Check if ssh-keyscan is available
|
103
|
+
try:
|
104
|
+
keyscan_path = shutil.which("ssh-keyscan")
|
105
|
+
if not keyscan_path:
|
106
|
+
log.error("❌ ssh-keyscan not found in PATH")
|
107
|
+
_raise_keyscan_not_found()
|
108
|
+
log.debug("✅ Found ssh-keyscan at: %s", keyscan_path)
|
109
|
+
except Exception as exc:
|
110
|
+
log.exception("❌ Failed to check for ssh-keyscan")
|
111
|
+
raise SSHDiscoveryError(
|
112
|
+
_MSG_KEYSCAN_CHECK_FAILED.format(error=exc)
|
113
|
+
) from exc
|
114
|
+
|
115
|
+
log.debug(
|
116
|
+
"🔍 Fetching SSH host keys for %s:%d (timeout: %ds)",
|
117
|
+
hostname,
|
118
|
+
port,
|
119
|
+
timeout,
|
120
|
+
)
|
88
121
|
|
89
122
|
# First check if the host is reachable
|
123
|
+
log.debug("🔍 Testing connectivity to %s:%d...", hostname, port)
|
90
124
|
if not is_host_reachable(hostname, port, timeout=5):
|
125
|
+
log.error("❌ Host %s:%d is not reachable", hostname, port)
|
91
126
|
raise SSHDiscoveryError(
|
92
127
|
_MSG_HOST_UNREACHABLE.format(hostname=hostname, port=port)
|
93
128
|
)
|
129
|
+
log.debug("✅ Host %s:%d is reachable", hostname, port)
|
94
130
|
|
95
131
|
try:
|
96
132
|
# Use ssh-keyscan to fetch all available key types
|
@@ -105,9 +141,26 @@ def fetch_ssh_host_keys(
|
|
105
141
|
hostname,
|
106
142
|
]
|
107
143
|
|
144
|
+
log.debug("🔍 Running command: %s", " ".join(cmd))
|
108
145
|
result = run_cmd(cmd, timeout=timeout + 5)
|
109
146
|
|
147
|
+
log.debug(
|
148
|
+
"ssh-keyscan stdout length: %d chars",
|
149
|
+
len(result.stdout) if result.stdout else 0,
|
150
|
+
)
|
151
|
+
log.debug(
|
152
|
+
"ssh-keyscan stderr: %s",
|
153
|
+
result.stderr if result.stderr else "(empty)",
|
154
|
+
)
|
155
|
+
|
110
156
|
if not result.stdout or not result.stdout.strip():
|
157
|
+
log.error(
|
158
|
+
"❌ ssh-keyscan returned no output for %s:%d", hostname, port
|
159
|
+
)
|
160
|
+
log.error("Command: %s", " ".join(cmd))
|
161
|
+
log.error(
|
162
|
+
"Stderr: %s", result.stderr if result.stderr else "(none)"
|
163
|
+
)
|
111
164
|
raise SSHDiscoveryError( # noqa: TRY301
|
112
165
|
_MSG_NO_KEYS_FOUND.format(hostname=hostname, port=port)
|
113
166
|
)
|
@@ -127,20 +180,34 @@ def fetch_ssh_host_keys(
|
|
127
180
|
valid_lines.append(stripped_line)
|
128
181
|
|
129
182
|
if not valid_lines:
|
183
|
+
log.error(
|
184
|
+
"❌ No valid SSH host keys found in output for %s:%d",
|
185
|
+
hostname,
|
186
|
+
port,
|
187
|
+
)
|
188
|
+
log.error("Raw output was: %s", result.stdout)
|
130
189
|
raise SSHDiscoveryError( # noqa: TRY301
|
131
190
|
_MSG_NO_VALID_KEYS.format(hostname=hostname, port=port)
|
132
191
|
)
|
133
192
|
|
134
193
|
discovered_keys = "\n".join(valid_lines)
|
135
194
|
log.info(
|
136
|
-
"Successfully discovered %d SSH host key(s) for %s:%d",
|
195
|
+
"✅ Successfully discovered %d SSH host key(s) for %s:%d",
|
137
196
|
len(valid_lines),
|
138
197
|
hostname,
|
139
198
|
port,
|
140
199
|
)
|
141
|
-
log.
|
200
|
+
log.info("📋 Discovered keys:\n%s", discovered_keys)
|
142
201
|
|
143
202
|
except CommandError as exc:
|
203
|
+
log.exception("❌ ssh-keyscan command failed for %s:%d", hostname, port)
|
204
|
+
log.debug("Return code: %d", exc.returncode)
|
205
|
+
stdout_msg = exc.stdout if exc.stdout else "(empty)"
|
206
|
+
stderr_msg = exc.stderr if exc.stderr else "(empty)"
|
207
|
+
log.debug("Stdout: %s", stdout_msg)
|
208
|
+
log.debug("Stderr: %s", stderr_msg)
|
209
|
+
log.debug("Command: %s", " ".join(cmd))
|
210
|
+
|
144
211
|
if exc.returncode == 1:
|
145
212
|
# ssh-keyscan returns 1 when it can't connect
|
146
213
|
error_msg = exc.stderr or exc.stdout or "Connection failed"
|
@@ -381,11 +448,60 @@ def auto_discover_gerrit_host_keys(
|
|
381
448
|
)
|
382
449
|
save_to_config = False
|
383
450
|
|
451
|
+
# Log system diagnostics for debugging
|
452
|
+
|
384
453
|
log.info(
|
385
|
-
"Attempting to auto-discover SSH host keys for %s:%d"
|
454
|
+
"🔍 Attempting to auto-discover SSH host keys for %s:%d "
|
455
|
+
"(org: %s, save: %s)",
|
386
456
|
gerrit_hostname,
|
387
457
|
gerrit_port,
|
458
|
+
organization or "none",
|
459
|
+
save_to_config,
|
460
|
+
)
|
461
|
+
|
462
|
+
# System diagnostics
|
463
|
+
log.debug("🔧 System diagnostics:")
|
464
|
+
log.debug(" - OS: %s", os.name)
|
465
|
+
log.debug(
|
466
|
+
" - Platform: %s",
|
467
|
+
os.uname() if hasattr(os, "uname") else "unknown",
|
468
|
+
)
|
469
|
+
path_env = os.getenv("PATH", "not set")
|
470
|
+
path_display = (
|
471
|
+
path_env[:200] + "..." if len(path_env) > 200 else path_env
|
388
472
|
)
|
473
|
+
log.debug(" - PATH: %s", path_display)
|
474
|
+
ssh_tools = [
|
475
|
+
f"{tool}={shutil.which(tool) or 'missing'}"
|
476
|
+
for tool in [
|
477
|
+
"ssh",
|
478
|
+
"ssh-keygen",
|
479
|
+
"ssh-add",
|
480
|
+
"ssh-agent",
|
481
|
+
"ssh-keyscan",
|
482
|
+
]
|
483
|
+
]
|
484
|
+
log.debug(" - Available SSH tools: %s", ", ".join(ssh_tools))
|
485
|
+
dns_status = "checking..." if gerrit_hostname else "no hostname"
|
486
|
+
log.debug(" - Network test (DNS resolution): %s", dns_status)
|
487
|
+
|
488
|
+
# Test DNS resolution
|
489
|
+
if gerrit_hostname:
|
490
|
+
try:
|
491
|
+
import socket
|
492
|
+
|
493
|
+
addr_info = socket.getaddrinfo(gerrit_hostname, gerrit_port)
|
494
|
+
log.debug(
|
495
|
+
" - DNS resolution: ✅ %s resolves to %d addresses",
|
496
|
+
gerrit_hostname,
|
497
|
+
len(addr_info),
|
498
|
+
)
|
499
|
+
except Exception as dns_exc:
|
500
|
+
log.debug(
|
501
|
+
" - DNS resolution: ❌ %s failed: %s",
|
502
|
+
gerrit_hostname,
|
503
|
+
dns_exc,
|
504
|
+
)
|
389
505
|
|
390
506
|
# Discover the host keys
|
391
507
|
host_keys = fetch_ssh_host_keys(gerrit_hostname, gerrit_port)
|
@@ -404,12 +520,18 @@ def auto_discover_gerrit_host_keys(
|
|
404
520
|
"Set ORGANIZATION environment variable to enable auto-saving."
|
405
521
|
)
|
406
522
|
|
407
|
-
except SSHDiscoveryError
|
408
|
-
log.
|
523
|
+
except SSHDiscoveryError:
|
524
|
+
log.exception(
|
525
|
+
"❌ SSH host key auto-discovery failed for %s:%d",
|
526
|
+
gerrit_hostname,
|
527
|
+
gerrit_port,
|
528
|
+
)
|
409
529
|
return None
|
410
|
-
except Exception
|
411
|
-
log.
|
412
|
-
"Unexpected error during SSH host key auto-discovery
|
530
|
+
except Exception:
|
531
|
+
log.exception(
|
532
|
+
"❌ Unexpected error during SSH host key auto-discovery for %s:%d",
|
533
|
+
gerrit_hostname,
|
534
|
+
gerrit_port,
|
413
535
|
)
|
414
536
|
return None
|
415
537
|
else:
|
@@ -219,7 +219,11 @@ class TestActionStepValidation:
|
|
219
219
|
|
220
220
|
script = install_step["run"]
|
221
221
|
assert "uv --version" in script
|
222
|
+
# Should contain both PyPI and local installation logic
|
223
|
+
assert "github.repository" in script
|
224
|
+
assert "modeseven-lfreleng-actions/github2gerrit-action" in script
|
222
225
|
assert "uv pip install --system ${{ github.action_path }}" in script
|
226
|
+
assert "uv pip install --system github2gerrit" in script
|
223
227
|
|
224
228
|
def test_cli_execution_step(self, action_config):
|
225
229
|
"""Test CLI execution step configuration."""
|
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-0.1.12 → github2gerrit-0.1.14}/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-0.1.12 → github2gerrit-0.1.14}/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
|
{github2gerrit-0.1.12 → github2gerrit-0.1.14}/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
|