forked from Gitlink/gitlink-cli
159 lines
5.1 KiB
Go
159 lines
5.1 KiB
Go
package pr
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
|
)
|
|
|
|
func newBatchCloseShortcut() *common.Shortcut {
|
|
return &common.Shortcut{
|
|
Name: "batch-close",
|
|
Description: "Close multiple pull requests",
|
|
Long: `Close multiple pull requests in a single operation.
|
|
|
|
Provide PR numbers via --numbers (comma-separated) or --from (CSV file).
|
|
Use --dry-run to preview which pull requests would be closed without
|
|
making changes.
|
|
|
|
The CSV file may have a "number", "issue_number", or "project_issues_index"
|
|
header column; otherwise the first column is used.`,
|
|
Example: ` # Close pull requests 1, 2, and 3
|
|
gitlink pr +batch-close --numbers 1,2,3
|
|
|
|
# Dry-run to preview
|
|
gitlink pr +batch-close --numbers 1,2,3 --dry-run
|
|
|
|
# Close pull requests listed in a CSV file
|
|
gitlink pr +batch-close --from prs.csv`,
|
|
Flags: []common.Flag{
|
|
{Name: "numbers", Short: "n", Usage: "Comma-separated PR numbers, e.g. 1,2,3"},
|
|
{Name: "from", Usage: "Read PR numbers from a CSV file. Supports a number/issue_number/project_issues_index column or first column without header"},
|
|
{Name: "dry-run", Usage: "Preview the pull requests that would be closed without changing them", Bool: true, Default: "false"},
|
|
},
|
|
Run: runBatchClose,
|
|
}
|
|
}
|
|
|
|
func runBatchClose(ctx *common.RuntimeContext) error {
|
|
if err := ctx.ResolveOwnerRepo(); err != nil {
|
|
return err
|
|
}
|
|
|
|
numbers, err := common.CollectNumbers(ctx.Arg("numbers"), ctx.Arg("from"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(numbers) == 0 {
|
|
return fmt.Errorf("no PR numbers provided; use --numbers 1,2,3 or --from prs.csv")
|
|
}
|
|
|
|
dryRun := common.ParseBool(ctx.Arg("dry-run"))
|
|
|
|
summary := common.ProcessBatch(numbers, dryRun, "close", func(number string) error {
|
|
_, err := ctx.CallAPI("POST", fmt.Sprintf("%s/pulls/%s/refuse_merge", ctx.RepoPath(), number), nil)
|
|
return err
|
|
})
|
|
summary.Repository = fmt.Sprintf("%s/%s", ctx.Owner, ctx.Repo)
|
|
|
|
if err := ctx.OutputData(summary); err != nil {
|
|
return err
|
|
}
|
|
if summary.Failed > 0 {
|
|
return fmt.Errorf("%d of %d pull request(s) failed to close", summary.Failed, summary.Total)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func newBatchMergeShortcut() *common.Shortcut {
|
|
return &common.Shortcut{
|
|
Name: "batch-merge",
|
|
Description: "Merge multiple pull requests",
|
|
Long: `Merge multiple pull requests in a single operation.
|
|
|
|
Provide PR numbers via --numbers (comma-separated) or --from (CSV file).
|
|
Use --method to choose the merge strategy: merge (default), rebase, or squash.
|
|
Use --dry-run to preview which pull requests would be merged without
|
|
making changes.
|
|
|
|
WARNING: Merging is irreversible. A confirmation prompt is shown before
|
|
execution (use --yes to auto-confirm).
|
|
|
|
The CSV file may have a "number", "issue_number", or "project_issues_index"
|
|
header column; otherwise the first column is used.`,
|
|
Example: ` # Merge pull requests 1, 2, and 3 using the default method
|
|
gitlink pr +batch-merge --numbers 1,2,3
|
|
|
|
# Squash-merge multiple pull requests
|
|
gitlink pr +batch-merge --numbers 1,2,3 --method squash
|
|
|
|
# Rebase-merge pull requests listed in a CSV file
|
|
gitlink pr +batch-merge --from prs.csv --method rebase
|
|
|
|
# Dry-run to preview
|
|
gitlink pr +batch-merge --numbers 1,2,3 --dry-run
|
|
|
|
# Auto-confirm without prompt
|
|
gitlink pr +batch-merge --numbers 1,2,3 --yes`,
|
|
Flags: []common.Flag{
|
|
{Name: "numbers", Short: "n", Usage: "Comma-separated PR numbers, e.g. 1,2,3"},
|
|
{Name: "from", Usage: "Read PR numbers from a CSV file. Supports a number/issue_number/project_issues_index column or first column without header"},
|
|
{Name: "method", Short: "m", Usage: "Merge method: merge, rebase, squash", Default: "merge"},
|
|
{Name: "dry-run", Usage: "Preview the pull requests that would be merged without changing them", Bool: true, Default: "false"},
|
|
},
|
|
Run: runBatchMerge,
|
|
}
|
|
}
|
|
|
|
func runBatchMerge(ctx *common.RuntimeContext) error {
|
|
if err := ctx.ResolveOwnerRepo(); err != nil {
|
|
return err
|
|
}
|
|
|
|
method := ctx.Arg("method")
|
|
if method == "" {
|
|
method = "merge"
|
|
}
|
|
if err := validateMergeMethod(method); err != nil {
|
|
return err
|
|
}
|
|
|
|
numbers, err := common.CollectNumbers(ctx.Arg("numbers"), ctx.Arg("from"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(numbers) == 0 {
|
|
return fmt.Errorf("no PR numbers provided; use --numbers 1,2,3 or --from prs.csv")
|
|
}
|
|
|
|
dryRun := common.ParseBool(ctx.Arg("dry-run"))
|
|
|
|
if dryRun {
|
|
summary := common.ProcessBatch(numbers, true, "merge", nil)
|
|
summary.Repository = fmt.Sprintf("%s/%s", ctx.Owner, ctx.Repo)
|
|
return ctx.OutputData(summary)
|
|
}
|
|
|
|
// Merging is irreversible — require explicit confirmation
|
|
if err := common.ConfirmAction(fmt.Sprintf("batch merge %d pull requests", len(numbers))); err != nil {
|
|
return err
|
|
}
|
|
|
|
summary := common.ProcessBatch(numbers, false, "merge", func(number string) error {
|
|
payload := map[string]interface{}{
|
|
"do": method,
|
|
}
|
|
_, err := ctx.CallAPI("POST", fmt.Sprintf("%s/pulls/%s/pr_merge", ctx.RepoPath(), number), payload)
|
|
return err
|
|
})
|
|
summary.Repository = fmt.Sprintf("%s/%s", ctx.Owner, ctx.Repo)
|
|
|
|
if err := ctx.OutputData(summary); err != nil {
|
|
return err
|
|
}
|
|
if summary.Failed > 0 {
|
|
return fmt.Errorf("%d of %d pull request(s) failed to merge", summary.Failed, summary.Total)
|
|
}
|
|
return nil
|
|
}
|