99 lines
2.8 KiB
Go
99 lines
2.8 KiB
Go
|
|
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
|
||
|
|
}
|