diff --git a/cmd/kosli/assertApproval.go b/cmd/kosli/assertApproval.go
index 8f5eb846c..090955b8b 100644
--- a/cmd/kosli/assertApproval.go
+++ b/cmd/kosli/assertApproval.go
@@ -48,7 +48,7 @@ func newAssertApprovalCmd(out io.Writer) *cobra.Command {
Short: assertApprovalShortDesc,
Long: assertApprovalLongDesc,
Example: assertApprovalExample,
- Deprecated: "this command is deprecated and will be removed in a future release.",
+ Deprecated: deprecatedCommandMsg,
PreRunE: func(cmd *cobra.Command, args []string) error {
err := RequireGlobalFlags(global, []string{"Org", "ApiToken"})
if err != nil {
diff --git a/cmd/kosli/attestDecision.go b/cmd/kosli/attestDecision.go
index 59c4d07e8..ae20612ae 100644
--- a/cmd/kosli/attestDecision.go
+++ b/cmd/kosli/attestDecision.go
@@ -7,6 +7,7 @@ import (
"net/url"
"os"
+ "github.com/kosli-dev/cli/internal/docgen"
"github.com/kosli-dev/cli/internal/requests"
"github.com/spf13/cobra"
)
@@ -27,7 +28,7 @@ type attestDecisionOptions struct {
payload DecisionAttestationPayload
}
-const attestDecisionShortDesc = `[BETA] Record a compliance decision against a control in a Kosli trail. `
+const attestDecisionShortDesc = `Record a compliance decision against a control in a Kosli trail. `
const attestDecisionLongDesc = attestDecisionShortDesc + `
Use this command to record the outcome of evaluating a control as part of your delivery
@@ -92,11 +93,12 @@ func newAttestDecisionCmd(out io.Writer) *cobra.Command {
},
}
cmd := &cobra.Command{
- Use: "decision [IMAGE-NAME | FILE-PATH | DIR-PATH]",
- Short: attestDecisionShortDesc,
- Long: attestDecisionLongDesc,
- Example: attestDecisionExample,
- Hidden: true,
+ Use: "decision [IMAGE-NAME | FILE-PATH | DIR-PATH]",
+ Short: attestDecisionShortDesc,
+ Long: attestDecisionLongDesc,
+ Example: attestDecisionExample,
+ Hidden: true,
+ Annotations: map[string]string{docgen.DocHiddenAnnotation: "", betaCLIAnnotation: ""},
PreRunE: func(cmd *cobra.Command, args []string) error {
err := CustomMaximumNArgs(1, args)
if err != nil {
diff --git a/cmd/kosli/docs.go b/cmd/kosli/docs.go
index 00140383b..9cffff0e9 100644
--- a/cmd/kosli/docs.go
+++ b/cmd/kosli/docs.go
@@ -67,7 +67,8 @@ func (o *docsOptions) run() error {
Name: cmd.CommandPath(),
Beta: isBeta(cmd),
Deprecated: isDeprecated(cmd),
- DeprecMsg: cmd.Deprecated,
+ DeprecMsg: deprecationHint(cmd),
+ Hidden: isDocHidden(cmd),
Summary: cmd.Short,
Long: cmd.Long,
UseLine: cmd.UseLine(),
diff --git a/cmd/kosli/evaluate.go b/cmd/kosli/evaluate.go
index e2eb4e8a6..702d9ae4a 100644
--- a/cmd/kosli/evaluate.go
+++ b/cmd/kosli/evaluate.go
@@ -6,7 +6,7 @@ import (
"github.com/spf13/cobra"
)
-const evaluateShortDesc = `[BETA] Evaluate data against Rego policies.`
+const evaluateShortDesc = `Evaluate data against Rego policies.`
// Backtick breaks (`"` + "`x`" + `"`) are needed to embed markdown
// inline code spans inside raw string literals.
@@ -36,9 +36,10 @@ logic reusable across environments with different tolerances.`
func newEvaluateCmd(out io.Writer) *cobra.Command {
cmd := &cobra.Command{
- Use: "evaluate",
- Short: evaluateShortDesc,
- Long: evaluateLongDesc,
+ Use: "evaluate",
+ Short: evaluateShortDesc,
+ Long: evaluateLongDesc,
+ Annotations: map[string]string{betaCLIAnnotation: ""},
}
// Add subcommands
diff --git a/cmd/kosli/evaluateInput.go b/cmd/kosli/evaluateInput.go
index 61d561c3b..55fc3674c 100644
--- a/cmd/kosli/evaluateInput.go
+++ b/cmd/kosli/evaluateInput.go
@@ -15,7 +15,7 @@ type evaluateInputOptions struct {
inputFile string
}
-const evaluateInputShortDesc = `[BETA] Evaluate a local JSON input against a Rego policy.`
+const evaluateInputShortDesc = `Evaluate a local JSON input against a Rego policy.`
const evaluateInputLongDesc = evaluateInputShortDesc + `
Read JSON from a file or stdin and evaluate it against a Rego policy.
diff --git a/cmd/kosli/evaluateTrail.go b/cmd/kosli/evaluateTrail.go
index f967f2ce9..30ce4eba9 100644
--- a/cmd/kosli/evaluateTrail.go
+++ b/cmd/kosli/evaluateTrail.go
@@ -6,7 +6,7 @@ import (
"github.com/spf13/cobra"
)
-const evaluateTrailShortDesc = `[BETA] Evaluate a trail against a policy.`
+const evaluateTrailShortDesc = `Evaluate a trail against a policy.`
const evaluateTrailLongDesc = evaluateTrailShortDesc + `
Fetch a single trail from Kosli and evaluate it against a Rego policy.
diff --git a/cmd/kosli/evaluateTrails.go b/cmd/kosli/evaluateTrails.go
index 801a1850e..c4c015b43 100644
--- a/cmd/kosli/evaluateTrails.go
+++ b/cmd/kosli/evaluateTrails.go
@@ -6,7 +6,7 @@ import (
"github.com/spf13/cobra"
)
-const evaluateTrailsShortDesc = `[BETA] Evaluate multiple trails against a policy.`
+const evaluateTrailsShortDesc = `Evaluate multiple trails against a policy.`
const evaluateTrailsLongDesc = evaluateTrailsShortDesc + `
Fetch multiple trails from Kosli and evaluate them together against a Rego policy.
diff --git a/cmd/kosli/getApproval.go b/cmd/kosli/getApproval.go
index eab82ce2f..792a9203a 100644
--- a/cmd/kosli/getApproval.go
+++ b/cmd/kosli/getApproval.go
@@ -56,7 +56,7 @@ func newGetApprovalCmd(out io.Writer) *cobra.Command {
Long: getApprovalLongDesc,
Example: getApprovalExample,
Args: cobra.ExactArgs(1),
- Deprecated: "this command is deprecated and will be removed in a future release.",
+ Deprecated: deprecatedCommandMsg,
PreRunE: func(cmd *cobra.Command, args []string) error {
err := RequireGlobalFlags(global, []string{"Org", "ApiToken"})
if err != nil {
diff --git a/cmd/kosli/lifecycle_test.go b/cmd/kosli/lifecycle_test.go
new file mode 100644
index 000000000..3bc6e20b0
--- /dev/null
+++ b/cmd/kosli/lifecycle_test.go
@@ -0,0 +1,68 @@
+package main
+
+import (
+ "io"
+ "strings"
+ "testing"
+
+ "github.com/kosli-dev/cli/internal/docgen"
+ "github.com/spf13/cobra"
+)
+
+func TestLifecycleEvaluateIsBeta(t *testing.T) {
+ cmd := newEvaluateCmd(io.Discard)
+ if !isBeta(cmd) {
+ t.Error("expected evaluate command to be beta")
+ }
+ // subcommands inherit beta via parent walk
+ for _, sub := range cmd.Commands() {
+ if !isBeta(sub) {
+ t.Errorf("expected subcommand %q to inherit beta", sub.Name())
+ }
+ }
+}
+
+func TestLifecycleAttestDecisionIsBetaAndDocHidden(t *testing.T) {
+ global = &GlobalOpts{}
+ cmd := newAttestDecisionCmd(io.Discard)
+ if !cmd.Hidden {
+ t.Error("expected attest decision to stay Hidden")
+ }
+ if !isBeta(cmd) {
+ t.Error("expected attest decision to be beta")
+ }
+ if _, ok := cmd.Annotations[docgen.DocHiddenAnnotation]; !ok {
+ t.Error("expected attest decision to carry the docHidden annotation")
+ }
+ if !isDocHidden(cmd) {
+ t.Error("expected isDocHidden to be true for attest decision")
+ }
+}
+
+func TestDeprecationHint(t *testing.T) {
+ generic := &cobra.Command{Use: "x", Deprecated: deprecatedCommandMsg}
+ if got := deprecationHint(generic); got != "" {
+ t.Errorf("expected generic deprecation message suppressed, got %q", got)
+ }
+ custom := &cobra.Command{Use: "y", Deprecated: "use 'kosli snapshot paths' instead"}
+ if got := deprecationHint(custom); got != "use 'kosli snapshot paths' instead" {
+ t.Errorf("expected custom hint preserved, got %q", got)
+ }
+ none := &cobra.Command{Use: "z"}
+ if got := deprecationHint(none); got != "" {
+ t.Errorf("expected empty for non-deprecated command, got %q", got)
+ }
+}
+
+func TestLifecycleNoBetaTextPrefix(t *testing.T) {
+ global = &GlobalOpts{}
+ cmds := []*cobra.Command{
+ newEvaluateCmd(io.Discard),
+ newAttestDecisionCmd(io.Discard),
+ }
+ for _, c := range cmds {
+ if strings.Contains(c.Short, "[BETA]") {
+ t.Errorf("command %q still has [BETA] text prefix in Short", c.Name())
+ }
+ }
+}
diff --git a/cmd/kosli/listApprovals.go b/cmd/kosli/listApprovals.go
index 4ea277eec..ed125e5ca 100644
--- a/cmd/kosli/listApprovals.go
+++ b/cmd/kosli/listApprovals.go
@@ -55,7 +55,7 @@ func newListApprovalsCmd(out io.Writer) *cobra.Command {
Long: listApprovalsLongDesc,
Example: listApprovalsExample,
Args: cobra.NoArgs,
- Deprecated: "this command is deprecated and will be removed in a future release.",
+ Deprecated: deprecatedCommandMsg,
PreRunE: func(cmd *cobra.Command, args []string) error {
err := RequireGlobalFlags(global, []string{"Org", "ApiToken"})
if err != nil {
diff --git a/cmd/kosli/report.go b/cmd/kosli/report.go
index 7f880cee5..8d28066eb 100644
--- a/cmd/kosli/report.go
+++ b/cmd/kosli/report.go
@@ -13,7 +13,7 @@ func newReportCmd(out io.Writer) *cobra.Command {
Use: "report",
Short: reportDesc,
Long: reportDesc,
- Deprecated: "this command is deprecated and will be removed in a future release.",
+ Deprecated: deprecatedCommandMsg,
}
// Add subcommands
diff --git a/cmd/kosli/reportApproval.go b/cmd/kosli/reportApproval.go
index b128df21b..43a1f1ba1 100644
--- a/cmd/kosli/reportApproval.go
+++ b/cmd/kosli/reportApproval.go
@@ -87,7 +87,7 @@ func newReportApprovalCmd(out io.Writer) *cobra.Command {
Short: reportApprovalShortDesc,
Long: reportApprovalLongDesc,
Example: reportApprovalExample,
- Deprecated: "this command is deprecated and will be removed in a future release.",
+ Deprecated: deprecatedCommandMsg,
PreRunE: func(cmd *cobra.Command, args []string) error {
err := RequireGlobalFlags(global, []string{"Org", "ApiToken"})
if err != nil {
diff --git a/cmd/kosli/request.go b/cmd/kosli/request.go
index 551dd71f7..0f3cf4159 100644
--- a/cmd/kosli/request.go
+++ b/cmd/kosli/request.go
@@ -13,7 +13,7 @@ func newRequestCmd(out io.Writer) *cobra.Command {
Use: "request",
Short: requestDesc,
Long: requestDesc,
- Deprecated: "this command is deprecated and will be removed in a future release.",
+ Deprecated: deprecatedCommandMsg,
}
// Add subcommands
diff --git a/cmd/kosli/requestApproval.go b/cmd/kosli/requestApproval.go
index d484d1c51..f15368473 100644
--- a/cmd/kosli/requestApproval.go
+++ b/cmd/kosli/requestApproval.go
@@ -57,7 +57,7 @@ func newRequestApprovalCmd(out io.Writer) *cobra.Command {
Short: requestApprovalShortDesc,
Long: requestApprovalLongDesc,
Example: requestApprovalExample,
- Deprecated: "this command is deprecated and will be removed in a future release.",
+ Deprecated: deprecatedCommandMsg,
PreRunE: func(cmd *cobra.Command, args []string) error {
err := RequireGlobalFlags(global, []string{"Org", "ApiToken"})
if err != nil {
diff --git a/cmd/kosli/root.go b/cmd/kosli/root.go
index 3b5ce9208..9b4ec0625 100644
--- a/cmd/kosli/root.go
+++ b/cmd/kosli/root.go
@@ -7,6 +7,7 @@ import (
"path/filepath"
"strings"
+ "github.com/kosli-dev/cli/internal/docgen"
"github.com/kosli-dev/cli/internal/requests"
"github.com/kosli-dev/cli/internal/security"
"github.com/kosli-dev/cli/internal/version"
@@ -16,6 +17,10 @@ import (
"github.com/spf13/viper"
)
+const betaCLIAnnotation = "betaCLI"
+
+const deprecatedCommandMsg = "this command is deprecated and will be removed in a future release."
+
var globalUsage = `The Kosli CLI.
Environment variables:
@@ -572,12 +577,12 @@ func bindFlags(cmd *cobra.Command, v *viper.Viper) {
}
func isBeta(cmd *cobra.Command) bool {
- if _, ok := cmd.Annotations["betaCLI"]; ok {
+ if _, ok := cmd.Annotations[betaCLIAnnotation]; ok {
return true
}
var beta bool
cmd.VisitParents(func(cmd *cobra.Command) {
- if _, ok := cmd.Annotations["betaCLI"]; ok {
+ if _, ok := cmd.Annotations[betaCLIAnnotation]; ok {
beta = true
}
})
@@ -588,6 +593,21 @@ func isDeprecated(cmd *cobra.Command) bool {
return cmd.Deprecated != ""
}
+func isDocHidden(cmd *cobra.Command) bool {
+ _, ok := cmd.Annotations[docgen.DocHiddenAnnotation]
+ return ok
+}
+
+// deprecationHint returns the per-command migration hint to show on the docs
+// page. The generic boilerplate is conveyed by the docs snippet, so it is
+// suppressed here to avoid duplication; only custom hints are surfaced.
+func deprecationHint(cmd *cobra.Command) string {
+ if cmd.Deprecated == deprecatedCommandMsg {
+ return ""
+ }
+ return cmd.Deprecated
+}
+
const usageTemplate = `{{- if isBeta .}}Beta Feature:
{{.CommandPath}} is a beta feature.
Beta features provide early access to product functionality. These
diff --git a/cmd/kosli/testdata/output/docs/mintlify/artifact.md b/cmd/kosli/testdata/output/docs/mintlify/artifact.md
index b021046a8..74ab3ba6b 100644
--- a/cmd/kosli/testdata/output/docs/mintlify/artifact.md
+++ b/cmd/kosli/testdata/output/docs/mintlify/artifact.md
@@ -1,13 +1,15 @@
---
title: "artifact"
-beta: false
-deprecated: true
+tag: "DEPRECATED"
description: "Report an artifact creation to a Kosli flow. "
---
-
-**artifact** is deprecated. see kosli attest commands Deprecated commands will be removed in a future release.
-
+import CliDeprecatedNotice from "/snippets/cli-deprecated-notice.mdx";
+
+
+
+see kosli attest commands
+
## Synopsis
```shell
diff --git a/cmd/kosli/testdata/output/docs/mintlify/snyk.md b/cmd/kosli/testdata/output/docs/mintlify/snyk.md
index 8cc9443ad..728b2d1be 100644
--- a/cmd/kosli/testdata/output/docs/mintlify/snyk.md
+++ b/cmd/kosli/testdata/output/docs/mintlify/snyk.md
@@ -1,7 +1,5 @@
---
title: "snyk"
-beta: false
-deprecated: false
description: "Report a snyk attestation to an artifact or a trail in a Kosli flow. "
---
diff --git a/internal/docgen/formatter.go b/internal/docgen/formatter.go
index a787d7816..45f1c2169 100644
--- a/internal/docgen/formatter.go
+++ b/internal/docgen/formatter.go
@@ -2,12 +2,19 @@ package docgen
import "github.com/spf13/cobra"
+// DocHiddenAnnotation marks a hidden command that should still get a generated
+// docs page (with hidden: true front matter), as opposed to internal commands
+// that are never documented. cmd/kosli sets this annotation; the tree walker
+// checks for its presence.
+const DocHiddenAnnotation = "docHidden"
+
// CommandMeta holds metadata about a cobra command for doc generation.
type CommandMeta struct {
Name string
Beta bool
Deprecated bool
DeprecMsg string
+ Hidden bool
Summary string
Long string
UseLine string
diff --git a/internal/docgen/generate.go b/internal/docgen/generate.go
index 4dc282f0c..a03c8579b 100644
--- a/internal/docgen/generate.go
+++ b/internal/docgen/generate.go
@@ -15,8 +15,9 @@ import (
// leaf command using the provided Formatter.
func GenMarkdownTree(cmd *cobra.Command, dir string, formatter Formatter, metaFn CommandMetaFunc) error {
for _, c := range cmd.Commands() {
- // skip all unavailable commands except deprecated ones
- if (!c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand()) && c.Deprecated == "" {
+ // skip unavailable commands, except deprecated ones and hidden-but-documented ones
+ _, docHidden := c.Annotations[DocHiddenAnnotation]
+ if (!c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand()) && c.Deprecated == "" && !docHidden {
continue
}
if err := GenMarkdownTree(c, dir, formatter, metaFn); err != nil {
@@ -60,8 +61,9 @@ func genMarkdownCustom(cmd *cobra.Command, w io.Writer, formatter Formatter, met
// Title
buf.WriteString(formatter.Title(name))
- // Beta warning
- if meta.Beta {
+ // Beta warning. Deprecated takes precedence (matching lifecycleTag), so a
+ // command that is somehow both renders only the deprecated notice.
+ if meta.Beta && !meta.Deprecated {
buf.WriteString(formatter.BetaWarning(name))
}
diff --git a/internal/docgen/generate_test.go b/internal/docgen/generate_test.go
index e8a994a3a..a05de19e8 100644
--- a/internal/docgen/generate_test.go
+++ b/internal/docgen/generate_test.go
@@ -81,6 +81,46 @@ func TestGenMarkdownTreeSkipsHiddenCommands(t *testing.T) {
}
}
+func TestGenMarkdownTreeIncludesDocHiddenCommands(t *testing.T) {
+ dir := t.TempDir()
+
+ root := &cobra.Command{Use: "root"}
+ docHidden := &cobra.Command{
+ Use: "dochidden",
+ Short: "A hidden but documented cmd",
+ Long: "Hidden but documented long desc.",
+ Hidden: true,
+ Annotations: map[string]string{DocHiddenAnnotation: ""},
+ RunE: func(cmd *cobra.Command, args []string) error { return nil },
+ }
+ root.AddCommand(docHidden)
+
+ metaFn := func(cmd *cobra.Command) CommandMeta {
+ _, hidden := cmd.Annotations[DocHiddenAnnotation]
+ return CommandMeta{
+ Name: cmd.CommandPath(),
+ Hidden: hidden,
+ Summary: cmd.Short,
+ Long: cmd.Long,
+ UseLine: cmd.UseLine(),
+ Runnable: cmd.Runnable(),
+ }
+ }
+
+ if err := GenMarkdownTree(root, dir, MintlifyFormatter{}, metaFn); err != nil {
+ t.Fatalf("GenMarkdownTree error: %v", err)
+ }
+
+ expected := filepath.Join(dir, "root_dochidden.md")
+ content, err := os.ReadFile(expected)
+ if err != nil {
+ t.Fatalf("expected doc-hidden command to be generated: %v", err)
+ }
+ if !strings.Contains(string(content), "hidden: true") {
+ t.Errorf("expected hidden: true front matter, got:\n%s", string(content))
+ }
+}
+
func TestGenMarkdownTreeIncludesDeprecatedCommands(t *testing.T) {
dir := t.TempDir()
@@ -120,8 +160,8 @@ func TestGenMarkdownTreeIncludesDeprecatedCommands(t *testing.T) {
if err != nil {
t.Fatalf("failed to read file: %v", err)
}
- if !strings.Contains(string(content), "") {
- t.Error("expected deprecation warning in output")
+ if !strings.Contains(string(content), "") {
+ t.Error("expected deprecation snippet in output")
}
}
diff --git a/internal/docgen/mintlify.go b/internal/docgen/mintlify.go
index a68cba965..768894669 100644
--- a/internal/docgen/mintlify.go
+++ b/internal/docgen/mintlify.go
@@ -16,28 +16,43 @@ func (MintlifyFormatter) Title(name string) string {
func (MintlifyFormatter) FrontMatter(meta CommandMeta) string {
desc := sanitizeDescription(meta.Summary)
- return fmt.Sprintf("---\ntitle: \"%s\"\nbeta: %t\ndeprecated: %t\ndescription: \"%s\"\n---\n\n",
- meta.Name, meta.Beta, meta.Deprecated, desc)
+ var b strings.Builder
+ fmt.Fprintf(&b, "---\ntitle: \"%s\"\n", meta.Name)
+ if tag := lifecycleTag(meta); tag != "" {
+ fmt.Fprintf(&b, "tag: \"%s\"\n", tag)
+ }
+ if meta.Hidden {
+ b.WriteString("hidden: true\n")
+ }
+ fmt.Fprintf(&b, "description: \"%s\"\n---\n\n", desc)
+ return b.String()
+}
+
+// lifecycleTag returns the Mintlify sidebar tag for a command's stage.
+// Deprecated takes precedence over beta if both are somehow set.
+func lifecycleTag(meta CommandMeta) string {
+ switch {
+ case meta.Deprecated:
+ return "DEPRECATED"
+ case meta.Beta:
+ return "BETA"
+ default:
+ return ""
+ }
}
func (MintlifyFormatter) BetaWarning(name string) string {
- var b strings.Builder
- b.WriteString("\n")
- fmt.Fprintf(&b, "**%s** is a beta feature. ", name)
- fmt.Fprintf(&b, "Beta features provide early access to product functionality. ")
- fmt.Fprintf(&b, "These features may change between releases without warning, or can be removed in a ")
- fmt.Fprintf(&b, "future release.\n")
- fmt.Fprintf(&b, "Please contact us to enable this feature for your organization.\n")
- b.WriteString("\n")
- return b.String()
+ return "import CliBetaNotice from \"/snippets/cli-beta-notice.mdx\";\n\n\n\n"
}
func (MintlifyFormatter) DeprecatedWarning(name, message string) string {
var b strings.Builder
- b.WriteString("\n")
- fmt.Fprintf(&b, "**%s** is deprecated. %s ", name, message)
- fmt.Fprintf(&b, "Deprecated commands will be removed in a future release.\n")
- b.WriteString("\n")
+ b.WriteString("import CliDeprecatedNotice from \"/snippets/cli-deprecated-notice.mdx\";\n\n\n\n")
+ if message != "" {
+ // Escape the same way prose is escaped elsewhere, so a future hint
+ // containing <, {, or > does not break the MDX build.
+ fmt.Fprintf(&b, "%s\n\n", escapeMintlifyProse(message))
+ }
return b.String()
}
diff --git a/internal/docgen/mintlify_test.go b/internal/docgen/mintlify_test.go
index f15c0197e..4949d3b8b 100644
--- a/internal/docgen/mintlify_test.go
+++ b/internal/docgen/mintlify_test.go
@@ -36,17 +36,60 @@ func TestMintlifyFrontMatterTruncatesLongDescription(t *testing.T) {
}
}
+func TestMintlifyFrontMatterBetaTag(t *testing.T) {
+ f := MintlifyFormatter{}
+ got := f.FrontMatter(CommandMeta{Name: "kosli evaluate", Beta: true})
+ if !strings.Contains(got, `tag: "BETA"`) {
+ t.Errorf("expected BETA tag, got:\n%s", got)
+ }
+}
+
+func TestMintlifyFrontMatterDeprecatedTag(t *testing.T) {
+ f := MintlifyFormatter{}
+ got := f.FrontMatter(CommandMeta{Name: "kosli report approval", Deprecated: true})
+ if !strings.Contains(got, `tag: "DEPRECATED"`) {
+ t.Errorf("expected DEPRECATED tag, got:\n%s", got)
+ }
+}
+
+func TestMintlifyFrontMatterDeprecatedWinsOverBeta(t *testing.T) {
+ f := MintlifyFormatter{}
+ got := f.FrontMatter(CommandMeta{Name: "cmd", Beta: true, Deprecated: true})
+ if !strings.Contains(got, `tag: "DEPRECATED"`) || strings.Contains(got, `tag: "BETA"`) {
+ t.Errorf("expected DEPRECATED to win, got:\n%s", got)
+ }
+}
+
+func TestMintlifyFrontMatterHidden(t *testing.T) {
+ f := MintlifyFormatter{}
+ got := f.FrontMatter(CommandMeta{Name: "kosli attest decision", Hidden: true})
+ if !strings.Contains(got, "hidden: true") {
+ t.Errorf("expected hidden: true, got:\n%s", got)
+ }
+}
+
+func TestMintlifyFrontMatterNormalHasNoTagOrHidden(t *testing.T) {
+ f := MintlifyFormatter{}
+ got := f.FrontMatter(CommandMeta{Name: "kosli attest snyk"})
+ if strings.Contains(got, "tag:") {
+ t.Errorf("expected no tag for normal command, got:\n%s", got)
+ }
+ if strings.Contains(got, "hidden:") {
+ t.Errorf("expected no hidden key for normal command, got:\n%s", got)
+ }
+}
+
func TestMintlifyBetaWarning(t *testing.T) {
f := MintlifyFormatter{}
- got := f.BetaWarning("kosli foo")
- if !strings.Contains(got, "") {
- t.Error("expected Warning component")
+ got := f.BetaWarning("kosli evaluate")
+ if !strings.Contains(got, `import CliBetaNotice from "/snippets/cli-beta-notice.mdx";`) {
+ t.Errorf("expected beta snippet import, got:\n%s", got)
}
- if !strings.Contains(got, "") {
- t.Error("expected closing Warning component")
+ if !strings.Contains(got, "") {
+ t.Errorf("expected beta snippet component, got:\n%s", got)
}
- if !strings.Contains(got, "**kosli foo** is a beta feature") {
- t.Error("expected command name in warning")
+ if strings.Contains(got, "") {
+ t.Errorf("notice prose should live in the snippet, not the generator, got:\n%s", got)
}
}
@@ -63,12 +106,26 @@ func TestMintlifyTutorialTip(t *testing.T) {
func TestMintlifyDeprecatedWarning(t *testing.T) {
f := MintlifyFormatter{}
- got := f.DeprecatedWarning("kosli artifact", "see kosli attest commands")
- if !strings.Contains(got, "") {
- t.Error("expected Warning component")
+ got := f.DeprecatedWarning("kosli snapshot server", "use 'kosli snapshot paths' instead")
+ if !strings.Contains(got, `import CliDeprecatedNotice from "/snippets/cli-deprecated-notice.mdx";`) {
+ t.Errorf("expected deprecated snippet import, got:\n%s", got)
}
- if !strings.Contains(got, "**kosli artifact** is deprecated") {
- t.Error("expected deprecation message")
+ if !strings.Contains(got, "") {
+ t.Errorf("expected deprecated snippet component, got:\n%s", got)
+ }
+ if !strings.Contains(got, "use 'kosli snapshot paths' instead") {
+ t.Errorf("expected migration message as plain text, got:\n%s", got)
+ }
+ if strings.Contains(got, "") {
+ t.Errorf("notice prose should live in the snippet, not the generator, got:\n%s", got)
+ }
+}
+
+func TestMintlifyDeprecatedWarningEmptyMessage(t *testing.T) {
+ f := MintlifyFormatter{}
+ got := f.DeprecatedWarning("cmd", "")
+ if !strings.Contains(got, "") {
+ t.Errorf("expected snippet component, got:\n%s", got)
}
}