186 lines
4.6 KiB
Go
186 lines
4.6 KiB
Go
|
|
package cmd
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
|
||
|
|
"code.gitea.io/sdk/gitea"
|
||
|
|
"forgejo.zerova.net/public/fgj-sid/internal/api"
|
||
|
|
"forgejo.zerova.net/public/fgj-sid/internal/config"
|
||
|
|
"github.com/spf13/cobra"
|
||
|
|
)
|
||
|
|
|
||
|
|
var branchCmd = &cobra.Command{
|
||
|
|
Use: "branch",
|
||
|
|
Aliases: []string{"b"},
|
||
|
|
Short: "Manage repository branches",
|
||
|
|
Long: "List, rename, and delete branches in a repository.",
|
||
|
|
}
|
||
|
|
|
||
|
|
var branchListCmd = &cobra.Command{
|
||
|
|
Use: "list",
|
||
|
|
Short: "List repository branches",
|
||
|
|
Long: "List branches in a repository, showing protection status.",
|
||
|
|
Example: ` # List branches in the current repository
|
||
|
|
fgj branch list
|
||
|
|
|
||
|
|
# List branches in a specific repository
|
||
|
|
fgj branch list -R owner/repo
|
||
|
|
|
||
|
|
# Output as JSON
|
||
|
|
fgj branch list --json`,
|
||
|
|
RunE: runBranchList,
|
||
|
|
}
|
||
|
|
|
||
|
|
var branchRenameCmd = &cobra.Command{
|
||
|
|
Use: "rename <old-name> <new-name>",
|
||
|
|
Short: "Rename a branch",
|
||
|
|
Long: "Rename a branch in a repository. Requires Forgejo/Gitea support for branch rename (usually present).",
|
||
|
|
Example: ` # Rename a branch in the current repository
|
||
|
|
fgj branch rename old-name new-name
|
||
|
|
|
||
|
|
# Rename a branch in a specific repository
|
||
|
|
fgj branch rename main trunk -R owner/repo`,
|
||
|
|
Args: cobra.ExactArgs(2),
|
||
|
|
RunE: runBranchRename,
|
||
|
|
}
|
||
|
|
|
||
|
|
var branchDeleteCmd = &cobra.Command{
|
||
|
|
Use: "delete <name>",
|
||
|
|
Aliases: []string{"rm"},
|
||
|
|
Short: "Delete a branch",
|
||
|
|
Long: "Delete a branch from a repository. Protected branches cannot be deleted.",
|
||
|
|
Example: ` # Delete a branch
|
||
|
|
fgj branch delete feature/old-work
|
||
|
|
|
||
|
|
# Delete without confirmation
|
||
|
|
fgj branch delete feature/old-work -y`,
|
||
|
|
Args: cobra.ExactArgs(1),
|
||
|
|
RunE: runBranchDelete,
|
||
|
|
}
|
||
|
|
|
||
|
|
func init() {
|
||
|
|
rootCmd.AddCommand(branchCmd)
|
||
|
|
branchCmd.AddCommand(branchListCmd)
|
||
|
|
branchCmd.AddCommand(branchRenameCmd)
|
||
|
|
branchCmd.AddCommand(branchDeleteCmd)
|
||
|
|
|
||
|
|
addRepoFlags(branchListCmd)
|
||
|
|
addJSONFlags(branchListCmd, "Output as JSON")
|
||
|
|
|
||
|
|
addRepoFlags(branchRenameCmd)
|
||
|
|
|
||
|
|
addRepoFlags(branchDeleteCmd)
|
||
|
|
branchDeleteCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt")
|
||
|
|
}
|
||
|
|
|
||
|
|
func runBranchList(cmd *cobra.Command, args []string) error {
|
||
|
|
client, owner, name, err := newBranchClient(cmd)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
branches, _, err := client.ListRepoBranches(owner, name, gitea.ListRepoBranchesOptions{})
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to list branches: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if wantJSON(cmd) {
|
||
|
|
return outputJSON(cmd, branches)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(branches) == 0 {
|
||
|
|
fmt.Fprintln(ios.Out, "No branches found")
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
tp := ios.NewTablePrinter()
|
||
|
|
tp.AddHeader("NAME", "PROTECTED", "COMMIT")
|
||
|
|
for _, b := range branches {
|
||
|
|
protected := ""
|
||
|
|
if b.Protected {
|
||
|
|
protected = "yes"
|
||
|
|
}
|
||
|
|
sha := ""
|
||
|
|
if b.Commit != nil {
|
||
|
|
if len(b.Commit.ID) >= 7 {
|
||
|
|
sha = b.Commit.ID[:7]
|
||
|
|
} else {
|
||
|
|
sha = b.Commit.ID
|
||
|
|
}
|
||
|
|
}
|
||
|
|
tp.AddRow(b.Name, protected, sha)
|
||
|
|
}
|
||
|
|
return tp.Render()
|
||
|
|
}
|
||
|
|
|
||
|
|
func runBranchRename(cmd *cobra.Command, args []string) error {
|
||
|
|
client, owner, name, err := newBranchClient(cmd)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
oldName, newName := args[0], args[1]
|
||
|
|
|
||
|
|
_, _, err = client.UpdateRepoBranch(owner, name, oldName, gitea.UpdateRepoBranchOption{Name: newName})
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to rename branch %q to %q: %w", oldName, newName, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
cs := ios.ColorScheme()
|
||
|
|
fmt.Fprintf(ios.Out, "%s Renamed branch %q to %q\n", cs.SuccessIcon(), oldName, newName)
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func runBranchDelete(cmd *cobra.Command, args []string) error {
|
||
|
|
client, owner, name, err := newBranchClient(cmd)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
branchName := args[0]
|
||
|
|
skipConfirm, _ := cmd.Flags().GetBool("yes")
|
||
|
|
|
||
|
|
if !skipConfirm && ios.IsStdinTTY() {
|
||
|
|
answer, err := promptLine(fmt.Sprintf("Delete branch %q in %s/%s? [y/N]: ", branchName, owner, name))
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if answer != "y" && answer != "Y" && answer != "yes" {
|
||
|
|
fmt.Fprintln(ios.ErrOut, "Cancelled.")
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ok, _, err := client.DeleteRepoBranch(owner, name, branchName)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to delete branch %q: %w", branchName, err)
|
||
|
|
}
|
||
|
|
if !ok {
|
||
|
|
return fmt.Errorf("branch %q was not deleted (it may be protected or not exist)", branchName)
|
||
|
|
}
|
||
|
|
|
||
|
|
cs := ios.ColorScheme()
|
||
|
|
fmt.Fprintf(ios.Out, "%s Deleted branch %q\n", cs.SuccessIcon(), branchName)
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func newBranchClient(cmd *cobra.Command) (*api.Client, string, string, error) {
|
||
|
|
repo, _ := cmd.Flags().GetString("repo")
|
||
|
|
owner, name, err := parseRepo(repo)
|
||
|
|
if err != nil {
|
||
|
|
return nil, "", "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
cfg, err := config.Load()
|
||
|
|
if err != nil {
|
||
|
|
return nil, "", "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd())
|
||
|
|
if err != nil {
|
||
|
|
return nil, "", "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
return client, owner, name, nil
|
||
|
|
}
|