feat: migrate doc and todo primary parameters to #85349380
This commit is contained in:
1 parent
7fbe7593c8
commit
290f39ecb8
4 files changed
+249
-33
No files matched your search
+23
-15
@@ -15,10 +15,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/cli"
|
||||
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd"
|
||||
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contract"
|
||||
apperrors "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contract"
|
||||
)
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
@@ -1018,7 +1018,7 @@ func inferMimeType(fileName string) string {
|
||||
}
|
||||
|
||||
// buildBlockElement 从 flags 构建块元素 JSON 对象。
|
||||
// 优先级: --element (原始 JSON) > --heading > --text
|
||||
// 优先级: --element (原始 JSON) > --heading > --text (旧名) > --content
|
||||
func buildBlockElement(cmd *cobra.Command) (any, error) {
|
||||
if raw, _ := cmd.Flags().GetString("element"); raw != "" {
|
||||
var obj any
|
||||
@@ -1037,13 +1037,13 @@ func buildBlockElement(cmd *cobra.Command) (any, error) {
|
||||
"heading": map[string]any{"text": h, "level": level},
|
||||
}, nil
|
||||
}
|
||||
if t, _ := cmd.Flags().GetString("text"); t != "" {
|
||||
if t := flagOrFallback(cmd, "text", "content"); t != "" {
|
||||
return map[string]any{
|
||||
"blockType": "paragraph",
|
||||
"paragraph": map[string]any{"text": t},
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("block content required: --text / --heading / --element")
|
||||
return nil, fmt.Errorf("block content required: --content / --heading / --element")
|
||||
}
|
||||
|
||||
// buildNodeTransferRunE creates a RunE handler for copy/move commands.
|
||||
@@ -2127,12 +2127,12 @@ WARNING: --mode overwrite 为破坏性写入,会清空原文档全部内容。
|
||||
Use: "insert",
|
||||
Short: "插入块元素",
|
||||
Long: `向文档插入块元素。通过 --element 传入 JSON 格式的块元素。
|
||||
可用 --text 快速插入段落,--heading + --level 快速插入标题。
|
||||
可用 --content 快速插入段落,--heading + --level 快速插入标题。
|
||||
|
||||
块类型: paragraph, heading, blockquote, callout, columns,
|
||||
orderedList, unorderedList, table, sheet, attachment, slot`,
|
||||
Example: ` # 快捷插入段落
|
||||
dws doc block insert --node DOC_ID --text "这是一段文字"
|
||||
dws doc block insert --node DOC_ID --content "这是一段文字"
|
||||
|
||||
# 快捷插入标题
|
||||
dws doc block insert --node DOC_ID --heading "二级标题" --level 2
|
||||
@@ -2155,7 +2155,7 @@ WARNING: --mode overwrite 为破坏性写入,会清空原文档全部内容。
|
||||
dws doc block insert --node DOC_ID --element '{"blockType":"unorderedList","unorderedList":{"list":{"listId":"list-2"}},"children":[{"text":"第二项"}]}'
|
||||
|
||||
# 在指定位置之前插入
|
||||
dws doc block insert --node DOC_ID --text "插入内容" --ref-block BLOCK_ID --where before`,
|
||||
dws doc block insert --node DOC_ID --content "插入内容" --ref-block BLOCK_ID --where before`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
nodeID, err := mustFlagOrFallback(cmd, "node", "url", "id", "node-id", "doc-id", "file-id")
|
||||
if err != nil {
|
||||
@@ -2241,14 +2241,14 @@ WARNING: --mode overwrite 为破坏性写入,会清空原文档全部内容。
|
||||
},
|
||||
Selection: contract.SelectionSpec{
|
||||
AgentSummary: "向文档插入块元素",
|
||||
UseWhen: []string{"在文档中插入新块(段落/标题等);简单场景用 --text/--heading,复杂块用 --element JSON"},
|
||||
UseWhen: []string{"在文档中插入新块(段落/标题等);简单场景用 --content/--heading,复杂块用 --element JSON"},
|
||||
AvoidWhen: []string{
|
||||
"整篇追加 Markdown 优先 doc update --mode append",
|
||||
"插入本地文件附件优先 doc media insert",
|
||||
"删块用 block delete;改已有块用 block update",
|
||||
},
|
||||
Examples: []string{
|
||||
"dws doc block insert --node <DOC_ID> --text \"这是一段文字\" --format json",
|
||||
"dws doc block insert --node <DOC_ID> --content \"这是一段文字\" --format json",
|
||||
"dws doc block insert --node <DOC_ID> --heading \"二级标题\" --level 2 --format json",
|
||||
},
|
||||
},
|
||||
@@ -2265,8 +2265,8 @@ WARNING: --mode overwrite 为破坏性写入,会清空原文档全部内容。
|
||||
Use: "update",
|
||||
Short: "更新块元素",
|
||||
Long: `更新文档中指定块的内容或样式。需提供 --block-id 和块元素内容。
|
||||
可用 --text 快速更新为段落,--heading + --level 快速更新为标题。`,
|
||||
Example: ` dws doc block update --node DOC_ID --block-id BLOCK_ID --text "新内容" # 查询 nodeId: dws doc search --query "..." 或 dws doc list # 查询 blockId: dws doc block list --node <nodeId>
|
||||
可用 --content 快速更新为段落,--heading + --level 快速更新为标题。`,
|
||||
Example: ` dws doc block update --node DOC_ID --block-id BLOCK_ID --content "新内容" # 查询 nodeId: dws doc search --query "..." 或 dws doc list # 查询 blockId: dws doc block list --node <nodeId>
|
||||
dws doc block update --node DOC_ID --block-id BLOCK_ID --element '{"blockType":"heading","heading":{"text":"新标题","level":1}}'`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := validateRequiredFlags(cmd, "block-id"); err != nil {
|
||||
@@ -2338,7 +2338,7 @@ WARNING: --mode overwrite 为破坏性写入,会清空原文档全部内容。
|
||||
"插入新块用 block insert;删除用 block delete",
|
||||
"改文档显示名用 rename;整篇覆盖用 update overwrite",
|
||||
},
|
||||
Examples: []string{"dws doc block update --node <DOC_ID> --block-id <BLOCK_ID> --text \"新内容\" --format json"},
|
||||
Examples: []string{"dws doc block update --node <DOC_ID> --block-id <BLOCK_ID> --content \"新内容\" --format json"},
|
||||
},
|
||||
Parameters: []contract.ParamDecl{
|
||||
{Name: "content-format", Property: "format"},
|
||||
@@ -2748,7 +2748,6 @@ WARNING: --mode overwrite 为破坏性写入,会清空原文档全部内容。
|
||||
|
||||
// block insert
|
||||
blockInsertCmd.Flags().String("node", "", "文档 ID 或 URL (必填)")
|
||||
blockInsertCmd.Flags().String("text", "", "快捷: 段落文本内容")
|
||||
blockInsertCmd.Flags().String("heading", "", "快捷: 标题文本")
|
||||
blockInsertCmd.Flags().Int("level", 1, "标题级别 1-6 (配合 --heading)")
|
||||
blockInsertCmd.Flags().String("element", "", "块元素 JSON (高级)")
|
||||
@@ -2762,7 +2761,6 @@ WARNING: --mode overwrite 为破坏性写入,会清空原文档全部内容。
|
||||
// block update
|
||||
blockUpdateCmd.Flags().String("node", "", "文档 ID 或 URL (必填)")
|
||||
blockUpdateCmd.Flags().String("block-id", "", "目标块 ID (必填)")
|
||||
blockUpdateCmd.Flags().String("text", "", "快捷: 段落文本内容")
|
||||
blockUpdateCmd.Flags().String("heading", "", "快捷: 标题文本")
|
||||
blockUpdateCmd.Flags().Int("level", 1, "标题级别 1-6 (配合 --heading)")
|
||||
blockUpdateCmd.Flags().String("element", "", "块元素 JSON (高级)")
|
||||
@@ -4644,6 +4642,16 @@ CLI 内部自动完成全部流程:
|
||||
RegisterCrossProductAliases(child)
|
||||
}
|
||||
}
|
||||
// Register the block content Primary after the cross-product pass. Registering
|
||||
// --content earlier would make the global content/markdown group expand a new
|
||||
// --markdown alias onto these commands, which is outside this migration.
|
||||
for _, cmd := range []*cobra.Command{blockInsertCmd, blockUpdateCmd} {
|
||||
corecmd.RegisterFlags(cmd, []corecmd.FlagSpec{{
|
||||
Name: "content",
|
||||
Usage: "快捷: 段落文本内容",
|
||||
Aliases: []string{"text"},
|
||||
}})
|
||||
}
|
||||
|
||||
// ── deprecated 标记:文件管理命令已迁移到 drive ──
|
||||
deprecatedDocToDrive := map[*cobra.Command]string{
|
||||
|
||||
+20
-10
@@ -11,11 +11,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd"
|
||||
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contract"
|
||||
apperrors "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/errors"
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contract"
|
||||
)
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
@@ -1017,14 +1017,20 @@ reset-reminder 写入的提醒规则。提醒写命令的成功响应只能作
|
||||
Short: "上传待办附件",
|
||||
Long: `上传待办附件
|
||||
⚠️ 重要:该接口会上传文件到附件,不可用于测试或试探性调用。调用前必须确认待办存在。`,
|
||||
Example: ` dws todo task add-attachment --task-id <taskId> --file-path <filePath>
|
||||
Example: ` dws todo task add-attachment --task-id <taskId> --file <filePath>
|
||||
# 查询 taskId: dws todo task list`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := validateRequiredFlags(cmd, "task-id", "file-path"); err != nil {
|
||||
return err
|
||||
filePath := flagOrFallback(cmd, "file-path", "file")
|
||||
taskID := mustGetFlag(cmd, "task-id")
|
||||
if taskID == "" && filePath == "" {
|
||||
return validateRequiredFlags(cmd, "task-id", "file")
|
||||
}
|
||||
if taskID == "" {
|
||||
return validateRequiredFlags(cmd, "task-id")
|
||||
}
|
||||
if filePath == "" {
|
||||
return validateRequiredFlags(cmd, "file")
|
||||
}
|
||||
|
||||
filePath, _ := cmd.Flags().GetString("file-path")
|
||||
meta, err := buildTodoLocalFileMeta(filePath, "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1092,8 +1098,8 @@ reset-reminder 写入的提醒规则。提醒写命令的成功响应只能作
|
||||
"要添加执行人/参与人/提醒时改用对应 add 命令",
|
||||
},
|
||||
Examples: []string{
|
||||
"dws todo task add-attachment --task-id <taskId> --file-path /path/to/file.pdf",
|
||||
"dws todo task add-attachment --task-id <taskId> --file-path /path/to/file.pdf --format json",
|
||||
"dws todo task add-attachment --task-id <taskId> --file /path/to/file.pdf",
|
||||
"dws todo task add-attachment --task-id <taskId> --file /path/to/file.pdf --format json",
|
||||
},
|
||||
},
|
||||
Parameters: []contract.ParamDecl{
|
||||
@@ -1247,7 +1253,11 @@ reset-reminder 写入的提醒规则。提醒写命令的成功响应只能作
|
||||
todoTaskListSubCmd.Flags().String("task-id", "", "待办任务 ID (必填)")
|
||||
todoTaskListAttachmentCmd.Flags().String("task-id", "", "待办任务 ID (必填)")
|
||||
todoTaskAddAttachment.Flags().String("task-id", "", "待办任务 ID (必填)")
|
||||
todoTaskAddAttachment.Flags().String("file-path", "", "本地文件路径(必填)")
|
||||
corecmd.RegisterFlags(todoTaskAddAttachment, []corecmd.FlagSpec{{
|
||||
Name: "file",
|
||||
Usage: "本地文件路径(必填)",
|
||||
Aliases: []string{"file-path"},
|
||||
}})
|
||||
todoTaskRemoveAttachmentCmd.Flags().String("task-id", "", "待办任务 ID (必填)")
|
||||
todoTaskRemoveAttachmentCmd.Flags().String("attachment-id", "", "待办附件 ID(必填)")
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import (
|
||||
// touching existing content. Params (nodeId/markdown/mode) are copied verbatim
|
||||
// from the update_document append call site in internal/helpers/doc.go.
|
||||
//
|
||||
// dws doc +doc-append --doc DOC_ID --text "今天的会议结论:下周一上线。"
|
||||
// dws doc +doc-append --doc DOC_ID --content "今天的会议结论:下周一上线。"
|
||||
var DocAppend = shortcut.Shortcut{
|
||||
Service: "doc",
|
||||
Command: "+doc-append",
|
||||
@@ -67,27 +67,28 @@ var DocAppend = shortcut.Shortcut{
|
||||
UseWhen: []string{"当你只想往一篇钉钉文档的最后面补一段文字、又不想动原有内容时使用;内部用文档更新的“追加(append)”模式,把你给的文本安全地拼到文档末尾,不需要你先去查文档块列表、算末尾位置或手工拼块结构。会真实写入文档内容。"},
|
||||
AvoidWhen: []string{"需要该 Shortcut 未公开的底层参数、原始响应或不同执行语义时,改用对应原子命令"},
|
||||
Examples: []string{
|
||||
"dws doc +doc-append --doc DOC_ID --text \"补充说明:本方案已评审通过。\"",
|
||||
"dws doc +doc-append --doc \"https://alidocs.dingtalk.com/i/nodes/<DOC_UUID>\" --text \"追加一行备注\"",
|
||||
"dws doc +doc-append --doc DOC_ID --content \"补充说明:本方案已评审通过。\"",
|
||||
"dws doc +doc-append --doc \"https://alidocs.dingtalk.com/i/nodes/<DOC_UUID>\" --content \"追加一行备注\"",
|
||||
},
|
||||
},
|
||||
Parameters: []contract.ParamDecl{renamedRequiredParam("content", "text")},
|
||||
},
|
||||
Flags: []shortcut.Flag{
|
||||
{Name: "doc", Type: shortcut.FlagString, Desc: "文档 documentId / nodeId(或文档 URL/token)", Required: true},
|
||||
{Name: "text", Type: shortcut.FlagString, Desc: "要追加到文档末尾的文本", Required: true},
|
||||
{Name: "content", Type: shortcut.FlagString, Desc: "要追加到文档末尾的文本", Required: true, Aliases: []string{"text"}},
|
||||
},
|
||||
Tips: []string{
|
||||
`dws doc +doc-append --doc DOC_ID --text "补充说明:本方案已评审通过。"`,
|
||||
`dws doc +doc-append --doc "https://alidocs.dingtalk.com/i/nodes/<DOC_UUID>" --text "追加一行备注"`,
|
||||
`dws doc +doc-append --doc DOC_ID --content "补充说明:本方案已评审通过。"`,
|
||||
`dws doc +doc-append --doc "https://alidocs.dingtalk.com/i/nodes/<DOC_UUID>" --content "追加一行备注"`,
|
||||
},
|
||||
Execute: func(rt *shortcut.RuntimeContext) error {
|
||||
nodeID := strings.TrimSpace(rt.Str("doc"))
|
||||
if nodeID == "" {
|
||||
return apperrors.NewValidation("--doc 不能为空,请提供文档 documentId/nodeId 或文档 URL")
|
||||
}
|
||||
text := rt.Str("text")
|
||||
text := rt.StrFirst("text", "content")
|
||||
if strings.TrimSpace(text) == "" {
|
||||
return apperrors.NewValidation("--text 不能为空,请提供要追加的文本")
|
||||
return apperrors.NewValidation("--content 不能为空,请提供要追加的文本")
|
||||
}
|
||||
|
||||
// update_document append: params copied verbatim from the helper's
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
// Copyright 2026 Alibaba Group
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package smart
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/runtimeannotate"
|
||||
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/helpers"
|
||||
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/shortcut"
|
||||
)
|
||||
|
||||
func TestPrimaryParamMigrationSmartPayloadCompatibility(t *testing.T) {
|
||||
commands := []struct {
|
||||
name string
|
||||
baseArgs []string
|
||||
wantProduct string
|
||||
wantTool string
|
||||
payloadKey string
|
||||
}{
|
||||
{
|
||||
name: "broadcast",
|
||||
baseArgs: []string{"chat", "+broadcast", "--to", "张三"},
|
||||
wantProduct: "chat",
|
||||
wantTool: "send_personal_message",
|
||||
payloadKey: "content",
|
||||
},
|
||||
{
|
||||
name: "dm",
|
||||
baseArgs: []string{"chat", "+dm", "--to", "张三"},
|
||||
wantProduct: "chat",
|
||||
wantTool: "send_personal_message",
|
||||
payloadKey: "content",
|
||||
},
|
||||
{
|
||||
name: "send-to-group",
|
||||
baseArgs: []string{"chat", "+send-to-group", "--group", "项目冲刺"},
|
||||
wantProduct: "chat",
|
||||
wantTool: "send_personal_message",
|
||||
payloadKey: "content",
|
||||
},
|
||||
{
|
||||
name: "doc-append",
|
||||
baseArgs: []string{"doc", "+doc-append", "--doc", "doc-1"},
|
||||
wantProduct: "doc",
|
||||
wantTool: "update_document",
|
||||
payloadKey: "markdown",
|
||||
},
|
||||
}
|
||||
spellings := []struct {
|
||||
name string
|
||||
args []string
|
||||
wantValue string
|
||||
}{
|
||||
{name: "old-only", args: []string{"--text", "legacy-value"}, wantValue: "legacy-value"},
|
||||
{name: "new-only", args: []string{"--content", "legacy-value"}, wantValue: "legacy-value"},
|
||||
{
|
||||
name: "both-different-old-wins",
|
||||
args: []string{"--text", "legacy-value", "--content", "canonical-value"},
|
||||
wantValue: "legacy-value",
|
||||
},
|
||||
}
|
||||
|
||||
for _, command := range commands {
|
||||
payloads := make(map[string]map[string]any, len(spellings))
|
||||
for _, spelling := range spellings {
|
||||
t.Run(command.name+"/"+spelling.name, func(t *testing.T) {
|
||||
fake := &platformCoverageCaller{}
|
||||
helpers.InitDeps(fake)
|
||||
root := newPlatformCoverageRoot()
|
||||
args := append([]string(nil), command.baseArgs...)
|
||||
args = append(args, spelling.args...)
|
||||
args = append(args, "--yes")
|
||||
root.SetArgs(args)
|
||||
if err := root.Execute(); err != nil {
|
||||
t.Fatalf("execute %v: %v", args, err)
|
||||
}
|
||||
if len(fake.calls) == 0 {
|
||||
t.Fatal("shortcut made no MCP call")
|
||||
}
|
||||
call := fake.calls[len(fake.calls)-1]
|
||||
if call.product != command.wantProduct || call.tool != command.wantTool {
|
||||
t.Fatalf("last call = %s/%s, want %s/%s", call.product, call.tool, command.wantProduct, command.wantTool)
|
||||
}
|
||||
if got := smartPrimaryPayloadValue(t, call.args, command.payloadKey); got != spelling.wantValue {
|
||||
t.Fatalf("payload value = %q, want %q; args=%#v", got, spelling.wantValue, call.args)
|
||||
}
|
||||
payloads[spelling.name] = call.args
|
||||
})
|
||||
}
|
||||
if !reflect.DeepEqual(payloads["old-only"], payloads["new-only"]) {
|
||||
t.Errorf("%s old/new payloads differ: old=%#v new=%#v", command.name, payloads["old-only"], payloads["new-only"])
|
||||
}
|
||||
if !reflect.DeepEqual(payloads["old-only"], payloads["both-different-old-wins"]) {
|
||||
t.Errorf("%s old/both payloads differ: old=%#v both=%#v", command.name, payloads["old-only"], payloads["both-different-old-wins"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func smartPrimaryPayloadValue(t *testing.T, args map[string]any, key string) string {
|
||||
t.Helper()
|
||||
value, _ := args[key].(string)
|
||||
if key == "markdown" {
|
||||
return value
|
||||
}
|
||||
var content map[string]string
|
||||
if err := json.Unmarshal([]byte(value), &content); err != nil {
|
||||
t.Fatalf("decode markdown content %q: %v", value, err)
|
||||
}
|
||||
return content["text"]
|
||||
}
|
||||
|
||||
func TestPrimaryParamMigrationSmartSurfaceAndContract(t *testing.T) {
|
||||
tests := []struct {
|
||||
service string
|
||||
command string
|
||||
}{
|
||||
{service: "chat", command: "+broadcast"},
|
||||
{service: "chat", command: "+dm"},
|
||||
{service: "chat", command: "+send-to-group"},
|
||||
{service: "doc", command: "+doc-append"},
|
||||
}
|
||||
|
||||
root := newPlatformCoverageRoot()
|
||||
for _, test := range tests {
|
||||
t.Run(test.service+"/"+test.command, func(t *testing.T) {
|
||||
cmd, _, err := root.Find([]string{test.service, test.command})
|
||||
if err != nil || cmd == nil {
|
||||
t.Fatalf("find command: %v", err)
|
||||
}
|
||||
canonical := cmd.Flags().Lookup("content")
|
||||
if canonical == nil || canonical.Hidden {
|
||||
t.Fatalf("canonical --content = %#v, want visible", canonical)
|
||||
}
|
||||
legacy := cmd.Flags().Lookup("text")
|
||||
if legacy == nil || !legacy.Hidden {
|
||||
t.Fatalf("legacy --text = %#v, want hidden", legacy)
|
||||
}
|
||||
if got := legacy.Annotations[runtimeannotate.AnnotationFlagAliasOf]; len(got) != 1 || got[0] != "content" {
|
||||
t.Fatalf("--text alias_of = %#v, want content", got)
|
||||
}
|
||||
if got := legacy.Annotations[runtimeannotate.AnnotationFlagAliasOrigin]; len(got) != 1 || got[0] != runtimeannotate.FlagAliasOriginCorecmdV1 {
|
||||
t.Fatalf("--text alias origin = %#v", got)
|
||||
}
|
||||
|
||||
var help bytes.Buffer
|
||||
cmd.SetOut(&help)
|
||||
if err := cmd.Help(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(help.String(), "--content") || strings.Contains(help.String(), "--text") {
|
||||
t.Fatalf("help does not expose only the new Primary:\n%s", help.String())
|
||||
}
|
||||
|
||||
spec := smartRegisteredShortcut(t, test.service, test.command)
|
||||
if len(spec.Contract.Parameters) != 1 {
|
||||
t.Fatalf("ParamDecls = %#v, want one", spec.Contract.Parameters)
|
||||
}
|
||||
param := spec.Contract.Parameters[0]
|
||||
if param.Name != "content" || param.Property != "text" ||
|
||||
param.Required == nil || !*param.Required || param.InterfaceType != "" {
|
||||
t.Fatalf("content ParamDecl = %#v", param)
|
||||
}
|
||||
for _, example := range append(append([]string(nil), spec.Tips...), spec.Contract.Selection.Examples...) {
|
||||
if strings.Contains(example, "--text") || !strings.Contains(example, "--content") {
|
||||
t.Fatalf("example does not recommend only --content: %q", example)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func smartRegisteredShortcut(t *testing.T, service, command string) shortcut.Shortcut {
|
||||
t.Helper()
|
||||
for _, spec := range shortcut.All() {
|
||||
if spec.Service == service && spec.Command == command {
|
||||
return spec
|
||||
}
|
||||
}
|
||||
t.Fatalf("registered shortcut %s %s not found", service, command)
|
||||
return shortcut.Shortcut{}
|
||||
}
|
||||
Reference in new issue
Block a user