Skip to content

Commit ce58b87

Browse files
committed
chore(release): address PR comments on sync PR
- Use is_news_file helper to avoid accidental deletion of non-news files. - Make branch checkout robust by resetting existing branch to main. - Specify UTF-8 encoding when writing patch files.
1 parent 21bc57c commit ce58b87

2 files changed

Lines changed: 116 additions & 7 deletions

File tree

tests/tools/private/release/process_backports_test.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,115 @@ def mock_resolve(items):
134134
self.assertEqual(call_args[0], 123)
135135
self.assertIn("- [x] #124 | status=done rc=rc0 commit= 12345678", call_args[1])
136136

137+
@patch("tools.private.release.process_backports.datetime")
138+
def test_process_backports_sync_branch_exists(self, mock_datetime):
139+
mock_datetime.date.today.return_value = datetime.date(2026, 7, 1)
140+
args = argparse.Namespace(
141+
issue=123, remote="origin", dry_run=False, add=None, triggering_comment=None
142+
)
143+
self.mock_gh.get_issue_title.return_value = "Release 2.0.0"
144+
self.mock_gh.get_issue_body.return_value = """
145+
## Checklist
146+
- [ ] Prepare Release
147+
- [ ] Create Release branch
148+
149+
## Backports
150+
- [ ] #124 | status=pending
151+
"""
152+
self.mock_git.get_remote_tags.return_value = []
153+
154+
def mock_resolve(items):
155+
for item in items:
156+
if item.pr_ref == "#124":
157+
item.commit = "abcdef12"
158+
item.status = "done"
159+
return items
160+
161+
self.mock_gh.get_merge_commits_for_prs.side_effect = mock_resolve
162+
163+
self.mock_git.sort_commits_chronologically.return_value = ["abcdef12"]
164+
self.mock_git.get_commit_sha.side_effect = ["12345678", "12345678", "main_sha"]
165+
self.mock_git.get_commit_message.return_value = 'Cherry-pick "fix bug"'
166+
self.mock_git.get_modified_files.return_value = ["news/124.fixed.md"]
167+
self.mock_git.diff.return_value = "version diff for 124"
168+
self.mock_git.apply_check.return_value = True
169+
self.mock_gh.create_pr.return_value = "https://github.com/foo/bar/pull/999"
170+
171+
# Configure branch to exist
172+
self.mock_git.branch_exists.return_value = True
173+
174+
result = ProcessBackports(args, self.mock_git, self.mock_gh).run()
175+
176+
self.assertEqual(result, 0)
177+
self.mock_git.fetch.assert_has_calls(
178+
[
179+
call("origin", tags=True, force=True),
180+
call("origin"),
181+
call("origin", refspec="main"),
182+
]
183+
)
184+
self.mock_git.checkout.assert_has_calls(
185+
[
186+
call("release/2.0", track_remote="origin"),
187+
call("main", track_remote="origin"),
188+
# Called without create_branch=True
189+
call("prepare-2.0.0-backports-6affdae"),
190+
call("release/2.0"),
191+
]
192+
)
193+
# Verify reset_hard was called to reset the existing branch to main
194+
self.mock_git.reset_hard.assert_has_calls(
195+
[
196+
call("main"),
197+
]
198+
)
199+
self.mock_git.cherry_pick.assert_called_once_with("abcdef12")
200+
self.mock_git.diff.assert_called_once()
201+
self.mock_git.apply_check.assert_called_once_with(unittest.mock.ANY)
202+
self.mock_git.apply.assert_called_once_with(unittest.mock.ANY)
203+
self.mock_changelog_news.update_changelog.assert_has_calls(
204+
[
205+
call("2.0.0", "2026-07-01"),
206+
call(
207+
"2.0.0",
208+
"2026-07-01",
209+
news_files=["news/124.fixed.md"],
210+
delete_news=True,
211+
),
212+
]
213+
)
214+
self.assertEqual(self.mock_git.add_modified_and_deleted.call_count, 2)
215+
self.mock_replace_version_next.assert_called_once_with("2.0.0")
216+
self.mock_git.commit.assert_has_calls(
217+
[
218+
call('Cherry-pick "fix bug"\n\nWork towards #123', amend=True),
219+
call("chore(release): sync changelog for v2.0.0 backports"),
220+
]
221+
)
222+
self.mock_git.push.assert_has_calls(
223+
[
224+
call("origin", "release/2.0"),
225+
call(
226+
"origin",
227+
"prepare-2.0.0-backports-6affdae",
228+
set_upstream=True,
229+
force=True,
230+
),
231+
]
232+
)
233+
234+
self.mock_gh.create_pr.assert_called_once_with(
235+
title="chore(release): sync changelog for v2.0.0 backports",
236+
body="Updates CHANGELOG.md and removes news files for backports:\n- #124\n\nWork towards #123",
237+
base="main",
238+
)
239+
self.mock_gh.enable_auto_merge.assert_called_once_with(999)
240+
241+
self.mock_gh.update_issue_body.assert_called_once()
242+
call_args = self.mock_gh.update_issue_body.call_args[0]
243+
self.assertEqual(call_args[0], 123)
244+
self.assertIn("- [x] #124 | status=done rc=rc0 commit= 12345678", call_args[1])
245+
137246
@patch("tools.private.release.process_backports.datetime")
138247
def test_process_backports_dry_run(self, mock_datetime):
139248
mock_datetime.date.today.return_value = datetime.date(2026, 7, 1)

tools/private/release/process_backports.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,7 @@ def _cherry_pick_and_update_prs(
116116
# Collect news files before they are deleted by update_changelog
117117
modified_files = self.git.get_modified_files("HEAD")
118118
for f in modified_files:
119-
if (
120-
f.startswith("news/")
121-
and f.endswith(".md")
122-
and f != "news/BUILD.bazel"
123-
):
119+
if changelog_news.is_news_file(f):
124120
collected_news_files.append(f)
125121

126122
# Replace version markers FIRST to isolate diff
@@ -258,7 +254,11 @@ def _sync_changelog_to_main(
258254
f"[DRY RUN] Would create and checkout branch {backport_branch} from {main_branch}"
259255
)
260256
else:
261-
self.git.checkout(backport_branch, create_branch=True)
257+
if self.git.branch_exists(backport_branch):
258+
self.git.checkout(backport_branch)
259+
self.git.reset_hard(main_branch)
260+
else:
261+
self.git.checkout(backport_branch, create_branch=True)
262262

263263
print(
264264
f"Updating CHANGELOG.md and removing news files on {backport_branch}..."
@@ -347,7 +347,7 @@ def _apply_version_marker_diffs(
347347
)
348348

349349
patch_filepath = os.path.join(temp_dir, f"{pr_num}.patch")
350-
with open(patch_filepath, "w") as f:
350+
with open(patch_filepath, "w", encoding="utf-8") as f:
351351
f.write(diff_content)
352352

353353
if self.git.apply_check(patch_filepath):

0 commit comments

Comments
 (0)