gitlink-cli/shortcuts/repo/batch_delete.go

95 lines
2.6 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 repo
import (
"fmt"
"strings"
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
)
// newBatchDeleteShortcut 实现 repo +batch-delete 命令。
//
// 设计参考 issue +batch-close 与 repo +batch-update
// - --names : 内联逗号分隔的仓库名列表
// - --from : CSV 文件路径(只读 name 列,复用 readNamesFromCSV
// - --dry-run : 仅预览不实际删除
//
// 与单条 repo +delete 的区别:批量操作下没有"当前仓库"语义,
// 因此只要求 --owner不需要 --repo所有要删除的仓库都位于该 owner 名下。
func newBatchDeleteShortcut() *common.Shortcut {
return &common.Shortcut{
Name: "batch-delete",
Description: "Delete multiple repositories by names or a CSV file",
Flags: []common.Flag{
{Name: "names", Short: "n", Usage: "Comma-separated repository names, e.g. repo-a,repo-b"},
{Name: "from", Usage: "CSV file path"},
{Name: "dry-run", Usage: "Preview without deleting", Bool: true, Default: "false"},
},
Run: runBatchDelete,
}
}
func runBatchDelete(ctx *common.RuntimeContext) error {
owner := ctx.Owner
if owner == "" {
return fmt.Errorf("--owner is required; pass --owner <login> to specify the account that owns the repos")
}
var repoNames []string
if namesStr := ctx.Arg("names"); namesStr != "" {
for _, name := range strings.Split(namesStr, ",") {
name = strings.TrimSpace(name)
if name != "" {
repoNames = append(repoNames, name)
}
}
}
if csvPath := ctx.Arg("from"); csvPath != "" {
csvNames, err := readNamesFromCSV(csvPath)
if err != nil {
return err
}
repoNames = append(repoNames, csvNames...)
}
if len(repoNames) == 0 {
return fmt.Errorf("no repository names provided; use -n repo-a,repo-b or --from repos.csv")
}
dryRun := ctx.Arg("dry-run") == "true"
summary := repoBatchSummary{
Owner: owner,
Action: "delete",
DryRun: dryRun,
Total: len(repoNames),
Results: make([]repoBatchResult, 0, len(repoNames)),
}
for _, name := range repoNames {
result := repoBatchResult{Name: name}
if dryRun {
result.Status = "planned"
summary.Succeeded++
summary.Results = append(summary.Results, result)
continue
}
if _, err := ctx.CallAPI("DELETE", fmt.Sprintf("/%s/%s", owner, name), nil); err != nil {
result.Status = "failed"
result.Error = err.Error()
summary.Failed++
} else {
result.Status = "deleted"
summary.Succeeded++
}
summary.Results = append(summary.Results, result)
}
if err := ctx.OutputData(summary); err != nil {
return err
}
if summary.Failed > 0 {
return fmt.Errorf("%d of %d repo(s) failed to delete", summary.Failed, summary.Total)
}
return nil
}