mirror of
https://github.com/larksuite/cli.git
synced 2026-07-03 22:24:31 +08:00
Validate the example commands embedded in shortcut definitions (the "Example: lark-cli ..." lines in each shortcut's Tips, shown in --help) against the real command tree built by cmd.Build. Implemented entirely as test-only code in cmd/ (package cmd_test), so it ships in no binary and is not importable by product code; the truth source is cmd.Build, the same tree the binary uses, so the check cannot drift. It runs in the standard unit-test CI job (go test ./cmd/...); a renamed command or unaccepted flag in an example fails that job.
114 lines
4.1 KiB
Go
114 lines
4.1 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
// This file and its cmdexample_*_test.go siblings implement a test-only check:
|
|
// the example commands embedded in shortcut definitions (the "Example: lark-cli
|
|
// ..." lines in each shortcut's Tips, shown in --help) must match the real
|
|
// command tree. It lives entirely in _test.go files (package cmd_test) so it
|
|
// ships in no binary and is not importable by product code; the truth source is
|
|
// cmd.Build, the same tree the binary uses, so the check cannot drift.
|
|
//
|
|
// It runs in the standard unit-test CI job (go test ./cmd/...). A mismatch — an
|
|
// example using a renamed command or an unaccepted flag — fails that job.
|
|
|
|
package cmd_test
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/larksuite/cli/cmd"
|
|
"github.com/larksuite/cli/internal/cmdutil"
|
|
"github.com/larksuite/cli/shortcuts"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
// TestShortcutExampleCommands checks the example commands embedded in every
|
|
// shortcut's Tips against the live command tree. A shortcut that defines no
|
|
// example is simply skipped.
|
|
//
|
|
// Because the examples and the command definitions live in the same Go code,
|
|
// this is a self-consistency check: any mismatch (an example using a renamed
|
|
// command or a flag the command doesn't accept) is a bug to fix at the source.
|
|
// It runs over all shortcuts — no baseline, no diff — since a wrong example is
|
|
// always a defect, never acceptable "pre-existing drift".
|
|
func TestShortcutExampleCommands(t *testing.T) {
|
|
// Reproducibility: use the embedded API metadata (not a developer's stale
|
|
// ~/.lark-cli remote cache, which can miss commands) and an empty config
|
|
// dir so local strict mode / plugins / policy cannot reshape the tree.
|
|
// t.Setenv auto-restores after the test, so other cmd tests are unaffected.
|
|
t.Setenv("LARKSUITE_CLI_REMOTE_META", "off")
|
|
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
|
|
|
|
cat := buildCmdExampleCatalog()
|
|
|
|
type located struct {
|
|
shortcut string
|
|
f finding
|
|
}
|
|
var findings []located
|
|
for _, sc := range shortcuts.AllShortcuts() {
|
|
var refs []ref
|
|
for _, tip := range sc.Tips {
|
|
refs = append(refs, parseRefs(tip)...)
|
|
}
|
|
label := strings.TrimSpace(sc.Service + " " + sc.Command)
|
|
for _, f := range checkRefs(cat, refs) {
|
|
findings = append(findings, located{shortcut: label, f: f})
|
|
}
|
|
}
|
|
|
|
if len(findings) == 0 {
|
|
return
|
|
}
|
|
sort.Slice(findings, func(i, j int) bool { return findings[i].shortcut < findings[j].shortcut })
|
|
for _, lf := range findings {
|
|
hint := ""
|
|
if lf.f.suggest != "" {
|
|
hint = " (did you mean " + lf.f.suggest + "?)"
|
|
}
|
|
if lf.f.kind == unknownFlag {
|
|
t.Errorf("shortcut %q example uses unknown flag %s on %q%s\n %s",
|
|
lf.shortcut, lf.f.flag, lf.f.path, hint, strings.TrimSpace(lf.f.raw))
|
|
} else {
|
|
t.Errorf("shortcut %q example uses unknown command %q%s\n %s",
|
|
lf.shortcut, lf.f.path, hint, strings.TrimSpace(lf.f.raw))
|
|
}
|
|
}
|
|
t.Fatalf("%d shortcut example command(s) don't match the real CLI — "+
|
|
"fix the Example in the shortcut definition.", len(findings))
|
|
}
|
|
|
|
// buildCmdExampleCatalog walks the live cobra command tree and records every
|
|
// command path (minus the "lark-cli" root prefix) with its accepted flags and
|
|
// whether it is a parent group. This is the same Build() the binary uses, so
|
|
// the catalog can never drift from the real commands.
|
|
func buildCmdExampleCatalog() *catalog {
|
|
root := cmd.Build(context.Background(), cmdutil.InvocationContext{})
|
|
cat := newCatalog()
|
|
var walk func(c *cobra.Command)
|
|
walk = func(c *cobra.Command) {
|
|
path := strings.TrimSpace(strings.TrimPrefix(c.CommandPath(), "lark-cli"))
|
|
var flags []string
|
|
add := func(fl *pflag.Flag) {
|
|
flags = append(flags, "--"+fl.Name)
|
|
if fl.Shorthand != "" {
|
|
flags = append(flags, "-"+fl.Shorthand)
|
|
}
|
|
}
|
|
c.Flags().VisitAll(add)
|
|
c.InheritedFlags().VisitAll(add)
|
|
c.PersistentFlags().VisitAll(add) // root's own persistent flags (e.g. --profile)
|
|
cat.addCommand(path, flags)
|
|
cat.setGroup(path, c.HasSubCommands())
|
|
for _, sub := range c.Commands() {
|
|
walk(sub)
|
|
}
|
|
}
|
|
walk(root)
|
|
return cat
|
|
}
|