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("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 := backend.FromContext(ctx)
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 return r.DeleteBranch(branch, gitm.DeleteBranchOptions{Force: true})
175 },
176 }
177
178 return cmd
179}