Skip to content

Commit 22fa202

Browse files
committed
shared loadStack helper for all cmds
1 parent e874e26 commit 22fa202

7 files changed

Lines changed: 96 additions & 196 deletions

File tree

cmd/add.go

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -55,40 +55,14 @@ func runAdd(cfg *config.Config, opts *addOptions, args []string) error {
5555
return nil
5656
}
5757

58-
gitDir, err := git.GitDir()
58+
result, err := loadStack(cfg, "")
5959
if err != nil {
60-
cfg.Errorf("not a git repository")
61-
return nil
62-
}
63-
64-
sf, err := stack.Load(gitDir)
65-
if err != nil {
66-
cfg.Errorf("failed to load stack state: %s", err)
67-
return nil
68-
}
69-
70-
currentBranch, err := git.CurrentBranch()
71-
if err != nil {
72-
cfg.Errorf("failed to get current branch: %s", err)
73-
return nil
74-
}
75-
76-
s, err := resolveStack(sf, currentBranch, cfg)
77-
if err != nil {
78-
cfg.Errorf("%s", err)
79-
return nil
80-
}
81-
if s == nil {
82-
cfg.Errorf("current branch %q is not part of a stack; run 'gh stack init' first", currentBranch)
83-
return nil
84-
}
85-
86-
// Re-read current branch in case disambiguation caused a checkout
87-
currentBranch, err = git.CurrentBranch()
88-
if err != nil {
89-
cfg.Errorf("failed to get current branch: %s", err)
9060
return nil
9161
}
62+
gitDir := result.GitDir
63+
sf := result.StackFile
64+
s := result.Stack
65+
currentBranch := result.CurrentBranch
9266

9367
if s.IsFullyMerged() {
9468
cfg.Warningf("All branches in this stack have been merged")

cmd/navigate.go

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55

66
"github.com/github/gh-stack/internal/config"
77
"github.com/github/gh-stack/internal/git"
8-
"github.com/github/gh-stack/internal/stack"
98
"github.com/spf13/cobra"
109
)
1110

@@ -60,10 +59,12 @@ func BottomCmd(cfg *config.Config) *cobra.Command {
6059
}
6160

