@@ -7,26 +7,34 @@ describe("buildConflictReport", () => {
77 expect ( buildConflictReport ( [ ] ) ) . toEqual ( [ ] ) ;
88 } ) ;
99
10- test ( "produces gap + message + gap + section for a single entry" , ( ) => {
10+ test ( "produces gap + message + gap + section + trailing guidance for a single entry" , ( ) => {
1111 const entries : ConflictEntry [ ] = [
12- { repo : "api" , stdout : "CONFLICT (content): Merge conflict in index.ts\n" , stderr : "" , subcommand : "rebase" } ,
12+ { repo : "api" , stdout : "CONFLICT (content): Merge conflict in index.ts\n" , stderr : "" , mode : "rebase" } ,
1313 ] ;
1414 const nodes = buildConflictReport ( entries ) ;
1515
1616 expect ( nodes [ 0 ] ) . toEqual ( { kind : "gap" } ) ;
1717 const msg = nodes [ 1 ] as MessageNode ;
1818 expect ( msg . kind ) . toBe ( "message" ) ;
19- expect ( msg . text ) . toBe ( "1 repo(s) have conflicts:" ) ;
19+ expect ( msg . text ) . toBe ( "1 repo has conflicts:" ) ;
2020
2121 expect ( nodes [ 2 ] ) . toEqual ( { kind : "gap" } ) ;
2222 const section = nodes [ 3 ] as SectionNode ;
2323 expect ( section . kind ) . toBe ( "section" ) ;
2424 expect ( section . header . plain ) . toBe ( "api" ) ;
25+ expect ( section . items ) . toHaveLength ( 1 ) ;
2526 expect ( section . items [ 0 ] ?. spans [ 0 ] ?. attention ) . toBe ( "muted" ) ;
2627 expect ( section . items [ 0 ] ?. plain ) . toBe ( "CONFLICT (content): Merge conflict in index.ts" ) ;
27- expect ( section . items [ 1 ] ?. plain ) . toBe ( "cd api" ) ;
28- expect ( section . items [ 2 ] ?. plain ) . toBe ( "# fix conflicts, then: git rebase --continue" ) ;
29- expect ( section . items [ 3 ] ?. plain ) . toBe ( "# or to undo: git rebase --abort" ) ;
28+
29+ // Trailing guidance
30+ expect ( nodes [ 4 ] ) . toEqual ( { kind : "gap" } ) ;
31+ const cont = nodes [ 5 ] as MessageNode ;
32+ expect ( cont . text ) . toBe ( "Fix conflicts, then: arb rebase --continue" ) ;
33+ const abort = nodes [ 6 ] as MessageNode ;
34+ expect ( abort . text ) . toBe ( "Or to abort: arb rebase --abort" ) ;
35+ const git = nodes [ 7 ] as MessageNode ;
36+ expect ( git . level ) . toBe ( "muted" ) ;
37+ expect ( git . text ) . toContain ( "git rebase --continue/--abort per repo" ) ;
3038 } ) ;
3139
3240 test ( "filters only CONFLICT lines from combined stdout/stderr" , ( ) => {
@@ -35,38 +43,67 @@ describe("buildConflictReport", () => {
3543 repo : "web" ,
3644 stdout : "Applying: abc\nCONFLICT (content): file.ts\nFailed to merge\n" ,
3745 stderr : "error: could not apply\nCONFLICT (modify/delete): old.ts\n" ,
38- subcommand : "merge" ,
46+ mode : "merge" ,
3947 } ,
4048 ] ;
4149 const nodes = buildConflictReport ( entries ) ;
4250 const section = nodes [ 3 ] as SectionNode ;
43- const conflictItems = section . items . filter ( ( i ) => i . spans [ 0 ] ?. attention === "muted" ) ;
44- expect ( conflictItems ) . toHaveLength ( 3 ) ; // 2 CONFLICT lines + 1 arb guidance line
45- expect ( conflictItems [ 0 ] ?. plain ) . toBe ( "CONFLICT (content): file.ts" ) ;
46- expect ( conflictItems [ 1 ] ?. plain ) . toBe ( "CONFLICT (modify/delete): old.ts" ) ;
51+ const mutedItems = section . items . filter ( ( i ) => i . spans [ 0 ] ?. attention === "muted" ) ;
52+ expect ( mutedItems ) . toHaveLength ( 2 ) ;
53+ expect ( mutedItems [ 0 ] ?. plain ) . toBe ( "CONFLICT (content): file.ts" ) ;
54+ expect ( mutedItems [ 1 ] ?. plain ) . toBe ( "CONFLICT (modify/delete): old.ts" ) ;
4755 } ) ;
4856
49- test ( "uses correct subcommand in recovery instructions " , ( ) => {
50- const mergeEntries : ConflictEntry [ ] = [ { repo : "lib" , stdout : "" , stderr : "" , subcommand : "merge" } ] ;
57+ test ( "uses mode for arb command and derives git subcommand " , ( ) => {
58+ const mergeEntries : ConflictEntry [ ] = [ { repo : "lib" , stdout : "" , stderr : "" , mode : "merge" } ] ;
5159 const mergeNodes = buildConflictReport ( mergeEntries ) ;
52- const section = mergeNodes [ 3 ] as SectionNode ;
53- expect ( section . items . some ( ( i ) => i . plain . includes ( "git merge --continue" ) ) ) . toBe ( true ) ;
54- expect ( section . items . some ( ( i ) => i . plain . includes ( "git merge --abort" ) ) ) . toBe ( true ) ;
60+ const cont = mergeNodes [ 5 ] as MessageNode ;
61+ expect ( cont . text ) . toContain ( "arb merge --continue" ) ;
62+ const abort = mergeNodes [ 6 ] as MessageNode ;
63+ expect ( abort . text ) . toContain ( "arb merge --abort" ) ;
64+ const git = mergeNodes [ 7 ] as MessageNode ;
65+ expect ( git . text ) . toContain ( "git merge --continue/--abort" ) ;
66+
67+ // pull and retarget use git rebase under the hood
68+ const pullEntries : ConflictEntry [ ] = [ { repo : "lib" , stdout : "" , stderr : "" , mode : "pull" } ] ;
69+ const pullNodes = buildConflictReport ( pullEntries ) ;
70+ const pullCont = pullNodes [ 5 ] as MessageNode ;
71+ expect ( pullCont . text ) . toContain ( "arb pull --continue" ) ;
72+ const pullGit = pullNodes [ 7 ] as MessageNode ;
73+ expect ( pullGit . text ) . toContain ( "git rebase --continue/--abort" ) ;
74+
75+ const retargetEntries : ConflictEntry [ ] = [ { repo : "lib" , stdout : "" , stderr : "" , mode : "retarget" } ] ;
76+ const retargetNodes = buildConflictReport ( retargetEntries ) ;
77+ const retargetCont = retargetNodes [ 5 ] as MessageNode ;
78+ expect ( retargetCont . text ) . toContain ( "arb retarget --continue" ) ;
79+ const retargetGit = retargetNodes [ 7 ] as MessageNode ;
80+ expect ( retargetGit . text ) . toContain ( "git rebase --continue/--abort" ) ;
5581 } ) ;
5682
5783 test ( "produces gap between multiple repo sections" , ( ) => {
5884 const entries : ConflictEntry [ ] = [
59- { repo : "api" , stdout : "" , stderr : "" , subcommand : "rebase" } ,
60- { repo : "web" , stdout : "" , stderr : "" , subcommand : "rebase" } ,
85+ { repo : "api" , stdout : "" , stderr : "" , mode : "rebase" } ,
86+ { repo : "web" , stdout : "" , stderr : "" , mode : "rebase" } ,
6187 ] ;
6288 const nodes = buildConflictReport ( entries ) ;
6389
6490 const msg = nodes [ 1 ] as MessageNode ;
65- expect ( msg . text ) . toBe ( "2 repo(s) have conflicts:" ) ;
91+ expect ( msg . text ) . toBe ( "2 repos have conflicts:" ) ;
6692
67- // Structure: gap, message, gap, section(api), gap, section(web)
93+ // Structure: gap, message, gap, section(api), gap, section(web), gap, message, message, message
6894 const kinds = nodes . map ( ( n ) => n . kind ) ;
69- expect ( kinds ) . toEqual ( [ "gap" , "message" , "gap" , "section" , "gap" , "section" ] ) ;
95+ expect ( kinds ) . toEqual ( [
96+ "gap" ,
97+ "message" ,
98+ "gap" ,
99+ "section" ,
100+ "gap" ,
101+ "section" ,
102+ "gap" ,
103+ "message" ,
104+ "message" ,
105+ "message" ,
106+ ] ) ;
70107 } ) ;
71108} ) ;
72109
@@ -80,7 +117,7 @@ describe("buildStashPopFailureReport", () => {
80117
81118 expect ( nodes [ 0 ] ) . toEqual ( { kind : "gap" } ) ;
82119 const msg = nodes [ 1 ] as MessageNode ;
83- expect ( msg . text ) . toBe ( "1 repo(s) need manual stash application:" ) ;
120+ expect ( msg . text ) . toBe ( "1 repo needs manual stash application:" ) ;
84121
85122 expect ( nodes [ 2 ] ) . toEqual ( { kind : "gap" } ) ;
86123 const section = nodes [ 3 ] as SectionNode ;
0 commit comments