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