package cmd import ( "fmt" "os/exec" "strings" "forgejo.zerova.net/public/fgj-sid/internal/api" "forgejo.zerova.net/public/fgj-sid/internal/config" "forgejo.zerova.net/public/fgj-sid/internal/git" "github.com/spf13/cobra" ) var prCleanCmd = &cobra.Command{ Use: "clean ", Short: "Delete the local branch created by 'pr checkout'", Long: `Remove the local branch that was checked out for a pull request. For safety, the PR must be closed (merged or declined). If the branch is currently checked out, switch away first — this command refuses to delete your active branch. Pass --force to delete the local branch even if the PR is still open.`, Example: ` # Clean up after a merged PR fgj pr clean 42 # Force-delete local branch for an open PR fgj pr clean 42 --force`, Args: cobra.ExactArgs(1), RunE: runPRClean, } func init() { prCmd.AddCommand(prCleanCmd) addRepoFlags(prCleanCmd) prCleanCmd.Flags().Bool("force", false, "Delete the local branch even if the PR is still open") } func runPRClean(cmd *cobra.Command, args []string) error { prNumber, err := parseIssueArg(args[0]) if err != nil { return fmt.Errorf("invalid pull request number: %w", err) } repoFlag, _ := cmd.Flags().GetString("repo") owner, name, err := parseRepo(repoFlag) if err != nil { return err } cfg, err := config.Load() if err != nil { return err } client, err := api.NewClientFromConfig(cfg, "", getDetectedHost(), getCwd()) if err != nil { return err } force, _ := cmd.Flags().GetBool("force") pr, _, err := client.GetPullRequest(owner, name, prNumber) if err != nil { return fmt.Errorf("failed to get pull request: %w", err) } if !force && string(pr.State) == "open" { return fmt.Errorf("PR #%d is still open; refuse to delete local branch without --force", prNumber) } headBranch := pr.Head.Ref if headBranch == "" { return fmt.Errorf("PR #%d has no head branch to clean (it may have been deleted already)", prNumber) } // Refuse to delete the current branch. current, err := git.GetCurrentBranch() if err == nil && current == headBranch { return fmt.Errorf("branch %q is currently checked out; switch to another branch first (e.g. 'git switch main')", headBranch) } // Check local branch exists. if out, _ := exec.Command("git", "rev-parse", "--verify", "--quiet", "refs/heads/"+headBranch).Output(); len(strings.TrimSpace(string(out))) == 0 { fmt.Fprintf(ios.ErrOut, "Local branch %q not found; nothing to clean.\n", headBranch) return nil } delCmd := exec.Command("git", "branch", "-D", headBranch) delCmd.Stdout = ios.Out delCmd.Stderr = ios.ErrOut if err := delCmd.Run(); err != nil { return fmt.Errorf("failed to delete local branch %q: %w", headBranch, err) } cs := ios.ColorScheme() fmt.Fprintf(ios.Out, "%s Deleted local branch %q\n", cs.SuccessIcon(), headBranch) return nil }