forked from Gitlink/gitlink-cli
167 lines
5.8 KiB
Go
167 lines
5.8 KiB
Go
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
|
||
}
|