github2gerrit 2.2.0__py3-none-any.whl → 2.2.2__py3-none-any.whl
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/cli.py +127 -30
- github2gerrit/config.py +390 -461
- github2gerrit/config_ini.py +355 -0
- github2gerrit/core.py +251 -63
- github2gerrit/duplicate_detection.py +7 -8
- github2gerrit/gerrit_pr_closer.py +56 -45
- github2gerrit/gerrit_query.py +6 -6
- github2gerrit/gerrit_rest.py +8 -2
- github2gerrit/gitreview.py +138 -0
- github2gerrit/project_names.py +505 -0
- github2gerrit/utils.py +33 -0
- {github2gerrit-2.2.0.dist-info → github2gerrit-2.2.2.dist-info}/METADATA +13 -12
- {github2gerrit-2.2.0.dist-info → github2gerrit-2.2.2.dist-info}/RECORD +16 -14
- {github2gerrit-2.2.0.dist-info → github2gerrit-2.2.2.dist-info}/WHEEL +1 -1
- {github2gerrit-2.2.0.dist-info → github2gerrit-2.2.2.dist-info}/entry_points.txt +0 -0
- {github2gerrit-2.2.0.dist-info → github2gerrit-2.2.2.dist-info}/licenses/LICENSE +0 -0
github2gerrit/cli.py
CHANGED
|
@@ -120,6 +120,46 @@ def _exit_for_pr_state_error(pr_number: int, pr_state: str) -> None:
|
|
|
120
120
|
exit_for_pr_state_error(pr_number, pr_state)
|
|
121
121
|
|
|
122
122
|
|
|
123
|
+
def _stop_for_pr_state(
|
|
124
|
+
gh: GitHubContext, pr_state: str, progress_tracker: Any = None
|
|
125
|
+
) -> NoReturn:
|
|
126
|
+
"""Stop because the pull request is not open.
|
|
127
|
+
|
|
128
|
+
On a pull request event this is not an error. GitHub delivers
|
|
129
|
+
several events around a close — Dependabot edits the body before
|
|
130
|
+
closing, for instance — and any of them may land after the
|
|
131
|
+
``closed`` event whose handler already ran. Such a run has nothing
|
|
132
|
+
to do, and a red check on the contributor's pull request would
|
|
133
|
+
misreport that. The report behind #441 cited exactly this run and
|
|
134
|
+
took it for the close handler failing.
|
|
135
|
+
|
|
136
|
+
A dispatch or direct invocation naming a closed pull request is
|
|
137
|
+
different: somebody asked for that one specifically, and being told
|
|
138
|
+
it cannot be processed is the useful answer.
|
|
139
|
+
"""
|
|
140
|
+
if gh.event_name in ("pull_request", "pull_request_target"):
|
|
141
|
+
log.info(
|
|
142
|
+
"Pull request #%s is %s; nothing to do for a '%s' event. Cleanup "
|
|
143
|
+
"for a closed pull request runs on the 'closed' event itself.",
|
|
144
|
+
gh.pr_number,
|
|
145
|
+
pr_state,
|
|
146
|
+
gh.event_action or gh.event_name,
|
|
147
|
+
)
|
|
148
|
+
safe_console_print(
|
|
149
|
+
f"⏩ Pull request #{gh.pr_number} is {pr_state}; nothing to do",
|
|
150
|
+
style="yellow",
|
|
151
|
+
progress_tracker=progress_tracker,
|
|
152
|
+
)
|
|
153
|
+
# The caller's own stop() is downstream of this raise, and
|
|
154
|
+
# safe_console_print only suspends and resumes the display, so
|
|
155
|
+
# an in-process caller catching the exit would otherwise be
|
|
156
|
+
# left with an active Rich context.
|
|
157
|
+
if progress_tracker is not None:
|
|
158
|
+
progress_tracker.stop()
|
|
159
|
+
raise typer.Exit(int(ExitCode.SUCCESS))
|
|
160
|
+
exit_for_pr_state_error(gh.pr_number or 0, pr_state)
|
|
161
|
+
|
|
162
|
+
|
|
123
163
|
def _exit_for_pr_not_found(pr_number: int, repository: str) -> None:
|
|
124
164
|
"""Exit with error message for PR not found."""
|
|
125
165
|
exit_for_pr_not_found(pr_number, repository)
|
|
@@ -756,10 +796,10 @@ def _extract_and_display_pr_info(
|
|
|
756
796
|
repo = get_repo_from_env(client)
|
|
757
797
|
pr_obj = get_pull(repo, int(gh.pr_number))
|
|
758
798
|
|
|
759
|
-
# Check PR state and
|
|
799
|
+
# Check PR state and stop if not processable
|
|
760
800
|
pr_state = getattr(pr_obj, "state", "unknown")
|
|
761
801
|
if pr_state != "open":
|
|
762
|
-
|
|
802
|
+
_stop_for_pr_state(gh, str(pr_state), progress_tracker)
|
|
763
803
|
|
|
764
804
|
# Check if automation_only is enabled and reject non-automation PRs
|
|
765
805
|
_check_automation_only(pr_obj, gh, progress_tracker)
|
|
@@ -792,6 +832,12 @@ def _extract_and_display_pr_info(
|
|
|
792
832
|
except GitHub2GerritError:
|
|
793
833
|
# Let our structured errors propagate
|
|
794
834
|
raise
|
|
835
|
+
except typer.Exit:
|
|
836
|
+
# display_and_exit and the clean stop above both raise this.
|
|
837
|
+
# It derives from Exception through click, so without this
|
|
838
|
+
# clause the handler below would swallow a deliberate exit 8
|
|
839
|
+
# and report "Failed to fetch PR details: 8" with exit 1.
|
|
840
|
+
raise
|
|
795
841
|
except Exception as exc:
|
|
796
842
|
log.debug("Failed to display PR info: %s", exc)
|
|
797
843
|
if "404" in str(exc) or "Not Found" in str(exc):
|
|
@@ -1468,19 +1514,19 @@ def main(
|
|
|
1468
1514
|
"",
|
|
1469
1515
|
"--gerrit-project",
|
|
1470
1516
|
envvar="GERRIT_PROJECT",
|
|
1471
|
-
help="Gerrit project (optional; .gitreview
|
|
1517
|
+
help="Gerrit project (optional; overrides .gitreview when set).",
|
|
1472
1518
|
),
|
|
1473
1519
|
gerrit_server: str = typer.Option(
|
|
1474
1520
|
"",
|
|
1475
1521
|
"--gerrit-server",
|
|
1476
1522
|
envvar="GERRIT_SERVER",
|
|
1477
|
-
help="Gerrit server hostname (optional; .gitreview
|
|
1523
|
+
help="Gerrit server hostname (optional; overrides .gitreview).",
|
|
1478
1524
|
),
|
|
1479
1525
|
gerrit_server_port: int = typer.Option(
|
|
1480
|
-
|
|
1526
|
+
0,
|
|
1481
1527
|
"--gerrit-server-port",
|
|
1482
1528
|
envvar="GERRIT_SERVER_PORT",
|
|
1483
|
-
help="Gerrit SSH port
|
|
1529
|
+
help="Gerrit SSH port; .gitreview's when unset, else 29418.",
|
|
1484
1530
|
),
|
|
1485
1531
|
gerrit_ssh_privkey_g2g: str = typer.Option(
|
|
1486
1532
|
"",
|
|
@@ -1853,9 +1899,10 @@ def _build_inputs_from_env() -> Inputs:
|
|
|
1853
1899
|
dry_run=env_bool("DRY_RUN", False),
|
|
1854
1900
|
normalise_commit=env_bool("NORMALISE_COMMIT", True),
|
|
1855
1901
|
gerrit_server=env_str("GERRIT_SERVER", ""),
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1902
|
+
# 0 means unset. A blank value is what the action passes when the
|
|
1903
|
+
# caller gave none, and the distinction matters: an explicit
|
|
1904
|
+
# port outranks .gitreview's, a defaulted one must not.
|
|
1905
|
+
gerrit_server_port=int(env_str("GERRIT_SERVER_PORT", "").strip() or 0),
|
|
1859
1906
|
gerrit_project=env_str("GERRIT_PROJECT"),
|
|
1860
1907
|
issue_id=env_str("ISSUE_ID", ""),
|
|
1861
1908
|
issue_id_lookup_json=env_str("ISSUE_ID_LOOKUP_JSON", ""),
|
|
@@ -3036,14 +3083,23 @@ def _log_abandoned_change_url(
|
|
|
3036
3083
|
|
|
3037
3084
|
|
|
3038
3085
|
def _abandon_change_for_closed_pr(data: Inputs, gh: GitHubContext) -> None:
|
|
3039
|
-
"""Abandon the Gerrit change associated with a closed pull request.
|
|
3086
|
+
"""Abandon the Gerrit change associated with a closed pull request.
|
|
3087
|
+
|
|
3088
|
+
Three outcomes, reported distinctly: a change was abandoned, no
|
|
3089
|
+
open change carries this pull request's trailer, or the lookup or
|
|
3090
|
+
abandon itself failed. The last two used to share one message, and
|
|
3091
|
+
a failed query read as a clean "nothing to do". A failure does not
|
|
3092
|
+
say which side of the abandon it happened on -- Gerrit may have
|
|
3093
|
+
applied it and the response been lost -- so the report says the
|
|
3094
|
+
state is unconfirmed rather than claiming the change is open.
|
|
3095
|
+
"""
|
|
3040
3096
|
if gh.pr_number is None:
|
|
3041
3097
|
return
|
|
3098
|
+
log.debug(
|
|
3099
|
+
"Checking for Gerrit change to abandon for PR #%s",
|
|
3100
|
+
gh.pr_number,
|
|
3101
|
+
)
|
|
3042
3102
|
try:
|
|
3043
|
-
log.debug(
|
|
3044
|
-
"Checking for Gerrit change to abandon for PR #%s",
|
|
3045
|
-
gh.pr_number,
|
|
3046
|
-
)
|
|
3047
3103
|
change_number = abandon_gerrit_change_for_closed_pr(
|
|
3048
3104
|
pr_number=gh.pr_number,
|
|
3049
3105
|
gerrit_server=data.gerrit_server,
|
|
@@ -3052,21 +3108,46 @@ def _abandon_change_for_closed_pr(data: Inputs, gh: GitHubContext) -> None:
|
|
|
3052
3108
|
dry_run=data.dry_run,
|
|
3053
3109
|
progress_tracker=None,
|
|
3054
3110
|
)
|
|
3055
|
-
if change_number:
|
|
3056
|
-
_log_abandoned_change_url(data, gh, change_number)
|
|
3057
|
-
# Console output already done by
|
|
3058
|
-
# abandon_gerrit_change_for_closed_pr
|
|
3059
|
-
else:
|
|
3060
|
-
log.debug(
|
|
3061
|
-
"No open Gerrit change found for pull request #%s",
|
|
3062
|
-
gh.pr_number,
|
|
3063
|
-
)
|
|
3064
3111
|
except Exception as exc:
|
|
3065
3112
|
log.warning(
|
|
3066
|
-
"Failed to abandon Gerrit change for
|
|
3113
|
+
"Failed to look up or abandon the Gerrit change for pull "
|
|
3114
|
+
"request #%s in project %r on %s: %s. Its state could not be "
|
|
3115
|
+
"confirmed; check Gerrit.",
|
|
3067
3116
|
gh.pr_number,
|
|
3117
|
+
data.gerrit_project,
|
|
3118
|
+
data.gerrit_server,
|
|
3068
3119
|
exc,
|
|
3069
3120
|
)
|
|
3121
|
+
log.debug("Cleanup failure detail", exc_info=True)
|
|
3122
|
+
safe_console_print(
|
|
3123
|
+
f"⚠️ Could not confirm the Gerrit change state for PR "
|
|
3124
|
+
f"#{gh.pr_number}: {exc}",
|
|
3125
|
+
style="yellow",
|
|
3126
|
+
)
|
|
3127
|
+
return
|
|
3128
|
+
|
|
3129
|
+
if change_number:
|
|
3130
|
+
_log_abandoned_change_url(data, gh, change_number)
|
|
3131
|
+
# Console output already done by
|
|
3132
|
+
# abandon_gerrit_change_for_closed_pr
|
|
3133
|
+
return
|
|
3134
|
+
|
|
3135
|
+
# Audible on purpose. This is the outcome when the project name is
|
|
3136
|
+
# wrong, and at debug level it hid 239 stranded changes on one
|
|
3137
|
+
# server for six months (#441). Naming the project queried is what
|
|
3138
|
+
# lets a reader spot the mismatch.
|
|
3139
|
+
log.info(
|
|
3140
|
+
"No open Gerrit change found for pull request #%s in "
|
|
3141
|
+
"project %r on %s; nothing to abandon",
|
|
3142
|
+
gh.pr_number,
|
|
3143
|
+
data.gerrit_project,
|
|
3144
|
+
data.gerrit_server,
|
|
3145
|
+
)
|
|
3146
|
+
safe_console_print(
|
|
3147
|
+
f"⏩ No open Gerrit change for PR #{gh.pr_number} in "
|
|
3148
|
+
f"project '{data.gerrit_project}'",
|
|
3149
|
+
style="dim",
|
|
3150
|
+
)
|
|
3070
3151
|
|
|
3071
3152
|
|
|
3072
3153
|
def _handle_pr_closed(
|
|
@@ -3104,13 +3185,28 @@ def _handle_pr_closed(
|
|
|
3104
3185
|
|
|
3105
3186
|
# First, abandon the specific Gerrit change for this closed PR
|
|
3106
3187
|
# Skip in G2G_NO_GERRIT: no Gerrit server to query
|
|
3107
|
-
if
|
|
3108
|
-
|
|
3109
|
-
|
|
3188
|
+
if no_gerrit:
|
|
3189
|
+
pass
|
|
3190
|
+
elif not (
|
|
3191
|
+
gh.pr_number
|
|
3192
|
+
and gh.repository
|
|
3110
3193
|
and data.gerrit_server
|
|
3111
3194
|
and data.gerrit_project
|
|
3112
|
-
and gh.repository
|
|
3113
3195
|
):
|
|
3196
|
+
# Say so. Silently skipping here is indistinguishable from a
|
|
3197
|
+
# successful cleanup that found nothing, and the change stays
|
|
3198
|
+
# open with no trace of why.
|
|
3199
|
+
log.warning(
|
|
3200
|
+
"Cannot look for a Gerrit change to abandon for PR #%s: "
|
|
3201
|
+
"repository=%r server=%r project=%r. Set GERRIT_SERVER and "
|
|
3202
|
+
"GERRIT_PROJECT, or add a .gitreview so they can be derived; "
|
|
3203
|
+
"the repository comes from GITHUB_REPOSITORY.",
|
|
3204
|
+
gh.pr_number,
|
|
3205
|
+
gh.repository,
|
|
3206
|
+
data.gerrit_server,
|
|
3207
|
+
data.gerrit_project,
|
|
3208
|
+
)
|
|
3209
|
+
else:
|
|
3114
3210
|
_abandon_change_for_closed_pr(data, gh)
|
|
3115
3211
|
|
|
3116
3212
|
_run_gerrit_cleanup_tasks(data, gh, no_gerrit=no_gerrit)
|
|
@@ -3935,8 +4031,9 @@ def _add_full_config(
|
|
|
3935
4031
|
# Show Gerrit settings if they have values
|
|
3936
4032
|
if data.gerrit_server:
|
|
3937
4033
|
config_info["GERRIT_SERVER"] = data.gerrit_server
|
|
3938
|
-
#
|
|
3939
|
-
|
|
4034
|
+
# Any set port is shown: 0 is the unset sentinel, and an explicit
|
|
4035
|
+
# 29418 is a real override of whatever .gitreview names.
|
|
4036
|
+
if data.gerrit_server_port:
|
|
3940
4037
|
config_info["GERRIT_SERVER_PORT"] = str(data.gerrit_server_port)
|
|
3941
4038
|
if data.gerrit_project:
|
|
3942
4039
|
config_info["GERRIT_PROJECT"] = data.gerrit_project
|