forked from Gitlink/gitlink-cli
148 lines
3.8 KiB
Go
148 lines
3.8 KiB
Go
package org
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
|
)
|
|
|
|
// BatchShortcuts 返回组织级批量成员管理 Shortcut
|
|
func BatchShortcuts() []*common.Shortcut {
|
|
return []*common.Shortcut{
|
|
{
|
|
Name: "batch-invite",
|
|
Description: "Batch invite members to a project (from --users list or --from CSV file)",
|
|
Flags: []common.Flag{
|
|
{Name: "users", Usage: "Comma-separated list of user IDs to invite"},
|
|
{Name: "from", Usage: "CSV file with user IDs (column: user_id)"},
|
|
{Name: "owner", Short: "o", Usage: "Project owner (e.g., zzx-coder)", Required: true},
|
|
{Name: "repo", Short: "r", Usage: "Project repo name (e.g., gitlink-cli)", Required: true},
|
|
{Name: "dry-run", Usage: "Preview operations without executing", Bool: true},
|
|
},
|
|
Run: runOrgBatchInvite,
|
|
},
|
|
{
|
|
Name: "batch-remove",
|
|
Description: "Batch remove members from a project (from --users list or --from CSV file)",
|
|
Flags: []common.Flag{
|
|
{Name: "users", Usage: "Comma-separated list of user IDs to remove"},
|
|
{Name: "from", Usage: "CSV file with user IDs (column: user_id)"},
|
|
{Name: "owner", Short: "o", Usage: "Project owner (e.g., zzx-coder)", Required: true},
|
|
{Name: "repo", Short: "r", Usage: "Project repo name (e.g., gitlink-cli)", Required: true},
|
|
{Name: "dry-run", Usage: "Preview operations without executing", Bool: true},
|
|
},
|
|
Run: runOrgBatchRemove,
|
|
},
|
|
}
|
|
}
|
|
|
|
// runOrgBatchInvite 组织级批量邀请
|
|
func runOrgBatchInvite(ctx *common.RuntimeContext) error {
|
|
userIDs, err := parseBatchUserIDs(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dryRun := ctx.Arg("dry-run") == "true"
|
|
|
|
return inviteToOrgProjects(ctx, userIDs, dryRun)
|
|
}
|
|
|
|
// runOrgBatchRemove 组织级批量移除
|
|
func runOrgBatchRemove(ctx *common.RuntimeContext) error {
|
|
userIDs, err := parseBatchUserIDs(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dryRun := ctx.Arg("dry-run") == "true"
|
|
|
|
return removeFromOrgProjects(ctx, userIDs, dryRun)
|
|
}
|
|
|
|
// parseBatchUserIDs 从 --users 或 --from CSV 解析用户 ID 列表
|
|
func parseBatchUserIDs(ctx *common.RuntimeContext) ([]int, error) {
|
|
usersStr := ctx.Arg("users")
|
|
csvFile := ctx.Arg("from")
|
|
|
|
if usersStr == "" && csvFile == "" {
|
|
return nil, fmt.Errorf("must specify --users (comma-separated user IDs) or --from (CSV file path)")
|
|
}
|
|
|
|
var userIDs []int
|
|
|
|
if usersStr != "" {
|
|
ids, err := parseUserIDList(usersStr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
userIDs = append(userIDs, ids...)
|
|
}
|
|
|
|
if csvFile != "" {
|
|
ids, err := parseCSVUserIDs(csvFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
userIDs = append(userIDs, ids...)
|
|
}
|
|
|
|
if len(userIDs) == 0 {
|
|
return nil, fmt.Errorf("no valid user IDs found")
|
|
}
|
|
|
|
return userIDs, nil
|
|
}
|
|
|
|
// parseCSVUserIDs 从 CSV 文件读取 user_id 列
|
|
func parseCSVUserIDs(filePath string) ([]int, error) {
|
|
f, err := os.Open(filePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open CSV file %s: %w", filePath, err)
|
|
}
|
|
defer f.Close()
|
|
|
|
reader := csv.NewReader(f)
|
|
records, err := reader.ReadAll()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read CSV file: %w", err)
|
|
}
|
|
|
|
if len(records) < 2 {
|
|
return nil, fmt.Errorf("CSV file must have a header row and at least one data row")
|
|
}
|
|
|
|
// 查找 user_id 列
|
|
header := records[0]
|
|
colIdx := -1
|
|
for i, h := range header {
|
|
if strings.TrimSpace(h) == "user_id" {
|
|
colIdx = i
|
|
break
|
|
}
|
|
}
|
|
if colIdx == -1 {
|
|
return nil, fmt.Errorf("CSV file must have a 'user_id' column")
|
|
}
|
|
|
|
var ids []int
|
|
for _, row := range records[1:] {
|
|
if len(row) <= colIdx {
|
|
continue
|
|
}
|
|
s := strings.TrimSpace(row[colIdx])
|
|
if s == "" {
|
|
continue
|
|
}
|
|
uid, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid user ID in CSV: %s", s)
|
|
}
|
|
ids = append(ids, uid)
|
|
}
|
|
|
|
return ids, nil
|
|
}
|