@@ -62,7 +62,7 @@ func TestPush_PushesAllBranches(t *testing.T) {
6262 assert .Equal (t , "origin" , pushCalls [0 ].remote )
6363 assert .Equal (t , []string {"b1" , "b2" }, pushCalls [0 ].branches )
6464 assert .True (t , pushCalls [0 ].force )
65- assert .True (t , pushCalls [0 ].atomic )
65+ assert .False (t , pushCalls [0 ].atomic )
6666 assert .Contains (t , output , "Pushed 2 branches" )
6767 assert .Contains (t , output , "gh stack submit" , "should hint about submit when branches have no PRs" )
6868}
@@ -182,6 +182,89 @@ func TestPush_PushFailure(t *testing.T) {
182182 assert .Contains (t , output , "failed to push" )
183183}
184184
185+ func TestPush_FetchesBeforePush (t * testing.T ) {
186+ s := stack.Stack {
187+ Trunk : stack.BranchRef {Branch : "main" },
188+ Branches : []stack.BranchRef {
189+ {Branch : "b1" },
190+ {Branch : "b2" },
191+ },
192+ }
193+
194+ tmpDir := t .TempDir ()
195+ writeStackFile (t , tmpDir , s )
196+
197+ var callOrder []string
198+
199+ mock := newPushMock (tmpDir , "b1" )
200+ mock .FetchBranchesFn = func (remote string , branches []string ) error {
201+ callOrder = append (callOrder , "fetch" )
202+ assert .Equal (t , "origin" , remote )
203+ assert .Equal (t , []string {"b1" , "b2" }, branches )
204+ return nil
205+ }
206+ mock .PushFn = func (remote string , branches []string , force , atomic bool ) error {
207+ callOrder = append (callOrder , "push" )
208+ return nil
209+ }
210+
211+ restore := git .SetOps (mock )
212+ defer restore ()
213+
214+ cfg , _ , errR := config .NewTestConfig ()
215+ cfg .GitHubClientOverride = & github.MockClient {}
216+ cmd := PushCmd (cfg )
217+ cmd .SetOut (io .Discard )
218+ cmd .SetErr (io .Discard )
219+ err := cmd .Execute ()
220+
221+ cfg .Err .Close ()
222+ _ , _ = io .ReadAll (errR )
223+
224+ assert .NoError (t , err )
225+ assert .Equal (t , []string {"fetch" , "push" }, callOrder , "fetch must happen before push" )
226+ }
227+
228+ func TestPush_FetchFailureIsNonFatal (t * testing.T ) {
229+ s := stack.Stack {
230+ Trunk : stack.BranchRef {Branch : "main" },
231+ Branches : []stack.BranchRef {
232+ {Branch : "b1" },
233+ },
234+ }
235+
236+ tmpDir := t .TempDir ()
237+ writeStackFile (t , tmpDir , s )
238+
239+ pushCalled := false
240+
241+ mock := newPushMock (tmpDir , "b1" )
242+ mock .FetchBranchesFn = func (string , []string ) error {
243+ return fmt .Errorf ("network error" )
244+ }
245+ mock .PushFn = func (string , []string , bool , bool ) error {
246+ pushCalled = true
247+ return nil
248+ }
249+
250+ restore := git .SetOps (mock )
251+ defer restore ()
252+
253+ cfg , _ , errR := config .NewTestConfig ()
254+ cfg .GitHubClientOverride = & github.MockClient {}
255+ cmd := PushCmd (cfg )
256+ cmd .SetOut (io .Discard )
257+ cmd .SetErr (io .Discard )
258+ err := cmd .Execute ()
259+
260+ cfg .Err .Close ()
261+ errOut , _ := io .ReadAll (errR )
262+
263+ assert .NoError (t , err , "fetch failure should not abort push" )
264+ assert .True (t , pushCalled , "push should proceed after fetch failure" )
265+ assert .Contains (t , string (errOut ), "Failed to fetch" )
266+ }
267+
185268func TestPush_DoesNotCreatePRs (t * testing.T ) {
186269 s := stack.Stack {
187270 Trunk : stack.BranchRef {Branch : "main" },
0 commit comments