@@ -148,16 +148,29 @@ where
148148            . run ( "gh" ,  repo_path,  & args) 
149149            . wrap_err ( "failed to run `gh pr merge`" ) ?; 
150150
151-         if  !output. success  { 
151+         let  branch_delete_failed = gh_branch_delete_failure ( & output) ; 
152+ 
153+         if  !output. success  && !branch_delete_failed { 
152154            return  Err ( command_failure ( "gh" ,  & args,  & output) ) ; 
153155        } 
154156
155-         self . restore_worktree_branch ( worktree_path,  branch) ?; 
156- 
157157        let  pr_label = format_with_color ( & format ! ( "#{}" ,  pr_number) ,  |text| { 
158158            format ! ( "{}" ,  text. green( ) . bold( ) ) 
159159        } ) ; 
160160        let  branch_label = format_with_color ( branch,  |text| format ! ( "{}" ,  text. magenta( ) . bold( ) ) ) ; 
161+ 
162+         if  branch_delete_failed { 
163+             let  warning = format ! ( 
164+                 "PR {} merged but `gh` could not delete branch `{}`. Leaving the branch intact." , 
165+                 pr_label,  branch_label
166+             ) ; 
167+             println ! ( 
168+                 "{}" , 
169+                 warning. if_supports_color( Stream :: Stdout ,  |text| format!( "{}" ,  text. yellow( ) ) ) 
170+             ) ; 
171+         } 
172+ 
173+         self . restore_worktree_branch ( worktree_path,  branch) ?; 
161174        println ! ( "Merged PR {} for branch `{}`." ,  pr_label,  branch_label) ; 
162175        Ok ( ( ) ) 
163176    } 
@@ -181,6 +194,15 @@ where
181194    } 
182195} 
183196
197+ fn  gh_branch_delete_failure ( output :  & CommandOutput )  -> bool  { 
198+     if  output. success  { 
199+         return  false ; 
200+     } 
201+ 
202+     let  stderr = output. stderr . to_lowercase ( ) ; 
203+     stderr. contains ( "failed to delete local branch" )  || stderr. contains ( "cannot delete branch" ) 
204+ } 
205+ 
184206fn  command_failure ( program :  & str ,  args :  & [ String ] ,  output :  & CommandOutput )  -> color_eyre:: Report  { 
185207    let  command_line = format_command ( program,  args) ; 
186208    let  status = match  output. status_code  { 
@@ -392,6 +414,92 @@ mod tests {
392414        Ok ( ( ) ) 
393415    } 
394416
417+     #[ test]  
418+     fn  treats_branch_delete_failure_as_success ( )  -> color_eyre:: Result < ( ) >  { 
419+         let  repo_dir = TempDir :: new ( ) ?; 
420+         init_git_repo ( & repo_dir) ?; 
421+         let  repo = Repo :: discover_from ( repo_dir. path ( ) ) ?; 
422+         let  repo_root = repo. root ( ) . to_path_buf ( ) ; 
423+         let  worktree_path = repo. worktrees_dir ( ) . join ( "feature/test" ) ; 
424+         fs:: create_dir_all ( & worktree_path) ?; 
425+ 
426+         let  mut  runner = MockCommandRunner :: default ( ) ; 
427+         runner. responses . extend ( [ 
428+             Ok ( CommandOutput  { 
429+                 stdout :  "feature/test\n " . into ( ) , 
430+                 stderr :  String :: new ( ) , 
431+                 success :  true , 
432+                 status_code :  Some ( 0 ) , 
433+             } ) , 
434+             Ok ( CommandOutput  { 
435+                 stdout :  "[{\" number\" :42}]" . into ( ) , 
436+                 stderr :  String :: new ( ) , 
437+                 success :  true , 
438+                 status_code :  Some ( 0 ) , 
439+             } ) , 
440+             Ok ( CommandOutput  { 
441+                 stdout :  "Pull request successfully merged" . into ( ) , 
442+                 stderr :  "failed to delete local branch merge-cmd" . into ( ) , 
443+                 success :  false , 
444+                 status_code :  Some ( 1 ) , 
445+             } ) , 
446+             Ok ( CommandOutput  { 
447+                 stdout :  String :: new ( ) , 
448+                 stderr :  String :: new ( ) , 
449+                 success :  true , 
450+                 status_code :  Some ( 0 ) , 
451+             } ) , 
452+         ] ) ; 
453+ 
454+         let  mut  command = MergePrGithubCommand :: with_runner ( "feature/test" . into ( ) ,  runner) ; 
455+         command. execute ( & repo) ?; 
456+ 
457+         assert_eq ! ( 
458+             command. runner. calls, 
459+             vec![ 
460+                 RecordedCall  { 
461+                     program:  "git" . into( ) , 
462+                     dir:  worktree_path. clone( ) , 
463+                     args:  vec![ "rev-parse" . into( ) ,  "--abbrev-ref" . into( ) ,  "HEAD" . into( ) ] , 
464+                 } , 
465+                 RecordedCall  { 
466+                     program:  "gh" . into( ) , 
467+                     dir:  repo_root. clone( ) , 
468+                     args:  vec![ 
469+                         "pr" . into( ) , 
470+                         "list" . into( ) , 
471+                         "--head" . into( ) , 
472+                         "feature/test" . into( ) , 
473+                         "--state" . into( ) , 
474+                         "open" . into( ) , 
475+                         "--json" . into( ) , 
476+                         "number" . into( ) , 
477+                         "--limit" . into( ) , 
478+                         "1" . into( ) , 
479+                     ] , 
480+                 } , 
481+                 RecordedCall  { 
482+                     program:  "gh" . into( ) , 
483+                     dir:  repo_root. clone( ) , 
484+                     args:  vec![ 
485+                         "pr" . into( ) , 
486+                         "merge" . into( ) , 
487+                         "42" . into( ) , 
488+                         "--merge" . into( ) , 
489+                         "--delete-branch" . into( ) , 
490+                     ] , 
491+                 } , 
492+                 RecordedCall  { 
493+                     program:  "git" . into( ) , 
494+                     dir:  worktree_path, 
495+                     args:  vec![ "switch" . into( ) ,  "feature/test" . into( ) ] , 
496+                 } , 
497+             ] 
498+         ) ; 
499+ 
500+         Ok ( ( ) ) 
501+     } 
502+ 
395503    #[ test]  
396504    fn  skips_merge_when_no_pull_request_found ( )  -> color_eyre:: Result < ( ) >  { 
397505        let  repo_dir = TempDir :: new ( ) ?; 
0 commit comments