branch.go

  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}