gitlink-cli/shortcuts/pr/batch.go

167 lines
5.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package pr
import (
"fmt"
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
)
func newBatchCloseShortcut() *common.Shortcut {
return &common.Shortcut{
// +batch-close按编号或 CSV 文件批量关闭多个合并请求(支持 --dry-run 预览)
Name: "batch-close",
Description: "批量关闭多个合并请求",
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,
}
}
// [B 类批量] 逐个关闭 PR——POST /pulls/{n}/refuse_merge每个请求独立
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{
// +batch-merge按编号或 CSV 文件批量合并多个合并请求(不可逆,默认需确认)
Name: "batch-merge",
Description: "批量合并多个合并请求",
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,
}
}
// [B 类批量] 逐个合并 PR——POST /pulls/{n}/pr_merge
// 不可逆操作:执行前调用 ConfirmAction 确认(除非 --yes
func runBatchMerge(ctx *common.RuntimeContext) error {
if err := ctx.ResolveOwnerRepo(); err != nil {
return err
}
method := ctx.Arg("method")
if method == "" {
method = "merge" // 默认使用 merge 方式
}
// P2 补全的 validateMergeMethod只允许 merge/rebase/squash 三种
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 {
// dry-run 直接返回预览,不给 fn 传实际逻辑
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
}
// 逐个调用 POST /pulls/{n}/pr_merge每个请求带合并方式参数
summary := common.ProcessBatch(numbers, false, "merge", func(number string) error {
payload := map[string]interface{}{
"do": method, // merge/rebase/squash
}
_, 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
}