forked from Gitlink/gitlink-cli
refactor(i18n): fork 引入的命令全面 i18n 化,对齐 upstream 风格
仅改造 fork 自己实现/新增的命令,不动 upstream 本身未 i18n 的包: - issue/batch_*.go(7文件): newBatchXxxShortcut 接受 tr,所有 Description/Usage 改 tr.T();新增 batchRuntimeFlags(tr) 共享 helper 消除 dry-run/confirm/max/delay 重复 - search +issues: 11 个硬编码改 tr.T(),复用 flag.search.keyword/ flag.page/flag.limit/flag.sort_by/flag.sort_direction - user headmaps/stats-*/trends: newStatsShortcut 接受 tr, Description/Usage 改 tr.T() - locale: 新增 51 个 key(zh-CN + en-US 双语),清理 10 个孤立死 key (batch_list.*/batch.reason/yes 等无对应命令的遗留 key) 全模块测试通过(40 包,0 失败)。
This commit is contained in:
parent
31065df31d
commit
fbdab04a57
|
|
@ -34,12 +34,15 @@
|
|||
"cmd.dataset.view.short": "View a repository's dataset",
|
||||
"cmd.doctor.long": "Run local diagnostics for gitlink-cli configuration, authentication, repository context and API connectivity.",
|
||||
"cmd.doctor.short": "Diagnose gitlink-cli environment problems",
|
||||
"cmd.issue.batch_close.long": "Close filtered issues in bulk.\n\nThis command defaults to dry-run mode and only prints matching issues.\nPass --yes to execute remote close operations. Use restrictive filters and a small limit.\n\nExamples:\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20 --yes",
|
||||
"cmd.issue.batch_close.short": "Close filtered issues in bulk. Defaults to dry-run; pass --yes to execute.",
|
||||
"cmd.issue.batch_label.long": "Add a label to filtered issues in bulk.\n\nThis command defaults to dry-run mode and only prints matching issues.\nPass --yes to execute remote label operations. The current implementation does not fake label writes when the API endpoint is unavailable.\n\nExamples:\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50 --yes",
|
||||
"cmd.issue.batch_label.short": "Add a label to filtered issues in bulk. Defaults to dry-run; pass --yes to execute.",
|
||||
"cmd.issue.batch_list.long": "List issue batch maintenance candidates without changing remote data.\n\nExamples:\n gitlink-cli issue +batch-list --owner Gitlink --repo gitlink-cli --state open --older-than-days 30 --limit 50 --format table\n gitlink-cli issue +batch-list --owner Gitlink --repo gitlink-cli --label bug --format json",
|
||||
"cmd.issue.batch_list.short": "List issue batch maintenance candidates without changing remote data",
|
||||
"cmd.issue.batch_assign.short": "Assign issues to a user or via CSV",
|
||||
"cmd.issue.batch_close.long": "Close multiple issues. Pass issue numbers via --numbers or read from a CSV via --from.\n\nDefaults to dry-run; pass --confirm to execute.",
|
||||
"cmd.issue.batch_close.short": "Close multiple issues by issue numbers or a CSV file",
|
||||
"cmd.issue.batch_create.short": "Create multiple issues from CSV",
|
||||
"cmd.issue.batch_delete.short": "Batch delete multiple issues (use with caution)",
|
||||
"cmd.issue.batch_label.long": "Batch add, remove, or set labels on multiple issues.\n\nDefaults to dry-run; pass --confirm to execute.",
|
||||
"cmd.issue.batch_label.short": "Add, remove, or set labels on multiple issues",
|
||||
"cmd.issue.batch_open.short": "Reopen multiple issues",
|
||||
"cmd.issue.batch_update.short": "Update multiple issues via CSV or --ids",
|
||||
"cmd.issue.close.short": "Close an issue",
|
||||
"cmd.issue.comment.short": "Add a comment to an issue",
|
||||
"cmd.issue.create.short": "Create a new issue",
|
||||
|
|
@ -90,12 +93,19 @@
|
|||
"cmd.repo.tree.short": "List repository files and directories",
|
||||
"cmd.root.long": "Manage repositories, issues, pull requests, releases, CI and workflows on GitLink.",
|
||||
"cmd.root.short": "GitLink CLI - command-line tool for GitLink",
|
||||
"cmd.search.issues.short": "Search issues in a repository",
|
||||
"cmd.search.repos.short": "Search repositories",
|
||||
"cmd.search.short": "Search operations",
|
||||
"cmd.search.users.short": "Search users",
|
||||
"cmd.user.headmaps.short": "Show user contribution heatmap",
|
||||
"cmd.user.info.short": "Show user profile",
|
||||
"cmd.user.me.short": "Show current authenticated user",
|
||||
"cmd.user.short": "User operations",
|
||||
"cmd.user.stats_activity.short": "Show user activity statistics",
|
||||
"cmd.user.stats_develop.short": "Show user development capability",
|
||||
"cmd.user.stats_major.short": "Show user major positioning",
|
||||
"cmd.user.stats_role.short": "Show user role positioning",
|
||||
"cmd.user.trends.short": "Show user project activity trends",
|
||||
"cmd.version.short": "Print version information",
|
||||
"cmd.webhook.create.short": "Create a repository webhook",
|
||||
"cmd.webhook.delete.short": "Delete a repository webhook",
|
||||
|
|
@ -150,13 +160,36 @@
|
|||
"flag.issue.assignee": "Assignee login",
|
||||
"flag.issue.assignee_id": "Assignee user ID",
|
||||
"flag.issue.author_id": "Author user ID",
|
||||
"flag.issue.batch.reason": "Optional reason shown in the batch result",
|
||||
"flag.issue.batch.yes": "Execute remote operations. Without this flag the command is dry-run only.",
|
||||
"flag.issue.batch_close.older_than_days": "Required safety filter; must be at least 7",
|
||||
"flag.issue.batch_close.state": "Filter by issue state before closing",
|
||||
"flag.issue.batch_label.state": "Filter by issue state",
|
||||
"flag.issue.batch_list.limit": "Maximum issues to return, capped at 100",
|
||||
"flag.issue.batch_process.limit": "Maximum issues to process, capped at 100",
|
||||
"flag.issue.batch.confirm": "Confirm batch operation",
|
||||
"flag.issue.batch.delay": "Delay in milliseconds between requests",
|
||||
"flag.issue.batch.dry_run": "Preview the issues that would be changed without making any changes",
|
||||
"flag.issue.batch.from": "Read issue numbers from a CSV file. Supports a number/issue_number/project_issues_index column or first column without header",
|
||||
"flag.issue.batch.label": "Filter by label name",
|
||||
"flag.issue.batch.max": "Maximum number of issues to process",
|
||||
"flag.issue.batch.numbers": "Comma-separated issue numbers from the web URL, for example: 1,2,3",
|
||||
"flag.issue.batch.search": "Search issues by keyword",
|
||||
"flag.issue.batch.state": "Filter by state: open, closed, all",
|
||||
"flag.issue.batch_assign.assignee": "Assignee username or ID (uniform mode)",
|
||||
"flag.issue.batch_assign.csv": "CSV file with number,assignee columns",
|
||||
"flag.issue.batch_assign.numbers": "Comma-separated issue numbers",
|
||||
"flag.issue.batch_close.state": "Filter by state before closing",
|
||||
"flag.issue.batch_create.csv": "CSV file with issue data",
|
||||
"flag.issue.batch_create.print_schema": "Print CSV header and exit",
|
||||
"flag.issue.batch_delete.confirm": "Confirm deletion (required for safety)",
|
||||
"flag.issue.batch_delete.dry_run": "Preview deletion without executing",
|
||||
"flag.issue.batch_delete.ids": "Comma-separated issue IDs",
|
||||
"flag.issue.batch_label.action": "Action: add, remove, or set",
|
||||
"flag.issue.batch_label.csv": "CSV file path with issue numbers",
|
||||
"flag.issue.batch_label.label_ids": "Comma-separated label IDs (mutually exclusive with --labels)",
|
||||
"flag.issue.batch_label.labels": "Comma-separated label names",
|
||||
"flag.issue.batch_label.numbers": "Comma-separated issue numbers",
|
||||
"flag.issue.batch_update.assignees": "Comma-separated assignee user IDs",
|
||||
"flag.issue.batch_update.csv": "CSV file path with updates",
|
||||
"flag.issue.batch_update.ids": "Comma-separated issue IDs",
|
||||
"flag.issue.batch_update.milestone": "Milestone ID",
|
||||
"flag.issue.batch_update.priority": "Priority ID",
|
||||
"flag.issue.batch_update.status": "New status: open or closed",
|
||||
"flag.issue.batch_update.tags": "Comma-separated label/tag IDs",
|
||||
"flag.issue.body": "Issue description",
|
||||
"flag.issue.label": "Label ID",
|
||||
"flag.issue.label_filter": "Filter by existing label",
|
||||
|
|
@ -214,6 +247,11 @@
|
|||
"flag.repo.private": "Make repository private (true/false)",
|
||||
"flag.repo.tree.path": "Directory path to list (default: repository root)",
|
||||
"flag.repo.tree.ref": "Branch, tag, or commit ref",
|
||||
"flag.search.issues.assignee": "Filter by assignee user ID",
|
||||
"flag.search.issues.author": "Filter by author user ID",
|
||||
"flag.search.issues.category": "Issue category: all, opened, closed",
|
||||
"flag.search.issues.milestone": "Filter by milestone ID",
|
||||
"flag.search.issues.tag": "Filter by tag IDs (comma-separated)",
|
||||
"flag.search.keyword": "Search keyword",
|
||||
"flag.sort_by": "Sort field",
|
||||
"flag.sort_direction": "Sort direction: asc, desc",
|
||||
|
|
|
|||
|
|
@ -34,12 +34,15 @@
|
|||
"cmd.dataset.view.short": "查看仓库数据集",
|
||||
"cmd.doctor.long": "诊断 gitlink-cli 的配置、认证、仓库上下文和 API 连通性问题。",
|
||||
"cmd.doctor.short": "诊断 gitlink-cli 环境问题",
|
||||
"cmd.issue.batch_close.long": "批量关闭筛选后的议题。\n\n该命令默认处于 dry-run 模式,只打印匹配的议题。\n传入 --yes 后执行远端关闭操作。请使用严格筛选条件和较小 limit。\n\n示例:\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20\n gitlink-cli issue +batch-close --owner Gitlink --repo gitlink-cli --older-than-days 60 --limit 20 --yes",
|
||||
"cmd.issue.batch_close.short": "批量关闭筛选后的议题。默认 dry-run;传入 --yes 后执行。",
|
||||
"cmd.issue.batch_label.long": "给筛选后的议题批量添加标签。\n\n该命令默认处于 dry-run 模式,只打印匹配的议题。\n传入 --yes 后执行远端标签操作。当前实现不会在 API 端点不可用时伪造写入结果。\n\n示例:\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50\n gitlink-cli issue +batch-label --owner Gitlink --repo gitlink-cli --add-label stale --older-than-days 30 --limit 50 --yes",
|
||||
"cmd.issue.batch_label.short": "给筛选后的议题批量添加标签。默认 dry-run;传入 --yes 后执行。",
|
||||
"cmd.issue.batch_list.long": "列出议题批量维护候选项,不修改远端数据。\n\n示例:\n gitlink-cli issue +batch-list --owner Gitlink --repo gitlink-cli --state open --older-than-days 30 --limit 50 --format table\n gitlink-cli issue +batch-list --owner Gitlink --repo gitlink-cli --label bug --format json",
|
||||
"cmd.issue.batch_list.short": "列出议题批量维护候选项,不修改远端数据",
|
||||
"cmd.issue.batch_assign.short": "批量指派议题负责人",
|
||||
"cmd.issue.batch_close.long": "批量关闭多个议题。支持 --numbers 直接传入编号,或 --from 从 CSV 读取。\n\n默认 dry-run,传入 --confirm 后执行。",
|
||||
"cmd.issue.batch_close.short": "批量关闭多个议题(按编号或 CSV)",
|
||||
"cmd.issue.batch_create.short": "从 CSV 批量创建议题",
|
||||
"cmd.issue.batch_delete.short": "批量删除多个议题(谨慎使用)",
|
||||
"cmd.issue.batch_label.long": "批量给多个议题添加、移除或设置标签。\n\n默认 dry-run,传入 --confirm 后执行。",
|
||||
"cmd.issue.batch_label.short": "批量管理议题标签(添加/移除/设置)",
|
||||
"cmd.issue.batch_open.short": "批量重新打开多个议题",
|
||||
"cmd.issue.batch_update.short": "批量更新议题(按 CSV 或 ID)",
|
||||
"cmd.issue.close.short": "关闭议题",
|
||||
"cmd.issue.comment.short": "给议题添加评论",
|
||||
"cmd.issue.create.short": "创建新议题",
|
||||
|
|
@ -90,12 +93,19 @@
|
|||
"cmd.repo.tree.short": "列出仓库文件和目录",
|
||||
"cmd.root.long": "用于管理 GitLink 上的仓库、议题、拉取请求、发布、CI 和工作流。",
|
||||
"cmd.root.short": "GitLink CLI - GitLink 命令行工具",
|
||||
"cmd.search.issues.short": "搜索仓库议题",
|
||||
"cmd.search.repos.short": "搜索仓库",
|
||||
"cmd.search.short": "搜索操作",
|
||||
"cmd.search.users.short": "搜索用户",
|
||||
"cmd.user.headmaps.short": "显示用户贡献热力图",
|
||||
"cmd.user.info.short": "显示用户资料",
|
||||
"cmd.user.me.short": "显示当前认证用户",
|
||||
"cmd.user.short": "用户操作",
|
||||
"cmd.user.stats_activity.short": "显示用户活动统计",
|
||||
"cmd.user.stats_develop.short": "显示用户开发能力",
|
||||
"cmd.user.stats_major.short": "显示用户专业/学科定位",
|
||||
"cmd.user.stats_role.short": "显示用户角色定位",
|
||||
"cmd.user.trends.short": "显示用户项目活动趋势",
|
||||
"cmd.version.short": "打印版本信息",
|
||||
"cmd.webhook.create.short": "创建仓库 Webhook",
|
||||
"cmd.webhook.delete.short": "删除仓库 Webhook",
|
||||
|
|
@ -150,13 +160,36 @@
|
|||
"flag.issue.assignee": "负责人登录名",
|
||||
"flag.issue.assignee_id": "负责人用户 ID",
|
||||
"flag.issue.author_id": "作者用户 ID",
|
||||
"flag.issue.batch.reason": "批量结果中显示的可选原因",
|
||||
"flag.issue.batch.yes": "执行远端操作。未传入该参数时仅 dry-run。",
|
||||
"flag.issue.batch_close.older_than_days": "必需的安全筛选条件;至少为 7",
|
||||
"flag.issue.batch.confirm": "确认执行批量操作",
|
||||
"flag.issue.batch.delay": "请求间隔(毫秒)",
|
||||
"flag.issue.batch.dry_run": "预览将被修改的议题,不实际执行",
|
||||
"flag.issue.batch.from": "从 CSV 文件读取议题编号(支持 number/issue_number/project_issues_index 列)",
|
||||
"flag.issue.batch.label": "按标签名筛选",
|
||||
"flag.issue.batch.max": "最多处理的议题数",
|
||||
"flag.issue.batch.numbers": "议题编号列表(逗号分隔),例如 1,2,3",
|
||||
"flag.issue.batch.search": "按关键词搜索议题",
|
||||
"flag.issue.batch.state": "按状态筛选:open、closed、all",
|
||||
"flag.issue.batch_assign.assignee": "负责人用户名或 ID(统一模式)",
|
||||
"flag.issue.batch_assign.csv": "CSV 文件(含 number,assignee 列)",
|
||||
"flag.issue.batch_assign.numbers": "议题编号列表(逗号分隔)",
|
||||
"flag.issue.batch_close.state": "关闭前按议题状态筛选",
|
||||
"flag.issue.batch_label.state": "按议题状态筛选",
|
||||
"flag.issue.batch_list.limit": "最多返回的议题数,上限 100",
|
||||
"flag.issue.batch_process.limit": "最多处理的议题数,上限 100",
|
||||
"flag.issue.batch_create.csv": "含议题数据的 CSV 文件",
|
||||
"flag.issue.batch_create.print_schema": "打印 CSV 表头并退出",
|
||||
"flag.issue.batch_delete.confirm": "确认删除(安全必需)",
|
||||
"flag.issue.batch_delete.dry_run": "预览删除,不实际执行",
|
||||
"flag.issue.batch_delete.ids": "议题 ID 列表(逗号分隔)",
|
||||
"flag.issue.batch_label.action": "操作类型:add、remove 或 set",
|
||||
"flag.issue.batch_label.csv": "含议题编号的 CSV 文件路径",
|
||||
"flag.issue.batch_label.label_ids": "标签 ID 列表(逗号分隔,与 --labels 互斥)",
|
||||
"flag.issue.batch_label.labels": "标签名列表(逗号分隔)",
|
||||
"flag.issue.batch_label.numbers": "议题编号列表(逗号分隔)",
|
||||
"flag.issue.batch_update.assignees": "负责人用户 ID 列表(逗号分隔)",
|
||||
"flag.issue.batch_update.csv": "含更新数据的 CSV 文件路径",
|
||||
"flag.issue.batch_update.ids": "议题 ID 列表(逗号分隔)",
|
||||
"flag.issue.batch_update.milestone": "里程碑 ID",
|
||||
"flag.issue.batch_update.priority": "优先级 ID",
|
||||
"flag.issue.batch_update.status": "新状态:open 或 closed",
|
||||
"flag.issue.batch_update.tags": "标签/标记 ID 列表(逗号分隔)",
|
||||
"flag.issue.body": "议题描述",
|
||||
"flag.issue.label": "标签 ID",
|
||||
"flag.issue.label_filter": "按已有标签筛选",
|
||||
|
|
@ -214,6 +247,11 @@
|
|||
"flag.repo.private": "设为私有仓库(true/false)",
|
||||
"flag.repo.tree.path": "要列出的目录路径(默认:仓库根目录)",
|
||||
"flag.repo.tree.ref": "分支、标签或提交引用",
|
||||
"flag.search.issues.assignee": "按负责人用户 ID 筛选",
|
||||
"flag.search.issues.author": "按作者用户 ID 筛选",
|
||||
"flag.search.issues.category": "议题分类:all、opened、closed",
|
||||
"flag.search.issues.milestone": "按里程碑 ID 筛选",
|
||||
"flag.search.issues.tag": "按标签 ID 筛选(逗号分隔)",
|
||||
"flag.search.keyword": "搜索关键词",
|
||||
"flag.sort_by": "排序字段",
|
||||
"flag.sort_direction": "排序方向:asc、desc",
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
package issue
|
||||
|
||||
import (
|
||||
"github.com/gitlink-org/gitlink-cli/internal/i18n"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
const closeIssueStatusID = 5
|
||||
|
||||
func newBatchCloseShortcut() *common.Shortcut {
|
||||
func newBatchCloseShortcut(tr *i18n.Translator) *common.Shortcut {
|
||||
return &common.Shortcut{
|
||||
Name: "batch-close",
|
||||
Description: "Close multiple issues by issue numbers or a CSV file",
|
||||
Flags: batchStateFlags(),
|
||||
Description: tr.T("cmd.issue.batch_close.short"),
|
||||
Flags: batchStateFlags(tr),
|
||||
Run: func(ctx *common.RuntimeContext) error { return runBatchStateChange(ctx, "close", closeIssueStatusID) },
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,28 +3,26 @@ package issue
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/internal/i18n"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
func newBatchAssignShortcut() *common.Shortcut {
|
||||
func newBatchAssignShortcut(tr *i18n.Translator) *common.Shortcut {
|
||||
flags := []common.Flag{
|
||||
{Name: "numbers", Short: "n", Usage: tr.T("flag.issue.batch_assign.numbers")},
|
||||
{Name: "from", Usage: tr.T("flag.issue.batch_assign.csv")},
|
||||
{Name: "search", Usage: tr.T("flag.issue.batch.search")},
|
||||
{Name: "state", Usage: tr.T("flag.issue.batch.state")},
|
||||
{Name: "assignee", Short: "a", Usage: tr.T("flag.issue.batch_assign.assignee")},
|
||||
}
|
||||
flags = append(flags, batchRuntimeFlags(tr)...)
|
||||
return &common.Shortcut{
|
||||
Name: "batch-assign",
|
||||
Description: "Assign issues to a user or via CSV",
|
||||
Flags: []common.Flag{
|
||||
{Name: "numbers", Short: "n", Usage: "Comma-separated issue numbers"},
|
||||
{Name: "from", Usage: "CSV file with number,assignee columns"},
|
||||
{Name: "search", Usage: "Search keyword"},
|
||||
{Name: "state", Usage: "State filter for --search"},
|
||||
{Name: "assignee", Short: "a", Usage: "Assignee username or ID (uniform mode)"},
|
||||
{Name: "dry-run", Usage: "Preview", Bool: true, Default: "false"},
|
||||
{Name: "confirm", Usage: "Confirm", Bool: true, Default: "false"},
|
||||
{Name: "max", Usage: "Max items", Default: strconv.Itoa(defaultBatchMaxItems)},
|
||||
{Name: "delay", Usage: "Delay ms", Default: strconv.Itoa(defaultBatchDelayMs)},
|
||||
},
|
||||
Run: runBatchAssign,
|
||||
Description: tr.T("cmd.issue.batch_assign.short"),
|
||||
Flags: flags,
|
||||
Run: runBatchAssign,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/internal/i18n"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
|
|
@ -39,17 +40,27 @@ func parseBatchOptions(ctx *common.RuntimeContext) BatchOptions {
|
|||
}
|
||||
|
||||
// batchStateFlags 返回 batch 状态变更命令(close、open)共用的 flag 列表。
|
||||
func batchStateFlags() []common.Flag {
|
||||
func batchStateFlags(tr *i18n.Translator) []common.Flag {
|
||||
return []common.Flag{
|
||||
{Name: "numbers", Short: "n", Usage: "Comma-separated issue numbers from the web URL, for example: 1,2,3"},
|
||||
{Name: "from", Usage: "Read issue numbers from a CSV file. Supports a number/issue_number/project_issues_index column or first column without header"},
|
||||
{Name: "search", Usage: "Search issues by keyword"},
|
||||
{Name: "state", Usage: "Filter by state: open, closed, all"},
|
||||
{Name: "label", Usage: "Filter by label name"},
|
||||
{Name: "confirm", Usage: "Confirm batch operation", Bool: true, Default: "false"},
|
||||
{Name: "max", Usage: "Maximum number of issues to process", Default: strconv.Itoa(defaultBatchMaxItems)},
|
||||
{Name: "delay", Usage: "Delay in milliseconds between requests", Default: strconv.Itoa(defaultBatchDelayMs)},
|
||||
{Name: "dry-run", Usage: "Preview the issues that would be changed without making any changes", Bool: true, Default: "false"},
|
||||
{Name: "numbers", Short: "n", Usage: tr.T("flag.issue.batch.numbers")},
|
||||
{Name: "from", Usage: tr.T("flag.issue.batch.from")},
|
||||
{Name: "search", Usage: tr.T("flag.issue.batch.search")},
|
||||
{Name: "state", Usage: tr.T("flag.issue.batch.state")},
|
||||
{Name: "label", Usage: tr.T("flag.issue.batch.label")},
|
||||
{Name: "confirm", Usage: tr.T("flag.issue.batch.confirm"), Bool: true, Default: "false"},
|
||||
{Name: "max", Usage: tr.T("flag.issue.batch.max"), Default: strconv.Itoa(defaultBatchMaxItems)},
|
||||
{Name: "delay", Usage: tr.T("flag.issue.batch.delay"), Default: strconv.Itoa(defaultBatchDelayMs)},
|
||||
{Name: "dry-run", Usage: tr.T("flag.issue.batch.dry_run"), Bool: true, Default: "false"},
|
||||
}
|
||||
}
|
||||
|
||||
// batchRuntimeFlags 返回各 batch 命令共用的运行时 flag(dry-run/confirm/max/delay)。
|
||||
func batchRuntimeFlags(tr *i18n.Translator) []common.Flag {
|
||||
return []common.Flag{
|
||||
{Name: "dry-run", Usage: tr.T("flag.issue.batch.dry_run"), Bool: true, Default: "false"},
|
||||
{Name: "confirm", Usage: tr.T("flag.issue.batch.confirm"), Bool: true, Default: "false"},
|
||||
{Name: "max", Usage: tr.T("flag.issue.batch.max"), Default: strconv.Itoa(defaultBatchMaxItems)},
|
||||
{Name: "delay", Usage: tr.T("flag.issue.batch.delay"), Default: strconv.Itoa(defaultBatchDelayMs)},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,22 +7,21 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/internal/i18n"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
func newBatchCreateShortcut() *common.Shortcut {
|
||||
func newBatchCreateShortcut(tr *i18n.Translator) *common.Shortcut {
|
||||
flags := []common.Flag{
|
||||
{Name: "from", Short: "f", Usage: tr.T("flag.issue.batch_create.csv"), Required: true},
|
||||
{Name: "print-schema", Usage: tr.T("flag.issue.batch_create.print_schema"), Bool: true, Default: "false"},
|
||||
}
|
||||
flags = append(flags, batchRuntimeFlags(tr)...)
|
||||
return &common.Shortcut{
|
||||
Name: "batch-create",
|
||||
Description: "Create multiple issues from CSV",
|
||||
Flags: []common.Flag{
|
||||
{Name: "from", Short: "f", Usage: "CSV file with issue data", Required: true},
|
||||
{Name: "print-schema", Usage: "Print CSV header and exit", Bool: true, Default: "false"},
|
||||
{Name: "dry-run", Usage: "Preview", Bool: true, Default: "false"},
|
||||
{Name: "confirm", Usage: "Confirm", Bool: true, Default: "false"},
|
||||
{Name: "max", Usage: "Max items", Default: strconv.Itoa(defaultBatchMaxItems)},
|
||||
{Name: "delay", Usage: "Delay ms", Default: strconv.Itoa(defaultBatchDelayMs)},
|
||||
},
|
||||
Run: runBatchCreate,
|
||||
Description: tr.T("cmd.issue.batch_create.short"),
|
||||
Flags: flags,
|
||||
Run: runBatchCreate,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,17 +5,18 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/internal/i18n"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
func newBatchDeleteShortcut() *common.Shortcut {
|
||||
func newBatchDeleteShortcut(tr *i18n.Translator) *common.Shortcut {
|
||||
return &common.Shortcut{
|
||||
Name: "batch-delete",
|
||||
Description: "Batch delete multiple issues (use with caution)",
|
||||
Description: tr.T("cmd.issue.batch_delete.short"),
|
||||
Flags: []common.Flag{
|
||||
{Name: "ids", Short: "i", Usage: "Comma-separated issue IDs", Required: true},
|
||||
{Name: "dry-run", Usage: "Preview deletion without executing", Bool: true, Default: "false"},
|
||||
{Name: "confirm", Usage: "Confirm deletion (required for safety)", Bool: true, Default: "false"},
|
||||
{Name: "ids", Short: "i", Usage: tr.T("flag.issue.batch_delete.ids"), Required: true},
|
||||
{Name: "dry-run", Usage: tr.T("flag.issue.batch_delete.dry_run"), Bool: true, Default: "false"},
|
||||
{Name: "confirm", Usage: tr.T("flag.issue.batch_delete.confirm"), Bool: true, Default: "false"},
|
||||
},
|
||||
Run: runBatchDelete,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,27 +5,26 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/internal/i18n"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
func newBatchLabelShortcut() *common.Shortcut {
|
||||
func newBatchLabelShortcut(tr *i18n.Translator) *common.Shortcut {
|
||||
flags := []common.Flag{
|
||||
{Name: "numbers", Short: "n", Usage: tr.T("flag.issue.batch_label.numbers")},
|
||||
{Name: "from", Usage: tr.T("flag.issue.batch_label.csv")},
|
||||
{Name: "search", Usage: tr.T("flag.issue.batch.search")},
|
||||
{Name: "state", Usage: tr.T("flag.issue.batch.state")},
|
||||
{Name: "action", Short: "a", Usage: tr.T("flag.issue.batch_label.action"), Required: true},
|
||||
{Name: "labels", Short: "l", Usage: tr.T("flag.issue.batch_label.labels")},
|
||||
{Name: "label-ids", Usage: tr.T("flag.issue.batch_label.label_ids")},
|
||||
}
|
||||
flags = append(flags, batchRuntimeFlags(tr)...)
|
||||
return &common.Shortcut{
|
||||
Name: "batch-label",
|
||||
Description: "Add, remove, or set labels on multiple issues",
|
||||
Flags: []common.Flag{
|
||||
{Name: "numbers", Short: "n", Usage: "Comma-separated issue numbers"},
|
||||
{Name: "from", Usage: "CSV file path with issue numbers"},
|
||||
{Name: "search", Usage: "Search keyword"},
|
||||
{Name: "state", Usage: "State filter for --search"},
|
||||
{Name: "action", Short: "a", Usage: "Action: add, remove, or set", Required: true},
|
||||
{Name: "labels", Short: "l", Usage: "Comma-separated label names"},
|
||||
{Name: "label-ids", Usage: "Comma-separated label IDs (mutually exclusive with --labels)"},
|
||||
{Name: "dry-run", Usage: "Preview", Bool: true, Default: "false"},
|
||||
{Name: "confirm", Usage: "Confirm", Bool: true, Default: "false"},
|
||||
{Name: "max", Usage: "Max items", Default: strconv.Itoa(defaultBatchMaxItems)},
|
||||
{Name: "delay", Usage: "Delay ms", Default: strconv.Itoa(defaultBatchDelayMs)},
|
||||
},
|
||||
Run: runBatchLabel,
|
||||
Description: tr.T("cmd.issue.batch_label.short"),
|
||||
Flags: flags,
|
||||
Run: runBatchLabel,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
package issue
|
||||
|
||||
import (
|
||||
"github.com/gitlink-org/gitlink-cli/internal/i18n"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
const openIssueStatusID = 1
|
||||
|
||||
func newBatchOpenShortcut() *common.Shortcut {
|
||||
func newBatchOpenShortcut(tr *i18n.Translator) *common.Shortcut {
|
||||
return &common.Shortcut{
|
||||
Name: "batch-open",
|
||||
Description: "Reopen multiple issues",
|
||||
Flags: batchStateFlags(),
|
||||
Description: tr.T("cmd.issue.batch_open.short"),
|
||||
Flags: batchStateFlags(tr),
|
||||
Run: func(ctx *common.RuntimeContext) error { return runBatchStateChange(ctx, "open", openIssueStatusID) },
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gitlink-org/gitlink-cli/internal/i18n"
|
||||
"github.com/gitlink-org/gitlink-cli/shortcuts/common"
|
||||
)
|
||||
|
||||
|
|
@ -19,27 +20,24 @@ var updateFieldMapping = map[string]string{
|
|||
"priority": "priority_id",
|
||||
}
|
||||
|
||||
func newBatchUpdateShortcut() *common.Shortcut {
|
||||
func newBatchUpdateShortcut(tr *i18n.Translator) *common.Shortcut {
|
||||
flags := []common.Flag{
|
||||
// --ids 统一模式参数
|
||||
{Name: "ids", Short: "i", Usage: tr.T("flag.issue.batch_update.ids"), Required: false},
|
||||
{Name: "status", Short: "s", Usage: tr.T("flag.issue.batch_update.status")},
|
||||
{Name: "priority", Short: "p", Usage: tr.T("flag.issue.batch_update.priority")},
|
||||
{Name: "milestone", Short: "m", Usage: tr.T("flag.issue.batch_update.milestone")},
|
||||
{Name: "labels", Short: "l", Usage: tr.T("flag.issue.batch_update.tags")},
|
||||
{Name: "assignees", Short: "a", Usage: tr.T("flag.issue.batch_update.assignees")},
|
||||
// CSV 模式参数
|
||||
{Name: "from", Usage: tr.T("flag.issue.batch_update.csv")},
|
||||
}
|
||||
flags = append(flags, batchRuntimeFlags(tr)...)
|
||||
return &common.Shortcut{
|
||||
Name: "batch-update",
|
||||
Description: "Update multiple issues via CSV or --ids",
|
||||
Flags: []common.Flag{
|
||||
// --ids 统一模式参数
|
||||
{Name: "ids", Short: "i", Usage: "Comma-separated issue IDs", Required: false},
|
||||
{Name: "status", Short: "s", Usage: "New status: open or closed"},
|
||||
{Name: "priority", Short: "p", Usage: "Priority ID"},
|
||||
{Name: "milestone", Short: "m", Usage: "Milestone ID"},
|
||||
{Name: "labels", Short: "l", Usage: "Comma-separated label/tag IDs"},
|
||||
{Name: "assignees", Short: "a", Usage: "Comma-separated assignee user IDs"},
|
||||
// CSV 模式参数
|
||||
{Name: "from", Usage: "CSV file path with updates"},
|
||||
// 共享参数
|
||||
{Name: "dry-run", Usage: "Preview", Bool: true, Default: "false"},
|
||||
{Name: "confirm", Usage: "Confirm", Bool: true, Default: "false"},
|
||||
{Name: "max", Usage: "Max items", Default: strconv.Itoa(defaultBatchMaxItems)},
|
||||
{Name: "delay", Usage: "Delay ms", Default: strconv.Itoa(defaultBatchDelayMs)},
|
||||
},
|
||||
Run: runBatchUpdate,
|
||||
Description: tr.T("cmd.issue.batch_update.short"),
|
||||
Flags: flags,
|
||||
Run: runBatchUpdate,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,13 +51,13 @@ func normalizeIssueListState(state string) string {
|
|||
func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
||||
tr := shortcutTranslator(translators...)
|
||||
return []*common.Shortcut{
|
||||
newBatchCreateShortcut(),
|
||||
newBatchCloseShortcut(),
|
||||
newBatchOpenShortcut(),
|
||||
newBatchAssignShortcut(),
|
||||
newBatchLabelShortcut(),
|
||||
newBatchUpdateShortcut(),
|
||||
newBatchDeleteShortcut(),
|
||||
newBatchCreateShortcut(tr),
|
||||
newBatchCloseShortcut(tr),
|
||||
newBatchOpenShortcut(tr),
|
||||
newBatchAssignShortcut(tr),
|
||||
newBatchLabelShortcut(tr),
|
||||
newBatchUpdateShortcut(tr),
|
||||
newBatchDeleteShortcut(tr),
|
||||
{
|
||||
Name: "list",
|
||||
Description: tr.T("cmd.issue.list.short"),
|
||||
|
|
|
|||
|
|
@ -55,18 +55,18 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
},
|
||||
{
|
||||
Name: "issues",
|
||||
Description: "Search issues in a repository",
|
||||
Description: tr.T("cmd.search.issues.short"),
|
||||
Flags: []common.Flag{
|
||||
{Name: "keyword", Short: "k", Usage: "Search keyword", Required: true},
|
||||
{Name: "category", Short: "c", Usage: "Issue category: all, opened, closed", Default: "all"},
|
||||
{Name: "assignee", Short: "a", Usage: "Filter by assignee user ID"},
|
||||
{Name: "author", Usage: "Filter by author user ID"},
|
||||
{Name: "milestone", Short: "m", Usage: "Filter by milestone ID"},
|
||||
{Name: "tag", Short: "t", Usage: "Filter by tag IDs (comma-separated)"},
|
||||
{Name: "sort-by", Usage: "Sort field: updated_on, created_on, priority", Default: "updated_on"},
|
||||
{Name: "sort-dir", Usage: "Sort direction: asc, desc", Default: "desc"},
|
||||
{Name: "page", Short: "p", Usage: "Page number", Default: "1"},
|
||||
{Name: "limit", Short: "l", Usage: "Items per page", Default: "20"},
|
||||
{Name: "keyword", Short: "k", Usage: tr.T("flag.search.keyword"), Required: true},
|
||||
{Name: "category", Short: "c", Usage: tr.T("flag.search.issues.category"), Default: "all"},
|
||||
{Name: "assignee", Short: "a", Usage: tr.T("flag.search.issues.assignee")},
|
||||
{Name: "author", Usage: tr.T("flag.search.issues.author")},
|
||||
{Name: "milestone", Short: "m", Usage: tr.T("flag.search.issues.milestone")},
|
||||
{Name: "tag", Short: "t", Usage: tr.T("flag.search.issues.tag")},
|
||||
{Name: "sort-by", Usage: tr.T("flag.sort_by"), Default: "updated_on"},
|
||||
{Name: "sort-dir", Usage: tr.T("flag.sort_direction"), Default: "desc"},
|
||||
{Name: "page", Short: "p", Usage: tr.T("flag.page"), Default: "1"},
|
||||
{Name: "limit", Short: "l", Usage: tr.T("flag.limit"), Default: "20"},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
if err := ctx.ResolveOwnerRepo(); err != nil {
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
},
|
||||
{
|
||||
Name: "headmaps",
|
||||
Description: "Show user contribution heatmap",
|
||||
Description: tr.T("cmd.user.headmaps.short"),
|
||||
Flags: []common.Flag{
|
||||
{Name: "login", Short: "l", Usage: "User login name", Required: true},
|
||||
{Name: "login", Short: "l", Usage: tr.T("flag.user.login"), Required: true},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
login, err := ctx.RequireArg("login")
|
||||
|
|
@ -58,17 +58,17 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
return ctx.Output(env)
|
||||
},
|
||||
},
|
||||
newStatsShortcut("stats-activity", "Show user activity statistics", "activity"),
|
||||
newStatsShortcut("stats-develop", "Show user development capability", "develop"),
|
||||
newStatsShortcut("stats-role", "Show user role positioning", "role"),
|
||||
newStatsShortcut("stats-major", "Show user major positioning", "major"),
|
||||
newStatsShortcut(tr, "stats-activity", tr.T("cmd.user.stats_activity.short"), "activity"),
|
||||
newStatsShortcut(tr, "stats-develop", tr.T("cmd.user.stats_develop.short"), "develop"),
|
||||
newStatsShortcut(tr, "stats-role", tr.T("cmd.user.stats_role.short"), "role"),
|
||||
newStatsShortcut(tr, "stats-major", tr.T("cmd.user.stats_major.short"), "major"),
|
||||
{
|
||||
Name: "trends",
|
||||
Description: "Show user project activity trends",
|
||||
Description: tr.T("cmd.user.trends.short"),
|
||||
Flags: []common.Flag{
|
||||
{Name: "login", Short: "l", Usage: "User login name", Required: true},
|
||||
{Name: "page", Short: "p", Usage: "Page number", Default: "1"},
|
||||
{Name: "limit", Usage: "Items per page", Default: "20"},
|
||||
{Name: "login", Short: "l", Usage: tr.T("flag.user.login"), Required: true},
|
||||
{Name: "page", Short: "p", Usage: tr.T("flag.page"), Default: "1"},
|
||||
{Name: "limit", Usage: tr.T("flag.limit"), Default: "20"},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
login, err := ctx.RequireArg("login")
|
||||
|
|
@ -89,12 +89,12 @@ func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut {
|
|||
}
|
||||
|
||||
// newStatsShortcut 生成用户统计类 shortcut,消除 stats-activity/develop/role/major 的重复代码。
|
||||
func newStatsShortcut(name, desc, subPath string) *common.Shortcut {
|
||||
func newStatsShortcut(tr *i18n.Translator, name, desc, subPath string) *common.Shortcut {
|
||||
return &common.Shortcut{
|
||||
Name: name,
|
||||
Description: desc,
|
||||
Flags: []common.Flag{
|
||||
{Name: "login", Short: "l", Usage: "User login name", Required: true},
|
||||
{Name: "login", Short: "l", Usage: tr.T("flag.user.login"), Required: true},
|
||||
},
|
||||
Run: func(ctx *common.RuntimeContext) error {
|
||||
login, err := ctx.RequireArg("login")
|
||||
|
|
|
|||
Loading…
Reference in New Issue