Skip to content

Commit 4b6f2bd

Browse files
committed
adressing review comments
1 parent d07c2be commit 4b6f2bd

3 files changed

Lines changed: 64 additions & 22 deletions

File tree

cmd/init.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -307,11 +307,11 @@ func runInit(cfg *config.Config, opts *initOptions) error {
307307
// Discover existing PRs for the new stack's branches.
308308
// For adopt, only record open/draft PRs (ignore closed/merged).
309309
// For non-adopt, use the standard sync which also detects merges.
310-
newStack_ := &sf.Stacks[len(sf.Stacks)-1]
310+
latestStack := &sf.Stacks[len(sf.Stacks)-1]
311311
if opts.adopt {
312312
if client, clientErr := cfg.GitHubClient(); clientErr == nil {
313-
for i := range newStack_.Branches {
314-
b := &newStack_.Branches[i]
313+
for i := range latestStack.Branches {
314+
b := &latestStack.Branches[i]
315315
pr, err := client.FindPRForBranch(b.Branch)
316316
if err != nil || pr == nil {
317317
continue
@@ -324,7 +324,7 @@ func runInit(cfg *config.Config, opts *initOptions) error {
324324
}
325325
}
326326
} else {
327-
syncStackPRs(cfg, newStack_)
327+
syncStackPRs(cfg, latestStack)
328328
}
329329

330330
if err := stack.Save(gitDir, sf); err != nil {

cmd/unstack.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,6 @@ func runUnstack(cfg *config.Config, opts *unstackOptions) error {
4444
gitDir := result.GitDir
4545
sf := result.StackFile
4646
s := result.Stack
47-
target := opts.target
48-
if target == "" {
49-
target = result.CurrentBranch
50-
}
51-
52-
cfg.Printf("Stack branches: %v", s.BranchNames())
5347

5448
// Delete the stack on GitHub first (unless --local).
5549
// Only proceed with local deletion after the remote operation succeeds.
@@ -65,18 +59,33 @@ func runUnstack(cfg *config.Config, opts *unstackOptions) error {
6559
if err := client.DeleteStack(s.ID); err != nil {
6660
var httpErr *api.HTTPError
6761
if errors.As(err, &httpErr) {
68-
cfg.Errorf("Failed to delete stack on GitHub (HTTP %d): %s", httpErr.StatusCode, httpErr.Message)
62+
switch httpErr.StatusCode {
63+
case 404:
64+
// Stack already deleted on GitHub — treat as success.
65+
cfg.Warningf("Stack not found on GitHub — continuing with local unstack")
66+
default:
67+
cfg.Errorf("Failed to delete stack on GitHub (HTTP %d): %s", httpErr.StatusCode, httpErr.Message)
68+
return ErrAPIFailure
69+
}
6970
} else {
7071
cfg.Errorf("Failed to delete stack on GitHub: %v", err)
72+
return ErrAPIFailure
7173
}
72-
return ErrAPIFailure
74+
} else {
75+
cfg.Successf("Stack deleted on GitHub")
7376
}
74-
cfg.Successf("Stack deleted on GitHub")
7577
}
7678
}
7779

78-
// Remove from local tracking
79-
sf.RemoveStackForBranch(target)
80+
// Remove the exact resolved stack from local tracking by pointer identity,
81+
// not by branch name — avoids removing the wrong stack when a trunk
82+
// branch is shared across multiple stacks.
83+
for i := range sf.Stacks {
84+
if &sf.Stacks[i] == s {
85+
sf.RemoveStack(i)
86+
break
87+
}
88+
}
8089
if err := stack.Save(gitDir, sf); err != nil {
8190
return handleSaveError(cfg, err)
8291
}

cmd/unstack_test.go

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func TestUnstack_NoStackID_WarnsAndSkipsAPI(t *testing.T) {
157157
assert.NotContains(t, output, "Stack deleted on GitHub")
158158
}
159159

160-
func TestUnstack_API404_ShowsErrorAndStopsLocalDeletion(t *testing.T) {
160+
func TestUnstack_API404_TreatedAsIdempotentSuccess(t *testing.T) {
161161
gitDir := t.TempDir()
162162
restore := git.SetOps(&git.MockOps{
163163
GitDirFn: func() (string, error) { return gitDir, nil },
@@ -180,15 +180,14 @@ func TestUnstack_API404_ShowsErrorAndStopsLocalDeletion(t *testing.T) {
180180
err := runUnstack(cfg, &unstackOptions{})
181181
output := collectOutput(cfg, outR, errR)
182182

183-
assert.ErrorIs(t, err, ErrAPIFailure)
184-
assert.Contains(t, output, "Failed to delete stack on GitHub (HTTP 404)")
185-
// Should NOT remove locally when remote fails
186-
assert.NotContains(t, output, "Stack removed from local tracking")
183+
// 404 means already deleted — should succeed and remove locally
184+
require.NoError(t, err)
185+
assert.Contains(t, output, "continuing with local unstack")
186+
assert.Contains(t, output, "Stack removed from local tracking")
187187

188-
// Stack should still exist locally
189188
sf, err := stack.Load(gitDir)
190189
require.NoError(t, err)
191-
require.Len(t, sf.Stacks, 1)
190+
assert.Empty(t, sf.Stacks)
192191
}
193192

194193
func TestUnstack_API409_ShowsErrorAndStopsLocalDeletion(t *testing.T) {
@@ -224,3 +223,37 @@ func TestUnstack_API409_ShowsErrorAndStopsLocalDeletion(t *testing.T) {
224223
require.NoError(t, err)
225224
require.Len(t, sf.Stacks, 1)
226225
}
226+
227+
func TestUnstack_RemovesCorrectStackByPointer(t *testing.T) {
228+
// Two stacks share the same trunk "main". Targeting "b3" should remove
229+
// only the second stack (b3,b4), leaving the first (b1,b2) intact.
230+
// This verifies pointer-based removal instead of branch-name-based.
231+
gitDir := t.TempDir()
232+
restore := git.SetOps(&git.MockOps{
233+
GitDirFn: func() (string, error) { return gitDir, nil },
234+
CurrentBranchFn: func() (string, error) { return "b3", nil },
235+
})
236+
defer restore()
237+
238+
s1 := stack.Stack{
239+
Trunk: stack.BranchRef{Branch: "main"},
240+
Branches: []stack.BranchRef{{Branch: "b1"}, {Branch: "b2"}},
241+
}
242+
s2 := stack.Stack{
243+
Trunk: stack.BranchRef{Branch: "main"},
244+
Branches: []stack.BranchRef{{Branch: "b3"}, {Branch: "b4"}},
245+
}
246+
writeTwoStacks(t, gitDir, s1, s2)
247+
248+
cfg, outR, errR := config.NewTestConfig()
249+
err := runUnstack(cfg, &unstackOptions{target: "b3", local: true})
250+
output := collectOutput(cfg, outR, errR)
251+
252+
require.NoError(t, err)
253+
assert.Contains(t, output, "Stack removed from local tracking")
254+
255+
sf, err := stack.Load(gitDir)
256+
require.NoError(t, err)
257+
require.Len(t, sf.Stacks, 1, "should remove exactly one stack")
258+
assert.Equal(t, []string{"b1", "b2"}, sf.Stacks[0].BranchNames(), "should keep the OTHER stack intact")
259+
}

0 commit comments

Comments
 (0)