@@ -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 \n Work 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 \n Work 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 )
0 commit comments