1package cmd
2
3import (
4 "fmt"
5 "strings"
6
7 "github.com/charmbracelet/soft-serve/git"
8 gitm "github.com/gogs/git-module"
9 "github.com/spf13/cobra"
10)
11
12func branchCommand() *cobra.Command {
13 cmd := &cobra.Command{
14 Use: "branch",
15 Short: "Manage repository branches",
16 }
17
18 cmd.AddCommand(
19 branchListCommand(),
20 branchDefaultCommand(),
21 branchDeleteCommand(),
22 )
23
24 return cmd
25}
26
27func branchListCommand() *cobra.Command {
28 cmd := &cobra.Command{
29 Use: "list REPOSITORY",
30 Short: "List repository branches",
31 Args: cobra.ExactArgs(1),
32 PersistentPreRunE: checkIfReadable,
33 RunE: func(cmd *cobra.Command, args []string) error {
34 be, _ := fromContext(cmd)
35 rn := strings.TrimSuffix(args[0], ".git")
36 ctx := cmd.Context()
37 rr, err := be.Repository(ctx, rn)
38 if err != nil {
39 return err
40 }
41
42 r, err := rr.Open()
43 if err != nil {
44 return err
45 }
46
47 branches, _ := r.Branches()
48 for _, b := range branches {
49 cmd.Println(b)
50 }
51
52 return nil
53 },
54 }
55
56 return cmd
57}
58
59func branchDefaultCommand() *cobra.Command {
60 cmd := &cobra.Command{
61 Use: "default REPOSITORY [BRANCH]",
62 Short: "Set or get the default branch",
63 Args: cobra.RangeArgs(1, 2),
64 RunE: func(cmd *cobra.Command, args []string) error {
65 ctx := cmd.Context()
66 be, _ := fromContext(cmd)
67 rn := strings.TrimSuffix(args[0], ".git")
68 switch len(args) {
69 case 1:
70 if err := checkIfReadable(cmd, args); err != nil {
71 return err
72 }
73
74 rr, err := be.Repository(ctx, rn)
75 if err != nil {
76 return err
77 }
78
79 r, err := rr.Open()
80 if err != nil {
81 return err
82 }
83
84 head, err := r.HEAD()
85 if err != nil {
86 return err
87 }
88
89 cmd.Println(head.Name().Short())
90 case 2:
91 if err := checkIfCollab(cmd, args); err != nil {
92 return err
93 }
94
95 rr, err := be.Repository(ctx, rn)
96 if err != nil {
97 return err
98 }
99
100 r, err := rr.Open()
101 if err != nil {
102 return err
103 }
104
105 branch := args[1]
106 branches, _ := r.Branches()
107 var exists bool
108 for _, b := range branches {
109 if branch == b {
110 exists = true
111 break
112 }
113 }
114
115 if !exists {
116 return git.ErrReferenceNotExist
117 }
118
119 if _, err := r.SymbolicRef("HEAD", gitm.RefsHeads+branch); err != nil {
120 return err
121 }
122 }
123
124 return nil
125 },
126 }
127
128 return cmd
129}
130
131func branchDeleteCommand() *cobra.Command {
132 cmd := &cobra.Command{
133 Use: "delete REPOSITORY BRANCH",
134 Aliases: []string{"remove", "rm", "del"},
135 Short: "Delete a branch",
136 PersistentPreRunE: checkIfCollab,
137 RunE: func(cmd *cobra.Command, args []string) error {
138 ctx := cmd.Context()
139 be, _ := fromContext(cmd)
140 rn := strings.TrimSuffix(args[0], ".git")
141 rr, err := be.Repository(ctx, rn)
142 if err != nil {
143 return err
144 }
145
146 r, err := rr.Open()
147 if err != nil {
148 return err
149 }
150
151 branch := args[1]
152 branches, _ := r.Branches()
153 var exists bool
154 for _, b := range branches {
155 if branch == b {
156 exists = true
157 break
158 }
159 }
160
161 if !exists {
162 return git.ErrReferenceNotExist
163 }
164
165 head, err := r.HEAD()
166 if err != nil {
167 return err
168 }
169
170 if head.Name().Short() == branch {
171 return fmt.Errorf("cannot delete the default branch")
172 }
173
174 if err := r.DeleteBranch(branch, gitm.DeleteBranchOptions{Force: true}); err != nil {
175 return err
176 }
177
178 return nil
179 },
180 }
181
182 return cmd
183}