Skip to content

Commit 7888026

Browse files
committed
address review comments
1 parent ea4d716 commit 7888026

4 files changed

Lines changed: 60 additions & 6 deletions

File tree

cmd/unstack.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ func runUnstack(cfg *config.Config, opts *unstackOptions) error {
7272
// GitHub by number (remote-first), so this works from anywhere in the
7373
// repository whether or not the stack is tracked locally.
7474
if opts.stackNumber > 0 {
75-
result, ok, err := lookupStackByNumber(cfg, opts.stackNumber)
75+
// --local must never contact GitHub, so it uses a strictly local lookup
76+
result, ok, err := lookupStackByNumber(cfg, opts.stackNumber, !opts.local)
7677
if err != nil {
7778
return ErrNotInStack
7879
}

cmd/unstack_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,55 @@ func TestUnstack_ByStackNumber_NotTracked_LocalFlag(t *testing.T) {
632632
require.Len(t, sf.Stacks, 1)
633633
}
634634

635+
func TestUnstack_ByStackNumber_LocalFlag_LegacyStack_NoRemoteCall(t *testing.T) {
636+
// --local must never contact GitHub. A legacy stack (Number == 0) can only
637+
// be matched by number via a remote backfill (ListStacks); under --local
638+
// that lookup must be skipped and the number reported as not tracked.
639+
gitDir := t.TempDir()
640+
restore := git.SetOps(&git.MockOps{
641+
GitDirFn: func() (string, error) { return gitDir, nil },
642+
CurrentBranchFn: func() (string, error) { return "b1", nil },
643+
})
644+
defer restore()
645+
646+
// Legacy: internal ID present, Number unset (0).
647+
writeStackFile(t, gitDir, stack.Stack{
648+
ID: "99",
649+
Trunk: stack.BranchRef{Branch: "main"},
650+
Branches: []stack.BranchRef{
651+
{Branch: "b1", PullRequest: &stack.PullRequestRef{Number: 101}},
652+
{Branch: "b2", PullRequest: &stack.PullRequestRef{Number: 102}},
653+
},
654+
})
655+
656+
listCalled := false
657+
unstackCalled := false
658+
cfg, outR, errR := config.NewTestConfig()
659+
cfg.GitHubClientOverride = &github.MockClient{
660+
ListStacksFn: func() ([]github.RemoteStack, error) {
661+
listCalled = true
662+
return []github.RemoteStack{{ID: 99, Number: 7, PullRequests: []int{101, 102}}}, nil
663+
},
664+
UnstackFn: func(int) (*github.RemoteStack, bool, error) {
665+
unstackCalled = true
666+
return nil, true, nil
667+
},
668+
}
669+
670+
err := runUnstack(cfg, &unstackOptions{stackNumber: 7, local: true})
671+
output := collectOutput(cfg, outR, errR)
672+
673+
assert.ErrorIs(t, err, ErrNotInStack)
674+
assert.False(t, listCalled, "--local must not contact GitHub (no ListStacks backfill)")
675+
assert.False(t, unstackCalled, "--local must not contact GitHub")
676+
assert.Contains(t, output, "stack #7 is not tracked locally")
677+
678+
// Local tracking is untouched.
679+
sf, loadErr := stack.Load(gitDir)
680+
require.NoError(t, loadErr)
681+
require.Len(t, sf.Stacks, 1)
682+
}
683+
635684
func TestUnstack_ByStackNumber_LegacyStackResolvedByID(t *testing.T) {
636685
// A stack tracked before the number was recorded (Number == 0) is resolved
637686
// by mapping its internal ID to the remote stack number, and the backfilled

cmd/utils.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,11 @@ func loadStack(cfg *config.Config, branch string) (*loadStackResult, error) {
269269
//
270270
// Stack files created before the number was tracked store only the internal ID
271271
// (Number == 0); such legacy stacks are resolved by mapping their ID to a remote
272-
// stack number so they can still be targeted by number.
273-
func lookupStackByNumber(cfg *config.Config, number int) (result *loadStackResult, ok bool, err error) {
272+
// stack number so they can still be targeted by number. That mapping contacts
273+
// GitHub (ListStacks), so it is only attempted when allowRemote is true — callers
274+
// that must stay purely local (e.g. `--local`) pass false, and legacy stacks
275+
// whose number isn't recorded locally are reported as not tracked.
276+
func lookupStackByNumber(cfg *config.Config, number int, allowRemote bool) (result *loadStackResult, ok bool, err error) {
274277
gitDir, err := git.GitDir()
275278
if err != nil {
276279
// Not a git repository — nothing can be tracked locally.
@@ -290,8 +293,9 @@ func lookupStackByNumber(cfg *config.Config, number int) (result *loadStackResul
290293

291294
// No direct match — backfill legacy stacks' numbers from the remote and
292295
// retry, so `gh stack unstack <number>` also works for stacks tracked
293-
// before the number was recorded locally.
294-
if backfillLegacyStackNumbers(cfg, sf, gitDir) {
296+
// before the number was recorded locally. This reaches GitHub, so it is
297+
// skipped when the caller requires a purely local lookup.
298+
if allowRemote && backfillLegacyStackNumbers(cfg, sf, gitDir) {
295299
if result := stackResultByNumber(sf, gitDir, number); result != nil {
296300
return result, true, nil
297301
}

docs/src/content/docs/reference/cli.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ This is useful when you need to restructure a stack — remove a branch, insert
258258
# Unstack the current stack on GitHub and remove local tracking
259259
gh stack unstack
260260

261-
# Unstack a specific stack by its numbe
261+
# Unstack a specific stack by its number
262262
gh stack unstack 7
263263

264264
# Only remove local tracking

0 commit comments

Comments
 (0)