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 ", 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 ", 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 }