Skip to content

Commit 9587fca

Browse files
authored
Clear git state (#735)
* Clear leftover cherry-picker state to prevent invalidrepoexception
1 parent 8bd2474 commit 9587fca

2 files changed

Lines changed: 92 additions & 7 deletions

File tree

miss_islington/tasks.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import logging
23
import os
34
import ssl
45
import subprocess
@@ -15,6 +16,7 @@
1516

1617
from . import util
1718

19+
logger = logging.getLogger(__name__)
1820

1921
app = celery.Celery("backport_cpython")
2022

@@ -116,16 +118,39 @@ async def backport_task_asyncio(
116118
# Ensure that we don't have any changes lying around
117119
subprocess.check_output(['git', 'reset', '--hard'])
118120
subprocess.check_output(['git', 'clean', '-fxd'])
119-
120-
cp = cherry_picker.CherryPicker(
121-
"origin",
122-
commit_hash,
123-
[branch],
124-
config=CHERRY_PICKER_CONFIG,
125-
prefix_commit=False,
121+
# Clear any leftover cherry-picker state from a previously interrupted
122+
# run; otherwise CherryPicker() init raises InvalidRepoException and
123+
# every subsequent backport on this worker silently fails.
124+
subprocess.run(
125+
['git', 'config', '--local', '--remove-section', 'cherry-picker'],
126+
stderr=subprocess.DEVNULL,
127+
check=False,
126128
)
129+
127130
try:
131+
cp = cherry_picker.CherryPicker(
132+
"origin",
133+
commit_hash,
134+
[branch],
135+
config=CHERRY_PICKER_CONFIG,
136+
prefix_commit=False,
137+
)
128138
cp.backport()
139+
except cherry_picker.InvalidRepoException as ire:
140+
await util.comment_on_pr(
141+
gh,
142+
issue_number,
143+
f"""\
144+
Sorry {util.get_participants(created_by, merged_by)}, I had trouble backporting to `{branch}`.
145+
Please retry by removing and re-adding the "needs backport to {branch}" label.
146+
Alternatively, you can backport using [cherry_picker](https://pypi.org/project/cherry-picker/) on the command line.
147+
```
148+
cherry_picker {commit_hash} {branch}
149+
```
150+
""",
151+
)
152+
await util.assign_pr_to_core_dev(gh, issue_number, merged_by)
153+
logger.exception("InvalidRepoException while backporting to %s", branch)
129154
except cherry_picker.BranchCheckoutException as bce:
130155
await util.comment_on_pr(
131156
gh,

tests/test_tasks.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import os
2+
import subprocess
3+
from unittest import mock
4+
5+
from cherry_picker import cherry_picker
6+
7+
os.environ.setdefault("HEROKU_REDIS_MAROON_URL", "someurl")
8+
9+
from miss_islington import tasks
10+
11+
12+
async def test_invalid_repo_exception_posts_comment_and_clears_state():
13+
"""A stuck cherry-picker.state in git config used to wedge every
14+
subsequent backport: CherryPicker() init raised InvalidRepoException
15+
and the task crashed with no comment posted. The task now wipes
16+
stale state pre-flight and posts an error comment if init still fails.
17+
"""
18+
with (
19+
mock.patch("miss_islington.tasks.aiohttp.ClientSession"),
20+
mock.patch(
21+
"miss_islington.tasks.apps.get_installation_access_token",
22+
new=mock.AsyncMock(return_value={"token": "test-token"}),
23+
),
24+
mock.patch("miss_islington.tasks.util.is_cpython_repo", return_value=True),
25+
mock.patch("miss_islington.tasks.subprocess.check_output"),
26+
mock.patch("miss_islington.tasks.subprocess.run") as run_mock,
27+
mock.patch(
28+
"miss_islington.tasks.cherry_picker.CherryPicker",
29+
side_effect=cherry_picker.InvalidRepoException("stuck state"),
30+
),
31+
mock.patch(
32+
"miss_islington.tasks.util.comment_on_pr", new=mock.AsyncMock()
33+
) as comment_mock,
34+
mock.patch(
35+
"miss_islington.tasks.util.assign_pr_to_core_dev", new=mock.AsyncMock()
36+
) as assign_mock,
37+
):
38+
await tasks.backport_task_asyncio(
39+
"7a4c6dfb8839eb05fb87baf70364680e45001dd4",
40+
"3.15",
41+
issue_number=130749,
42+
created_by="medmunds",
43+
merged_by="bitdancer",
44+
installation_id=42958231,
45+
)
46+
47+
run_mock.assert_any_call(
48+
["git", "config", "--local", "--remove-section", "cherry-picker"],
49+
stderr=subprocess.DEVNULL,
50+
check=False,
51+
)
52+
53+
comment_mock.assert_awaited_once()
54+
posted_message = comment_mock.await_args.args[2]
55+
assert "3.15" in posted_message
56+
assert "@bitdancer" in posted_message
57+
58+
assign_mock.assert_awaited_once()
59+
assert assign_mock.await_args.args[1] == 130749
60+
assert assign_mock.await_args.args[2] == "bitdancer"

0 commit comments

Comments
 (0)