From 5c16a4a70edf177df1971fc98118c8497f674a77 Mon Sep 17 00:00:00 2001 From: Mengz <2567587994@qq.com> Date: Sun, 7 Jun 2026 17:45:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20shell=20=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=A1=A5=E5=85=A8=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 23 +++++++++++ README.zh-CN.md | 23 +++++++++++ cmd/cmd_test.go | 4 +- cmd/completion_test.go | 71 ++++++++++++++++++++++++++++++++ cmd/root.go | 38 +++++++++++++++++ doc/changes/shell-completion.md | 5 +++ internal/i18n/locales/en-US.json | 3 ++ internal/i18n/locales/zh-CN.json | 3 ++ skills/gitlink-shared/SKILL.md | 21 ++++++++++ 9 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 cmd/completion_test.go create mode 100644 doc/changes/shell-completion.md diff --git a/README.md b/README.md index e5e4318..cea7007 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,29 @@ export GITLINK_TOKEN="your-token" # Or set env var (for CI/CD, non-interactive e gitlink-cli repo +list ``` +#### Shell Completion + +Generate completion scripts for your shell after installation: + +```bash +# Bash +mkdir -p ~/.local/share/bash-completion/completions +gitlink-cli completion bash > ~/.local/share/bash-completion/completions/gitlink-cli + +# Zsh +gitlink-cli completion zsh > "${fpath[1]}/_gitlink-cli" + +# Fish +mkdir -p ~/.config/fish/completions +gitlink-cli completion fish > ~/.config/fish/completions/gitlink-cli.fish + +# PowerShell +gitlink-cli completion powershell > gitlink-cli.ps1 +. ./gitlink-cli.ps1 +``` + +Use `--no-descriptions` if your shell setup prefers compact completion output. + ### Quick Start (AI Agent) > The following steps are for AI Agents. Some steps require the user to complete actions in a browser. diff --git a/README.zh-CN.md b/README.zh-CN.md index 6a8879d..3810536 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -180,6 +180,29 @@ export GITLINK_TOKEN="your-token" # 或设置环境变量(适用于 CI/CD、 gitlink-cli repo +list ``` +#### Shell 自动补全 + +安装后可以为常用 shell 生成自动补全脚本: + +```bash +# Bash +mkdir -p ~/.local/share/bash-completion/completions +gitlink-cli completion bash > ~/.local/share/bash-completion/completions/gitlink-cli + +# Zsh +gitlink-cli completion zsh > "${fpath[1]}/_gitlink-cli" + +# Fish +mkdir -p ~/.config/fish/completions +gitlink-cli completion fish > ~/.config/fish/completions/gitlink-cli.fish + +# PowerShell +gitlink-cli completion powershell > gitlink-cli.ps1 +. ./gitlink-cli.ps1 +``` + +如果当前终端不需要补全说明文本,可以追加 `--no-descriptions` 生成更精简的脚本。 + ### 快速上手(AI Agent) > 以下步骤面向 AI Agent。部分步骤需要用户在浏览器中完成操作。 diff --git a/cmd/cmd_test.go b/cmd/cmd_test.go index 12499db..82aeed3 100644 --- a/cmd/cmd_test.go +++ b/cmd/cmd_test.go @@ -55,9 +55,9 @@ func TestRootCmdHasSubcommands(t *testing.T) { } names := map[string]bool{} for _, sub := range root.Commands() { - names[sub.Use] = true + names[sub.Name()] = true } - for _, want := range []string{"auth", "config", "doctor", "version"} { + for _, want := range []string{"auth", "completion", "config", "doctor", "version"} { if !names[want] { t.Fatalf("missing subcommand: %s", want) } diff --git a/cmd/completion_test.go b/cmd/completion_test.go new file mode 100644 index 0000000..7b4e1fb --- /dev/null +++ b/cmd/completion_test.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "bytes" + "strings" + "testing" +) + +func TestCompletionCmdGeneratesSupportedShells(t *testing.T) { + cases := []struct { + shell string + want string + }{ + {shell: "bash", want: "__gitlink-cli"}, + {shell: "zsh", want: "#compdef gitlink-cli"}, + {shell: "fish", want: "complete -c gitlink-cli"}, + {shell: "powershell", want: "Register-ArgumentCompleter"}, + } + + for _, tc := range cases { + root, err := NewRootCmd(RootOptions{Version: "test", Args: []string{"completion", tc.shell}}, nil) + if err != nil { + t.Fatal(err) + } + var out bytes.Buffer + root.SetOut(&out) + root.SetErr(&out) + if err := root.Execute(); err != nil { + t.Fatalf("%s completion error: %v", tc.shell, err) + } + if !strings.Contains(out.String(), tc.want) { + t.Fatalf("%s completion missing %q, got:\n%s", tc.shell, tc.want, out.String()[:min(len(out.String()), 400)]) + } + } +} + +func TestCompletionCmdNoDescriptions(t *testing.T) { + root, err := NewRootCmd(RootOptions{ + Version: "test", + Args: []string{"completion", "bash", "--no-descriptions"}, + }, nil) + if err != nil { + t.Fatal(err) + } + var out bytes.Buffer + root.SetOut(&out) + root.SetErr(&out) + if err := root.Execute(); err != nil { + t.Fatal(err) + } + if strings.Contains(out.String(), "GitLink CLI - command-line tool for GitLink") { + t.Fatalf("expected descriptions to be omitted") + } +} + +func TestCompletionCmdRejectsUnsupportedShell(t *testing.T) { + root, err := NewRootCmd(RootOptions{Version: "test", Args: []string{"completion", "xonsh"}}, nil) + if err != nil { + t.Fatal(err) + } + var out bytes.Buffer + root.SetOut(&out) + root.SetErr(&out) + err = root.Execute() + if err == nil { + t.Fatal("expected unsupported shell error") + } + if !strings.Contains(err.Error(), "invalid argument") { + t.Fatalf("expected invalid argument error, got %q", err.Error()) + } +} diff --git a/cmd/root.go b/cmd/root.go index 75f8532..14a47fe 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -58,6 +58,7 @@ func NewRootCmd(opts RootOptions, tr *i18n.Translator) (*cobra.Command, error) { rootCmd.AddCommand(apiCmd.NewAPICmd(tr)) rootCmd.AddCommand(configCmd.NewConfigCmd(tr)) rootCmd.AddCommand(doctorCmd.NewDoctorCmd(tr)) + rootCmd.AddCommand(newCompletionCmd(tr)) rootCmd.AddCommand(newVersionCmd(version, tr)) shortcuts.RegisterAll(rootCmd, tr) @@ -79,6 +80,43 @@ func newVersionCmd(version string, tr *i18n.Translator) *cobra.Command { } } +func newCompletionCmd(tr *i18n.Translator) *cobra.Command { + var noDescriptions bool + cmd := &cobra.Command{ + Use: "completion [bash|zsh|fish|powershell]", + Short: tr.T("cmd.completion.short"), + Long: tr.T("cmd.completion.long"), + ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, + Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), + RunE: func(cmd *cobra.Command, args []string) error { + root := cmd.Root() + out := cmd.OutOrStdout() + includeDescriptions := !noDescriptions + + switch args[0] { + case "bash": + return root.GenBashCompletionV2(out, includeDescriptions) + case "zsh": + if noDescriptions { + return root.GenZshCompletionNoDesc(out) + } + return root.GenZshCompletion(out) + case "fish": + return root.GenFishCompletion(out, includeDescriptions) + case "powershell": + if noDescriptions { + return root.GenPowerShellCompletion(out) + } + return root.GenPowerShellCompletionWithDesc(out) + default: + return fmt.Errorf("unsupported shell: %s", args[0]) + } + }, + } + cmd.Flags().BoolVar(&noDescriptions, "no-descriptions", false, tr.T("flag.completion.no_descriptions")) + return cmd +} + func Execute() error { args := os.Args[1:] rootCmd, err := NewRootCmd(RootOptions{ diff --git a/doc/changes/shell-completion.md b/doc/changes/shell-completion.md new file mode 100644 index 0000000..347e44b --- /dev/null +++ b/doc/changes/shell-completion.md @@ -0,0 +1,5 @@ +# Shell 自动补全命令 + +新增 `gitlink-cli completion [bash|zsh|fish|powershell]`,用于为 Bash、Zsh、Fish 和 PowerShell 生成原生自动补全脚本。用户安装 CLI 后可以直接把脚本写入对应 shell 的补全目录,减少记忆 Shortcut 命令、全局参数和子命令名称的成本,也让跨平台安装体验更完整。 + +命令支持 `--no-descriptions`,在不需要补全文案的终端配置中可以输出更精简的脚本。实现复用 Cobra 官方补全生成能力,不引入远端 API 依赖,并通过单元测试覆盖四类 shell 输出、描述开关和非法 shell 参数校验。 diff --git a/internal/i18n/locales/en-US.json b/internal/i18n/locales/en-US.json index 0739395..a38302c 100644 --- a/internal/i18n/locales/en-US.json +++ b/internal/i18n/locales/en-US.json @@ -16,6 +16,8 @@ "cmd.ci.restart.short": "Restart a build", "cmd.ci.short": "CI/CD operations", "cmd.ci.stop.short": "Stop a build", + "cmd.completion.long": "Generate shell completion scripts for gitlink-cli.\n\nLoad the generated script in your shell profile to enable command and flag completion.\n\nExamples:\n gitlink-cli completion bash > ~/.local/share/bash-completion/completions/gitlink-cli\n gitlink-cli completion zsh > \"${fpath[1]}/_gitlink-cli\"\n gitlink-cli completion fish > ~/.config/fish/completions/gitlink-cli.fish\n gitlink-cli completion powershell > gitlink-cli.ps1", + "cmd.completion.short": "Generate shell completion scripts", "cmd.config.get.short": "Get a configuration value", "cmd.config.init.short": "Initialize configuration file", "cmd.config.list.short": "List all configuration values", @@ -130,6 +132,7 @@ "flag.ci.stage": "Stage number", "flag.ci.step": "Step number", "flag.comment.body": "Comment body", + "flag.completion.no_descriptions": "Disable completion descriptions", "flag.dataset.description": "Dataset description", "flag.dataset.dry_run": "Preview the request without writing the dataset", "flag.dataset.dry_run_delete": "Preview the request without deleting the attachment", diff --git a/internal/i18n/locales/zh-CN.json b/internal/i18n/locales/zh-CN.json index 2e6fc4d..8468665 100644 --- a/internal/i18n/locales/zh-CN.json +++ b/internal/i18n/locales/zh-CN.json @@ -16,6 +16,8 @@ "cmd.ci.restart.short": "重启构建", "cmd.ci.short": "CI/CD 操作", "cmd.ci.stop.short": "停止构建", + "cmd.completion.long": "为 gitlink-cli 生成 shell 自动补全脚本。\n\n将生成的脚本加载到 shell 配置中,即可启用命令和参数补全。\n\n示例:\n gitlink-cli completion bash > ~/.local/share/bash-completion/completions/gitlink-cli\n gitlink-cli completion zsh > \"${fpath[1]}/_gitlink-cli\"\n gitlink-cli completion fish > ~/.config/fish/completions/gitlink-cli.fish\n gitlink-cli completion powershell > gitlink-cli.ps1", + "cmd.completion.short": "生成 shell 自动补全脚本", "cmd.config.get.short": "获取配置项", "cmd.config.init.short": "初始化配置文件", "cmd.config.list.short": "列出所有配置项", @@ -130,6 +132,7 @@ "flag.ci.stage": "阶段编号", "flag.ci.step": "步骤编号", "flag.comment.body": "评论内容", + "flag.completion.no_descriptions": "关闭补全描述", "flag.dataset.description": "数据集描述", "flag.dataset.dry_run": "预览请求,不写入数据集", "flag.dataset.dry_run_delete": "预览请求,不删除附件", diff --git a/skills/gitlink-shared/SKILL.md b/skills/gitlink-shared/SKILL.md index 55674de..aec2510 100644 --- a/skills/gitlink-shared/SKILL.md +++ b/skills/gitlink-shared/SKILL.md @@ -63,6 +63,27 @@ gitlink-cli auth login - HTTPS: `https://www.gitlink.org.cn/owner/repo.git` - SSH: `git@www.gitlink.org.cn:owner/repo.git` +## Shell 自动补全 + +安装后可以按用户当前 shell 生成补全脚本,帮助用户发现 Shortcut 子命令和参数: + +```bash +# Bash +gitlink-cli completion bash > ~/.local/share/bash-completion/completions/gitlink-cli + +# Zsh +gitlink-cli completion zsh > "${fpath[1]}/_gitlink-cli" + +# Fish +gitlink-cli completion fish > ~/.config/fish/completions/gitlink-cli.fish + +# PowerShell +gitlink-cli completion powershell > gitlink-cli.ps1 +. ./gitlink-cli.ps1 +``` + +如果终端补全不需要描述文本,可以追加 `--no-descriptions`。 + ## 输出格式 所有命令输出遵循统一 Envelope 格式: