fj/cmd/pr_clean.go

99 lines
2.8 KiB
Go
Raw Normal View History

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