-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathunstack.go
More file actions
95 lines (84 loc) · 2.5 KB
/
unstack.go
File metadata and controls
95 lines (84 loc) · 2.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package cmd
import (
"errors"
"github.com/cli/go-gh/v2/pkg/api"
"github.com/github/gh-stack/internal/config"
"github.com/github/gh-stack/internal/stack"
"github.com/spf13/cobra"
)
type unstackOptions struct {
target string
local bool
}
func UnstackCmd(cfg *config.Config) *cobra.Command {
opts := &unstackOptions{}
cmd := &cobra.Command{
Use: "unstack [branch]",
Aliases: []string{"delete"},
Short: "Delete a stack locally and on GitHub",
Long: "Remove a stack from local tracking and delete it on GitHub. Use --local to only remove local tracking.",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
opts.target = args[0]
}
return runUnstack(cfg, opts)
},
}
cmd.Flags().BoolVar(&opts.local, "local", false, "Only delete the stack locally")
return cmd
}
func runUnstack(cfg *config.Config, opts *unstackOptions) error {
result, err := loadStack(cfg, opts.target)
if err != nil {
return ErrNotInStack
}
gitDir := result.GitDir
sf := result.StackFile
s := result.Stack
// Delete the stack on GitHub first (unless --local).
// Only proceed with local deletion after the remote operation succeeds.
if !opts.local {
if s.ID == "" {
cfg.Warningf("Stack has no remote ID — skipping server-side deletion")
} else {
client, err := cfg.GitHubClient()
if err != nil {
cfg.Errorf("failed to create GitHub client: %s", err)
return ErrAPIFailure
}
if err := client.DeleteStack(s.ID); err != nil {
var httpErr *api.HTTPError
if errors.As(err, &httpErr) {
switch httpErr.StatusCode {
case 404:
// Stack already deleted on GitHub — treat as success.
cfg.Warningf("Stack not found on GitHub — continuing with local unstack")
default:
cfg.Errorf("Failed to delete stack on GitHub (HTTP %d): %s", httpErr.StatusCode, httpErr.Message)
return ErrAPIFailure
}
} else {
cfg.Errorf("Failed to delete stack on GitHub: %v", err)
return ErrAPIFailure
}
} else {
cfg.Successf("Stack deleted on GitHub")
}
}
}
// Remove the exact resolved stack from local tracking by pointer identity,
// not by branch name — avoids removing the wrong stack when a trunk
// branch is shared across multiple stacks.
for i := range sf.Stacks {
if &sf.Stacks[i] == s {
sf.RemoveStack(i)
break
}
}
if err := stack.Save(gitDir, sf); err != nil {
return handleSaveError(cfg, err)
}
cfg.Successf("Stack removed from local tracking")
return nil
}