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