6261
func runNavigate(cfg *config.Config, delta int) error {
63-
s, currentBranch, err := loadCurrentStack(cfg)
62+
result, err := loadStack(cfg, "")
6463
if err != nil {
6564
return nil
6665
}
66+
s := result.Stack
67+
currentBranch := result.CurrentBranch
6768

6869
idx := s.IndexOf(currentBranch)
6970
if idx < 0 {
@@ -181,11 +182,12 @@ func runNavigate(cfg *config.Config, delta int) error {
181182
}
182183

183184
func runNavigateToEnd(cfg *config.Config, top bool) error {
184-
s, currentBranch, err := loadCurrentStack(cfg)
185+
result, err := loadStack(cfg, "")
185186
if err != nil {
186-
cfg.Errorf("failed to load current stack: %s", err)
187187
return nil
188188
}
189+
s := result.Stack
190+
currentBranch := result.CurrentBranch
189191

190192
if len(s.Branches) == 0 {
191193
cfg.Errorf("stack has no branches")
@@ -226,51 +228,6 @@ func runNavigateToEnd(cfg *config.Config, top bool) error {
226228
return nil
227229
}
228230

229-
func loadCurrentStack(cfg *config.Config) (*stack.Stack, string, error) {
230-
gitDir, err := git.GitDir()
231-
if err != nil {
232-
errMsg := "not a git repository"
233-
cfg.Errorf("%s", errMsg)
234-
return nil, "", fmt.Errorf("%s", errMsg)
235-
}
236-
237-
sf, err := stack.Load(gitDir)
238-
if err != nil {
239-
errMsg := fmt.Sprintf("failed to load stack state: %s", err)
240-
cfg.Errorf("%s", errMsg)
241-
return nil, "", fmt.Errorf("%s", errMsg)
242-
}
243-
244-
currentBranch, err := git.CurrentBranch()
245-
if err != nil {
246-
errMsg := fmt.Sprintf("failed to get current branch: %s", err)
247-
cfg.Errorf("%s", errMsg)
248-
return nil, "", fmt.Errorf("%s", errMsg)
249-
}
250-
251-
s, err := resolveStack(sf, currentBranch, cfg)
252-
if err != nil {
253-
cfg.Errorf("%s", err)
254-
return nil, "", err
255-
}
256-
if s == nil {
257-
errMsg := fmt.Sprintf("current branch %q is not part of a stack", currentBranch)
258-
cfg.Errorf("current branch %q is not part of a stack", currentBranch)
259-
cfg.Printf("Checkout an existing stack using %s or create a new stack using %s", cfg.ColorCyan("gh stack checkout"), cfg.ColorCyan("gh stack init"))
260-
return nil, "", fmt.Errorf("%s", errMsg)
261-
}
262-
263-
// Re-read current branch in case disambiguation caused a checkout
264-
currentBranch, err = git.CurrentBranch()
265-
if err != nil {
266-
errMsg := fmt.Sprintf("failed to get current branch: %s", err)
267-
cfg.Errorf("%s", errMsg)
268-
return nil, "", fmt.Errorf("%s", errMsg)
269-
}
270-
271-
return s, currentBranch, nil
272-
}
273-
274231
func plural(n int, singular, pluralForm string) string {
275232
if n == 1 {
276233
return singular

cmd/rebase.go

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -79,37 +79,13 @@ func runRebase(cfg *config.Config, opts *rebaseOptions) error {
7979
return abortRebase(cfg, gitDir)
8080
}
8181

82-
sf, err := stack.Load(gitDir)
83-
if err != nil {
84-
cfg.Errorf("failed to load stack state: %s", err)
85-
return nil
86-
}
87-
88-
currentBranch := opts.branch
89-
if currentBranch == "" {
90-
currentBranch, err = git.CurrentBranch()
91-
if err != nil {
92-
cfg.Errorf("unable to determine current branch: %s", err)
93-
return nil
94-
}
95-
}
96-
97-
s, err := resolveStack(sf, currentBranch, cfg)
98-
if err != nil {
99-
cfg.Errorf("%s", err)
100-
return nil
101-
}
102-
if s == nil {
103-
cfg.Errorf("no stack found for branch %s", currentBranch)
104-
return nil
105-
}
106-
107-
// Re-read current branch in case disambiguation caused a checkout
108-
currentBranch, err = git.CurrentBranch()
82+
result, err := loadStack(cfg, opts.branch)
10983
if err != nil {
110-
cfg.Errorf("failed to get current branch: %s", err)
11184
return nil
11285
}
86+
sf := result.StackFile
87+
s := result.Stack
88+
currentBranch := result.CurrentBranch
11389

11490
// Enable git rerere so conflict resolutions are remembered.
11591
_ = git.EnableRerere()

cmd/sync.go

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,40 +40,14 @@ conflicts interactively.`,
4040
}
4141

4242
func runSync(cfg *config.Config, _ *syncOptions) error {
43-
gitDir, err := git.GitDir()
43+
result, err := loadStack(cfg, "")
4444
if err != nil {
45-
cfg.Errorf("not a git repository")
46-
return nil
47-
}
48-
49-
sf, err := stack.Load(gitDir)
50-
if err != nil {
51-
cfg.Errorf("failed to load stack state: %s", err)
52-
return nil
53-
}
54-
55-
currentBranch, err := git.CurrentBranch()
56-
if err != nil {
57-
cfg.Errorf("failed to get current branch: %s", err)
58-
return nil
59-
}
60-
61-
s, err := resolveStack(sf, currentBranch, cfg)
62-
if err != nil {
63-
cfg.Errorf("%s", err)
64-
return nil
65-
}
66-
if s == nil {
67-
cfg.Errorf("current branch %q is not part of a stack", currentBranch)
68-
return nil
69-
}
70-
71-
// Re-read current branch in case disambiguation caused a checkout
72-
currentBranch, err = git.CurrentBranch()
73-
if err != nil {
74-
cfg.Errorf("failed to get current branch: %s", err)
7545
return nil
7646
}
47+
gitDir := result.GitDir
48+
sf := result.StackFile
49+
s := result.Stack
50+
currentBranch := result.CurrentBranch
7751

7852
// Resolve remote once for fetch and push
7953
remote, err := pickRemote(cfg, currentBranch)

cmd/unstack.go

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package cmd
22

33
import (
44
"github.com/github/gh-stack/internal/config"
5-
"github.com/github/gh-stack/internal/git"
65
"github.com/github/gh-stack/internal/stack"
76
"github.com/spf13/cobra"
87
)
@@ -34,35 +33,16 @@ func UnstackCmd(cfg *config.Config) *cobra.Command {
3433
}
3534

3635
func runUnstack(cfg *config.Config, opts *unstackOptions) error {
37-
gitDir, err := git.GitDir()
36+
result, err := loadStack(cfg, opts.target)
3837
if err != nil {
39-
cfg.Errorf("not a git repository")
4038
return nil
4139
}
42-
43-
sf, err := stack.Load(gitDir)
44-
if err != nil {
45-
cfg.Errorf("failed to load stack state: %s", err)
46-
return nil
47-
}
48-
40+
gitDir := result.GitDir
41+
sf := result.StackFile
42+
s := result.Stack
4943
target := opts.target
5044
if target == "" {
51-
target, err = git.CurrentBranch()
52-
if err != nil {
53-
cfg.Errorf("unable to determine current branch: %s", err)
54-
return nil
55-
}
56-
}
57-
58-
s, err := resolveStack(sf, target, cfg)
59-
if err != nil {
60-
cfg.Errorf("%s", err)
61-
return nil
62-
}
63-
if s == nil {
64-
cfg.Errorf("branch %q is not part of a stack", target)
65-
return nil
45+
target = result.CurrentBranch
6646
}
6747

6848
cfg.Printf("Stack branches: %v", s.BranchNames())

cmd/utils.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,72 @@ import (
99
"github.com/github/gh-stack/internal/stack"
1010
)
1111

12+
// loadStackResult holds everything returned by loadStack.
13+
type loadStackResult struct {
14+
GitDir string
15+
StackFile *stack.StackFile
16+
Stack *stack.Stack
17+
CurrentBranch string
18+
}
19+
20+
// loadStack is the standard way to obtain a Stack for the current (or given)
21+
// branch. It resolves the git directory, loads the stack file, determines the
22+
// branch, calls resolveStack (which may prompt for disambiguation), checks for
23+
// a nil stack, and re-reads the current branch (in case disambiguation caused
24+
// a checkout). Errors are printed via cfg and returned.
25+
func loadStack(cfg *config.Config, branch string) (*loadStackResult, error) {
26+
gitDir, err := git.GitDir()
27+
if err != nil {
28+
cfg.Errorf("not a git repository")
29+
return nil, fmt.Errorf("not a git repository")
30+
}
31+
32+
sf, err := stack.Load(gitDir)
33+
if err != nil {
34+
cfg.Errorf("failed to load stack state: %s", err)
35+
return nil, fmt.Errorf("failed to load stack state: %w", err)
36+
}
37+
38+
branchFromArg := branch != ""
39+
if branch == "" {
40+
branch, err = git.CurrentBranch()
41+
if err != nil {
42+
cfg.Errorf("failed to get current branch: %s", err)
43+
return nil, fmt.Errorf("failed to get current branch: %w", err)
44+
}
45+
}
46+
47+
s, err := resolveStack(sf, branch, cfg)
48+
if err != nil {
49+
cfg.Errorf("%s", err)
50+
return nil, err
51+
}
52+
if s == nil {
53+
if branchFromArg {
54+
cfg.Errorf("branch %q is not part of a stack", branch)
55+
} else {
56+
cfg.Errorf("current branch %q is not part of a stack", branch)
57+
}
58+
cfg.Printf("Checkout an existing stack using %s or create a new stack using %s",
59+
cfg.ColorCyan("gh stack checkout"), cfg.ColorCyan("gh stack init"))
60+
return nil, fmt.Errorf("branch %q is not part of a stack", branch)
61+
}
62+
63+
// Re-read current branch in case disambiguation caused a checkout.
64+
currentBranch, err := git.CurrentBranch()
65+
if err != nil {
66+
cfg.Errorf("failed to get current branch: %s", err)
67+
return nil, fmt.Errorf("failed to get current branch: %w", err)
68+
}
69+
70+
return &loadStackResult{
71+
GitDir: gitDir,
72+
StackFile: sf,
73+
Stack: s,
74+
CurrentBranch: currentBranch,
75+
}, nil
76+
}
77+
1278
// resolveStack finds the stack for the given branch, handling ambiguity when
1379
// a branch (typically a trunk) belongs to multiple stacks. If exactly one
1480
// stack matches, it is returned directly. If multiple stacks match, the user

cmd/view.go

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -40,41 +40,14 @@ func ViewCmd(cfg *config.Config) *cobra.Command {
4040
}
4141

4242
func runView(cfg *config.Config, opts *viewOptions) error {
43-
gitDir, err := git.GitDir()
43+
result, err := loadStack(cfg, "")
4444
if err != nil {
45-
cfg.Errorf("not a git repository")
46-
return nil
47-
}
48-
49-
sf, err := stack.Load(gitDir)
50-
if err != nil {
51-
cfg.Errorf("failed to load stack state: %s", err)
52-
return nil
53-
}
54-
55-
currentBranch, err := git.CurrentBranch()
56-
if err != nil {
57-
cfg.Errorf("failed to get current branch: %s", err)
58-
return nil
59-
}
60-
61-
s, err := resolveStack(sf, currentBranch, cfg)
62-
if err != nil {
63-
cfg.Errorf("%s", err)
64-
return nil
65-
}
66-
if s == nil {
67-
cfg.Errorf("current branch %q is not part of a stack", currentBranch)
68-
cfg.Printf("Checkout an existing stack using %s or create a new stack using %s", cfg.ColorCyan("gh stack checkout"), cfg.ColorCyan("gh stack init"))
69-
return nil
70-
}
71-
72-
// Re-read current branch in case disambiguation caused a checkout
73-
currentBranch, err = git.CurrentBranch()
74-
if err != nil {
75-
cfg.Errorf("failed to get current branch: %s", err)
7645
return nil
7746
}
47+
gitDir := result.GitDir
48+
sf := result.StackFile
49+
s := result.Stack
50+
currentBranch := result.CurrentBranch
7851

7952
// Sync PR state
8053
syncStackPRs(cfg, s)

0 commit comments

Comments
 (0)