Fix: Corrects CLI generation and documentation issues (#7095)

Signed-off-by: Brian Kane <briankane1@gmail.com>
(cherry picked from commit 079356fad9)
This commit is contained in:
Brian Kane
2026-04-16 18:25:28 +01:00
committed by github-actions[bot]
parent 012a134829
commit 2841a79b10
29 changed files with 413 additions and 218 deletions

View File

@@ -72,15 +72,16 @@ const (
// Parameter defines a parameter for cli from capability template
type Parameter struct {
Name string `json:"name"`
Short string `json:"short,omitempty"`
Required bool `json:"required,omitempty"`
Default interface{} `json:"default,omitempty"`
Usage string `json:"usage,omitempty"`
Ignore bool `json:"ignore,omitempty"`
Type cue.Kind `json:"type,omitempty"`
Alias string `json:"alias,omitempty"`
JSONType string `json:"jsonType,omitempty"`
Name string `json:"name"`
Short string `json:"short,omitempty"`
Required bool `json:"required,omitempty"`
Default interface{} `json:"default,omitempty"`
Usage string `json:"usage,omitempty"`
Ignore bool `json:"ignore,omitempty"`
Type cue.Kind `json:"type,omitempty"`
Alias string `json:"alias,omitempty"`
JSONType string `json:"jsonType,omitempty"`
Immutable bool `json:"immutable,omitempty"`
}
// Capability defines the content of a capability

View File

@@ -907,26 +907,26 @@ spec:
`
var showCdResult = `# Specification
+---------+--------------------------------------------------------------------------------------------------+----------+----------+---------+
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT |
+---------+--------------------------------------------------------------------------------------------------+----------+----------+---------+
| count | specify number of tasks to run in parallel. | int | false | 1 |
| image | Which image would you like to use for your service. | string | true | |
| restart | Define the job restart policy, the value can only be Never or OnFailure. By default, it's Never. | string | false | Never |
| cmd | Commands to run in the container. | []string | false | |
+---------+--------------------------------------------------------------------------------------------------+----------+----------+---------+
+---------+--------------------------------------------------------------------------------------------------+----------+----------+---------+-----------+
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT | IMMUTABLE |
+---------+--------------------------------------------------------------------------------------------------+----------+----------+---------+-----------+
| count | specify number of tasks to run in parallel. | int | false | 1 | |
| image | Which image would you like to use for your service. | string | true | | |
| restart | Define the job restart policy, the value can only be Never or OnFailure. By default, it's Never. | string | false | Never | |
| cmd | Commands to run in the container. | []string | false | | |
+---------+--------------------------------------------------------------------------------------------------+----------+----------+---------+-----------+
`
var showTdResult = `# Specification
+---------+-------------+----------+----------+---------+
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT |
+---------+-------------+----------+----------+---------+
| name | | string | true | |
| image | | string | true | |
| command | | []string | false | |
+---------+-------------+----------+----------+---------+
+---------+-------------+----------+----------+---------+-----------+
| NAME | DESCRIPTION | TYPE | REQUIRED | DEFAULT | IMMUTABLE |
+---------+-------------+----------+----------+---------+-----------+
| name | | string | true | | |
| image | | string | true | | |
| command | | []string | false | | |
+---------+-------------+----------+----------+---------+-----------+
`

View File

@@ -46,7 +46,7 @@ func PrintCLIByTag(cmd *cobra.Command, all []*cobra.Command, tag string) string
cname := cmd.Name() + " " + c.Name()
link := cname
link = strings.Replace(link, " ", "_", -1)
pl = append(pl, cli.NewPrintable(c, fmt.Sprintf("* [%s](%s)\t - %s\n", cname, link, c.Long)))
pl = append(pl, cli.NewPrintable(c, fmt.Sprintf("* [%s](%s.md)\t - %s\n", cname, link, c.Long)))
}
slices.Sort(pl, func(i, j cli.Printable) bool { return i.Order < j.Order })
@@ -93,7 +93,7 @@ func GenMarkdownTreeForIndex(cmd *cobra.Command, dir string) error {
func main() {
rootPath := "../kubevela.io/docs/cli/"
rootPath := "../kubevela.github.io/docs/cli/"
if len(os.Args) > 1 {
rootPath = os.Args[1]
}
@@ -140,7 +140,7 @@ func main() {
if lastIdx == 0 {
return nil
}
lines[lastIdx] = "#### Go Back to [CLI Commands](vela) Homepage.\n\n\n###### Auto generated by [spf13/cobra script in KubeVela](https://github.com/kubevela/kubevela/tree/master/hack/docgen)."
lines[lastIdx] = "#### Go Back to [CLI Commands](vela.md) Homepage.\n\n\n###### Auto generated by [spf13/cobra script in KubeVela](https://github.com/kubevela/kubevela/tree/master/hack/docgen)."
// update the title format
title := strings.TrimPrefix(firstL, "## ")

View File

@@ -41,7 +41,8 @@ func main() {
location := flag.String("location", "", "path of output")
defdir := flag.String("def-dir", "", "path of definition dir")
tp := flag.String("type", "", "choose one of the definition to print")
i18nfile := flag.String("i18n", "../kubevela.io/static/reference-i18n.json", "file path of i18n data")
baseDir := flag.String("base-dir", "../kubevela.github.io", "base path of the kubevela docs site")
i18nfile := flag.String("i18n", "", "file path of i18n data (if not specified, i18n translations are not loaded)")
forceExample := flag.Bool("force-example-doc", false, "example must be provided for definitions")
flag.Parse()
@@ -57,6 +58,7 @@ func main() {
opt := mods.Options{
Path: *path,
Location: *location,
SitePath: *baseDir,
DefDirs: make([]string, 0),
ForceExamples: *forceExample,
}

View File

@@ -108,19 +108,21 @@ func ComponentDef(ctx context.Context, c common.Args, opt Options) {
}
if opt.Location == "" || opt.Location == "en" {
ref.I18N = &docgen.En
if err := ref.GenerateReferenceDocs(ctx, c, ComponentDefRefPath); err != nil {
path := opt.SiteBase() + "/docs/end-user/components/references.md"
if err := ref.GenerateReferenceDocs(ctx, c, path); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), ComponentDefRefPath)
fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), path)
}
if opt.Location == "" || opt.Location == "zh" {
ref.I18N = &docgen.Zh
ref.CustomDocHeader = CustomComponentHeaderZH
if err := ref.GenerateReferenceDocs(ctx, c, ComponentDefRefPathZh); err != nil {
path := opt.SiteBase() + "/i18n/zh/docusaurus-plugin-content-docs/current/end-user/components/references.md"
if err := ref.GenerateReferenceDocs(ctx, c, path); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), ComponentDefRefPathZh)
fmt.Printf("component reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), path)
}
}

View File

@@ -108,19 +108,21 @@ func PolicyDef(ctx context.Context, c common.Args, opt Options) {
}
if opt.Location == "" || opt.Location == "en" {
ref.I18N = &docgen.En
if err := ref.GenerateReferenceDocs(ctx, c, PolicyDefRefPath); err != nil {
path := opt.SiteBase() + "/docs/end-user/policies/references.md"
if err := ref.GenerateReferenceDocs(ctx, c, path); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), PolicyDefRefPath)
fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), path)
}
if opt.Location == "" || opt.Location == "zh" {
ref.I18N = &docgen.Zh
ref.CustomDocHeader = CustomPolicyHeaderZH
if err := ref.GenerateReferenceDocs(ctx, c, PolicyDefRefPathZh); err != nil {
path := opt.SiteBase() + "/i18n/zh/docusaurus-plugin-content-docs/current/end-user/policies/references.md"
if err := ref.GenerateReferenceDocs(ctx, c, path); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), PolicyDefRefPathZh)
fmt.Printf("policy reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), path)
}
}

View File

@@ -108,20 +108,22 @@ func TraitDef(ctx context.Context, c common.Args, opt Options) {
// Generate to default path depends on language
if opt.Location == "" || opt.Location == "en" {
ref.I18N = &docgen.En
if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPath); err != nil {
path := opt.SiteBase() + "/docs/end-user/traits/references.md"
if err := ref.GenerateReferenceDocs(ctx, c, path); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), TraitDefRefPath)
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), path)
}
if opt.Location == "" || opt.Location == "zh" {
ref.I18N = &docgen.Zh
ref.CustomDocHeader = CustomTraitHeaderZH
if err := ref.GenerateReferenceDocs(ctx, c, TraitDefRefPathZh); err != nil {
path := opt.SiteBase() + "/i18n/zh/docusaurus-plugin-content-docs/current/end-user/traits/references.md"
if err := ref.GenerateReferenceDocs(ctx, c, path); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), TraitDefRefPathZh)
fmt.Printf("trait reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), path)
}
}
}

View File

@@ -20,6 +20,15 @@ package mods
type Options struct {
Path string
Location string
SitePath string
DefDirs []string
ForceExamples bool
}
// SiteBase returns the base path of the docs site, defaulting to ../kubevela.io
func (o Options) SiteBase() string {
if o.SitePath != "" {
return o.SitePath
}
return "../kubevela.github.io"
}

View File

@@ -27,6 +27,7 @@ import (
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/workflow/providers"
"github.com/oam-dev/kubevela/references/docgen"
)
@@ -94,6 +95,7 @@ func WorkflowDef(ctx context.Context, c common.Args, opt Options) {
}
ref.Local = &docgen.FromLocal{Paths: opt.DefDirs}
ref.Client = singleton.KubeClient.Get()
ref.Compiler = providers.DefaultCompiler.Get()
if opt.Path != "" {
ref.I18N = &docgen.En
@@ -110,19 +112,21 @@ func WorkflowDef(ctx context.Context, c common.Args, opt Options) {
}
if opt.Location == "" || opt.Location == "en" {
ref.I18N = &docgen.En
if err := ref.GenerateReferenceDocs(ctx, c, WorkflowDefRefPath); err != nil {
path := opt.SiteBase() + "/docs/end-user/workflow/built-in-workflow-defs.md"
if err := ref.GenerateReferenceDocs(ctx, c, path); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), WorkflowDefRefPath)
fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), path)
}
if opt.Location == "" || opt.Location == "zh" {
ref.I18N = &docgen.Zh
ref.CustomDocHeader = CustomWorkflowHeaderZH
if err := ref.GenerateReferenceDocs(ctx, c, WorkflowDefRefPathZh); err != nil {
path := opt.SiteBase() + "/i18n/zh/docusaurus-plugin-content-docs/current/end-user/workflow/built-in-workflow-defs.md"
if err := ref.GenerateReferenceDocs(ctx, c, path); err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), WorkflowDefRefPathZh)
fmt.Printf("workflow reference docs (%s) successfully generated in %s \n", ref.I18N.Language(), path)
}
}

View File

@@ -65,7 +65,7 @@ func GetParameters(templateStr string) ([]types.Parameter, error) {
if param.Default == nil {
param.Default = getDefaultByKind(param.Type)
}
param.Short, param.Usage, param.Alias, param.Ignore = RetrieveComments(val)
param.Short, param.Usage, param.Alias, param.Ignore, param.Immutable = RetrieveComments(val)
params = append(params, param)
}
@@ -110,7 +110,7 @@ func GetParametersWithCuex(ctx context.Context, templateStr string) ([]types.Par
if param.Default == nil {
param.Default = getDefaultByKind(param.Type)
}
param.Short, param.Usage, param.Alias, param.Ignore = RetrieveComments(val)
param.Short, param.Usage, param.Alias, param.Ignore, param.Immutable = RetrieveComments(val)
params = append(params, param)
}
@@ -172,12 +172,12 @@ const (
AliasPrefix = "+alias="
// IgnorePrefix defines parameter in system level which we don't want our end user to see for KubeVela CLI
IgnorePrefix = "+ignore"
// ImmutablePrefix marks a parameter field as immutable after initial set
ImmutablePrefix = "+immutable"
)
// RetrieveComments will retrieve Usage, Short, Alias and Ignore from CUE Value
func RetrieveComments(value cue.Value) (string, string, string, bool) {
var short, usage, alias string
var ignore bool
// RetrieveComments will retrieve Usage, Short, Alias, Ignore and Immutable from CUE Value
func RetrieveComments(value cue.Value) (short, usage, alias string, ignore, immutable bool) {
docs := value.Doc()
for _, doc := range docs {
lines := strings.Split(doc.Text(), "\n")
@@ -197,9 +197,12 @@ func RetrieveComments(value cue.Value) (string, string, string, bool) {
if strings.HasPrefix(line, AliasPrefix) {
alias = strings.TrimPrefix(line, AliasPrefix)
}
if strings.HasPrefix(line, ImmutablePrefix) {
immutable = true
}
}
}
return short, usage, alias, ignore
return short, usage, alias, ignore, immutable
}
// IsFieldNotExist check whether the error type is the field not found

View File

@@ -86,6 +86,31 @@ func TestGetParameter(t *testing.T) {
}
assert.Equal(t, flag, true)
// Test cue parameter with "// +immutable" annotation
immutableCUE := `
parameter: {
// +usage=The image name
// +immutable
image: string
// +usage=The replica count
replicas: *1 | int
}
`
params, err = GetParameters(immutableCUE)
assert.NoError(t, err)
immutableFound := false
for _, para := range params {
if para.Name == "image" {
immutableFound = true
assert.True(t, para.Immutable, "image field should be marked immutable")
assert.Equal(t, "The image name", para.Usage)
}
if para.Name == "replicas" {
assert.False(t, para.Immutable, "replicas field should not be immutable")
}
}
assert.True(t, immutableFound, "Should find the immutable 'image' parameter")
// Test pattern parameter selectors which would cause panic with Unquoted()
data, _ = os.ReadFile("testdata/workloads/pattern-params.cue")
params, err = GetParameters(string(data))

View File

@@ -22,6 +22,7 @@ import (
"context"
"encoding/json"
"fmt"
"sort"
"strings"
ast2 "github.com/oam-dev/kubevela/pkg/definition/ast"
@@ -413,6 +414,7 @@ func ValidDefinitionTypes() []string {
for k := range DefinitionTypeToKind {
types = append(types, k)
}
sort.Strings(types)
return types
}

View File

@@ -211,9 +211,15 @@ func GetCUEParameterValue(cueStr string) (cue.Value, error) {
return val, nil
}
// GetCUExParameterValue converts definitions with cuex imports to cue format and extracts parameter field
func GetCUExParameterValue(ctx context.Context, cueStr string) (cue.Value, error) {
template, err := cuex.DefaultCompiler.Get().CompileStringWithOptions(
// GetCUExParameterValue converts definitions with cuex imports to cue format and extracts parameter field.
// An optional *cuex.Compiler can be passed to override the default compiler (e.g. to use one that has
// additional internal packages such as vela/builtin or vela/multicluster registered).
func GetCUExParameterValue(ctx context.Context, cueStr string, compilers ...*cuex.Compiler) (cue.Value, error) {
compiler := cuex.DefaultCompiler.Get()
if len(compilers) > 0 && compilers[0] != nil {
compiler = compilers[0]
}
template, err := compiler.CompileStringWithOptions(
ctx,
cueStr+velacue.BaseTemplate,
cuex.DisableResolveProviderFunctions{},

View File

@@ -417,6 +417,26 @@ parameter: {
assert.Equal(t, 2, fieldCount, "should have 2 parameter fields: name and config")
}
func TestGetCUExParameterValueWithCustomCompiler(t *testing.T) {
ctx := context.Background()
var validCueStr = `
parameter: {
name: string
}
`
// Pass the default compiler explicitly - exercises the custom compiler path
compiler := cuex.DefaultCompiler.Get()
val, err := GetCUExParameterValue(ctx, validCueStr, compiler)
assert.NoError(t, err, "should work with explicit compiler")
assert.True(t, val.Exists(), "parameter value should exist")
// Passing nil compiler falls back to default
val, err = GetCUExParameterValue(ctx, validCueStr, nil)
assert.NoError(t, err, "nil compiler should fall back to default")
assert.True(t, val.Exists(), "parameter value should exist with nil compiler")
}
func TestGenOpenAPI(t *testing.T) {
type want struct {
targetSchemaFile string

View File

@@ -501,13 +501,13 @@ func NewAddonPushCommand(c common.Args) *cobra.Command {
Short: "uploads an addon package to ChartMuseum",
Long: `Uploads an addon package to ChartMuseum.
Two arguments are needed <addon directory/package> and <name/URL of ChartMuseum>.
Two arguments are needed ` + "`<addon directory/package>`" + ` and ` + "`<name/URL of ChartMuseum>`" + `.
The first argument <addon directory/package> can be:
The first argument ` + "`<addon directory/package>`" + ` can be:
- your conventional addon directory (containing metadata.yaml). We will package it for you.
- packaged addon (.tgz) generated by 'vela addon package' command
The second argument <name/URL of ChartMuseum> can be:
The second argument ` + "`<name/URL of ChartMuseum>`" + ` can be:
- registry name (helm type). You can add your ChartMuseum registry using 'vela addon registry add'.
- ChartMuseum URL, e.g. http://localhost:8080`,
Example: `# Push the addon in directory <your-addon> to a ChartMuseum registry named <localcm>

View File

@@ -33,9 +33,8 @@ The shell code must be evaluated to provide interactive completion of vela comma
const bashCompDesc = `Generate the autocompletion script for Vela for the bash shell.
To load completions in your current shell session:
$ source <(vela completion bash)
To load completions for every new session, execute once:
` + "```\n$ source <(vela completion bash)\n```\n\n" + `To load completions for every new session, execute once:
Linux:
$ vela completion bash > /etc/bash_completion.d/vela
MacOS:
@@ -45,11 +44,10 @@ MacOS:
const zshCompDesc = `Generate the autocompletion script for Vela for the zsh shell.
To load completions in your current shell session:
$ source <(vela completion zsh)
To load completions for every new session, execute once:
$ vela completion zsh > "${fpath[1]}/_vela"
`
` + "```\n$ source <(vela completion zsh)\n```\n\n" + `To load completions for every new session, execute once:
` + "```\n$ vela completion zsh > \"${fpath[1]}/_vela\"\n```\n"
// NewCompletionCommand Output shell completion code for the specified shell (bash or zsh)
func NewCompletionCommand(order string) *cobra.Command {

View File

@@ -1156,7 +1156,7 @@ func NewDefinitionRenderCommand(c common.Args) *cobra.Command {
"> vela def render my-webservice.cue -o my-webservice.yaml\n" +
"# Command below will render all CUE and Go definitions in the ./defs/ directory and save the YAML objects in ./defs/yaml/.\n" +
"> vela def render ./defs/ -o ./defs/yaml/\n" +
"# Command below will render all Go definitions in ./defs/ and save CUE output in ./defs/cue/.\n" +
"# Command below will render all CUE and Go definitions in ./defs/ and save CUE output in ./defs/cue/.\n" +
"> vela def render ./defs/ -o ./defs/cue/ --format cue",
Args: cobra.ExactArgs(1),
Annotations: map[string]string{

View File

@@ -1963,8 +1963,8 @@ func NewDefinitionGenModuleCommand(_ common.Args, streams util.IOStreams) *cobra
This command loads a Go definition module, compiles all definitions to CUE,
and writes the generated CUE files to an output directory organized by type.
Output structure:
<output>/
Output structure:` + "\n\n```\n" +
` <output>/
components/
webservice.cue
worker.cue
@@ -1973,7 +1973,7 @@ Output structure:
policies/
topology.cue
workflowsteps/
deploy.cue`,
deploy.cue` + "\n```",
Example: `# Generate CUE from a local module (output to ./cue-generated)
> vela def gen-module ./my-definitions

View File

@@ -54,7 +54,7 @@ func NewUISchemaCommand(c common.Args, order string, ioStreams util.IOStreams) *
}
cmd.AddCommand(&cobra.Command{
Use: "apply",
Short: "apply <ui schema file/dir path>",
Short: "apply `<ui schema file/dir path>`",
Args: cobra.ExactArgs(1),
Long: "apply UI schema from a file or dir",
Annotations: map[string]string{

View File

@@ -55,9 +55,11 @@ func NewQlCommand(c common.Args, order string, ioStreams util.IOStreams) *cobra.
cmd := &cobra.Command{
Use: "ql",
Short: "Show result of executing velaQL.",
Long: `Show result of executing velaQL, use it like:
vela ql --query "inner-view-name{param1=value1,param2=value2}"
vela ql --file ./ql.cue`,
Long: `Show result of executing velaQL, use it like:` +
"\n\n```\n" +
"vela ql --query \"inner-view-name{param1=value1,param2=value2}\"\n" +
"vela ql --file ./ql.cue\n" +
"```",
Example: ` Users can query with a query statement:
vela ql --query "inner-view-name{param1=value1,param2=value2}"

View File

@@ -5,114 +5,114 @@
### *Params*
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
cluster | The cluster to use. | string | true |
resource | The resource to get or apply. | map[string]_ | true |
options | The options to get or apply. | [options](#options) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
cluster | The cluster to use. | string | true | |
resource | The resource to get or apply. | map[string]_ | true | |
options | The options to get or apply. | [options](#options) | true | |
#### options
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
threeWayMergePatch | The strategy of the resource. | [threeWayMergePatch](#threewaymergepatch) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
threeWayMergePatch | The strategy of the resource. | [threeWayMergePatch](#threewaymergepatch) | true | |
##### threeWayMergePatch
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
enabled | The strategy to get or apply the resource. | bool | false | true
annotationPrefix | The annotation prefix to use for the three way merge patch. | string | false | resource
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
enabled | The strategy to get or apply the resource. | bool | false | true |
annotationPrefix | The annotation prefix to use for the three way merge patch. | string | false | resource |
### *Returns*
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
\- | | {} | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
\- | | {} | true | |
## #Get
### *Params*
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
cluster | The cluster to use. | string | true |
resource | The resource to get or apply. | map[string]_ | true |
options | The options to get or apply. | [options](#options) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
cluster | The cluster to use. | string | true | |
resource | The resource to get or apply. | map[string]_ | true | |
options | The options to get or apply. | [options](#options) | true | |
#### options
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
threeWayMergePatch | The strategy of the resource. | [threeWayMergePatch](#threewaymergepatch) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
threeWayMergePatch | The strategy of the resource. | [threeWayMergePatch](#threewaymergepatch) | true | |
##### threeWayMergePatch
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
enabled | The strategy to get or apply the resource. | bool | false | true
annotationPrefix | The annotation prefix to use for the three way merge patch. | string | false | resource
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
enabled | The strategy to get or apply the resource. | bool | false | true |
annotationPrefix | The annotation prefix to use for the three way merge patch. | string | false | resource |
### *Returns*
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
\- | | {} | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
\- | | {} | true | |
## #List
### *Params*
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
cluster | The cluster to use. | string | true |
filter | The filter to list the resources. | [filter](#filter) | false |
resource | The resource to list. | map[string]_ | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
cluster | The cluster to use. | string | true | |
filter | The filter to list the resources. | [filter](#filter) | false | |
resource | The resource to list. | map[string]_ | true | |
#### filter
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
namespace | The namespace to list the resources. | string | false |
matchingLabels | The label selector to filter the resources. | map[string]string | false |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
namespace | The namespace to list the resources. | string | false | |
matchingLabels | The label selector to filter the resources. | map[string]string | false | |
### *Returns*
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
\- | | {} | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
\- | | {} | true | |
## #Patch
### *Params*
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
cluster | The cluster to use. | string | true |
resource | The resource to patch. | map[string]_ | true |
patch | The patch to be applied to the resource with kubernetes patch. | [patch](#patch) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
cluster | The cluster to use. | string | true | |
resource | The resource to patch. | map[string]_ | true | |
patch | The patch to be applied to the resource with kubernetes patch. | [patch](#patch) | true | |
#### patch
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
type | The type of patch being provided. | "merge" or "json" or "strategic" | true |
data | | _ | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
type | The type of patch being provided. | "merge" or "json" or "strategic" | true | |
data | | _ | true | |
### *Returns*
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
\- | | {} | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
\- | | {} | true | |
------

View File

@@ -68,6 +68,23 @@ func TestGenerateCUETemplateProperties(t *testing.T) {
},
expectErr: true,
},
{
name: "component definition with immutable parameter",
capability: &types.Capability{
Name: "test-immutable",
CueTemplate: `
parameter: {
// +usage=The image to use
// +immutable
image: string
// +usage=The replica count
replicas: *1 | int
}
`,
},
expectedTables: 1,
expectErr: false,
},
}
for _, tc := range testCases {

View File

@@ -184,6 +184,10 @@ var i18nDoc = map[string]map[Language]string{
LangZh: "默认值",
LangEn: "Default",
},
"Immutable": {
LangZh: "不可变",
LangEn: "Immutable",
},
"Apply To Component Types": {
LangZh: "适用于组件类型",
LangEn: "Apply To Component Types",

View File

@@ -24,6 +24,7 @@ import (
"sort"
"strings"
"github.com/kubevela/pkg/cue/cuex"
"github.com/pkg/errors"
"golang.org/x/text/cases"
"golang.org/x/text/language"
@@ -43,6 +44,10 @@ type MarkdownReference struct {
AllInOne bool
ForceExample bool
CustomDocHeader string
// Compiler overrides the default cuex compiler used to extract CUE parameter values.
// Set this to providers.DefaultCompiler.Get() when generating docs for definitions that
// import vela-specific packages (vela/builtin, vela/multicluster, etc.).
Compiler *cuex.Compiler
ParseReference
}
@@ -148,7 +153,7 @@ func (ref *MarkdownReference) GenerateMarkdownForCap(_ context.Context, c types.
// TODO: Use context from caller for proper cancellation/timeout support
// Currently using Background() to avoid breaking changes to function
ctx := context.Background()
cueValue, err := common.GetCUExParameterValue(ctx, c.CueTemplate)
cueValue, err := common.GetCUExParameterValue(ctx, c.CueTemplate, ref.Compiler)
if err != nil && !errors.Is(err, cue.ErrParameterNotExist) {
return "", fmt.Errorf("failed to retrieve `parameters` value from %s with err: %w", c.Name, err)
}
@@ -283,26 +288,31 @@ func (ref *MarkdownReference) getParameterString(tableName string, parameterList
if tableName == "" || tableName == Specification {
tab = "\n\n"
}
tab += fmt.Sprintf(" %s | %s | %s | %s | %s \n", ref.I18N.Get("Name"), ref.I18N.Get("Description"), ref.I18N.Get("Type"), ref.I18N.Get("Required"), ref.I18N.Get("Default"))
tab += fmt.Sprintf(" %s | %s | %s | %s | %s \n",
tab += fmt.Sprintf(" %s | %s | %s | %s | %s | %s \n", ref.I18N.Get("Name"), ref.I18N.Get("Description"), ref.I18N.Get("Type"), ref.I18N.Get("Required"), ref.I18N.Get("Default"), ref.I18N.Get("Immutable"))
tab += fmt.Sprintf(" %s | %s | %s | %s | %s | %s \n",
strings.Repeat("-", len(ref.I18N.Get("Name"))),
strings.Repeat("-", len(ref.I18N.Get("Description"))),
strings.Repeat("-", len(ref.I18N.Get("Type"))),
strings.Repeat("-", len(ref.I18N.Get("Required"))),
strings.Repeat("-", len(ref.I18N.Get("Default"))))
strings.Repeat("-", len(ref.I18N.Get("Default"))),
strings.Repeat("-", len(ref.I18N.Get("Immutable"))))
switch category {
case types.CUECategory:
for _, p := range parameterList {
if !p.Ignore {
printableDefaultValue := ref.getCUEPrintableDefaultValue(p.Default)
tab += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, ref.prettySentence(p.Usage), ref.formatTableString(p.PrintableType), p.Required, printableDefaultValue)
immutableVal := ""
if p.Immutable {
immutableVal = "true"
}
tab += fmt.Sprintf(" %s | %s | %s | %t | %s | %s \n", p.Name, ref.prettySentence(p.Usage), ref.formatTableString(p.PrintableType), p.Required, printableDefaultValue, immutableVal)
}
}
case types.TerraformCategory:
// Terraform doesn't have default value
for _, p := range parameterList {
tab += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, ref.prettySentence(p.Usage), ref.formatTableString(p.PrintableType), p.Required, "")
tab += fmt.Sprintf(" %s | %s | %s | %t | %s | %s \n", p.Name, ref.prettySentence(p.Usage), ref.formatTableString(p.PrintableType), p.Required, "", "")
}
default:
}

View File

@@ -126,19 +126,23 @@ func (ref *ParseReference) formatTableString(s string) string {
func (ref *ParseReference) prepareConsoleParameter(tableName string, parameterList []ReferenceParameter, category types.CapabilityCategory) ConsoleReference {
table := tablewriter.NewWriter(os.Stdout)
table.SetColWidth(100)
table.SetHeader([]string{ref.I18N.Get("Name"), ref.I18N.Get("Description"), ref.I18N.Get("Type"), ref.I18N.Get("Required"), ref.I18N.Get("Default")})
table.SetHeader([]string{ref.I18N.Get("Name"), ref.I18N.Get("Description"), ref.I18N.Get("Type"), ref.I18N.Get("Required"), ref.I18N.Get("Default"), ref.I18N.Get("Immutable")})
switch category {
case types.CUECategory:
for _, p := range parameterList {
if !p.Ignore {
printableDefaultValue := ref.getCUEPrintableDefaultValue(p.Default)
table.Append([]string{ref.I18N.Get(p.Name), ref.prettySentence(p.Usage), ref.I18N.Get(p.PrintableType), ref.I18N.Get(strconv.FormatBool(p.Required)), ref.I18N.Get(printableDefaultValue)})
immutableVal := ""
if p.Immutable {
immutableVal = "true"
}
table.Append([]string{ref.I18N.Get(p.Name), ref.prettySentence(p.Usage), ref.I18N.Get(p.PrintableType), ref.I18N.Get(strconv.FormatBool(p.Required)), ref.I18N.Get(printableDefaultValue), immutableVal})
}
}
case types.TerraformCategory:
// Terraform doesn't have default value
for _, p := range parameterList {
table.Append([]string{ref.I18N.Get(p.Name), ref.prettySentence(p.Usage), ref.I18N.Get(p.PrintableType), ref.I18N.Get(strconv.FormatBool(p.Required)), ""})
table.Append([]string{ref.I18N.Get(p.Name), ref.prettySentence(p.Usage), ref.I18N.Get(p.PrintableType), ref.I18N.Get(strconv.FormatBool(p.Required)), "", ""})
}
default:
}
@@ -250,7 +254,7 @@ func (ref *ParseReference) parseParameters(capName string, paraValue cue.Value,
param.Default = velacue.GetDefault(def)
}
param.Required = !fi.IsOptional && (param.Default == nil)
param.Short, param.Usage, param.Alias, param.Ignore = velacue.RetrieveComments(val)
param.Short, param.Usage, param.Alias, param.Ignore, param.Immutable = velacue.RetrieveComments(val)
param.Type = val.IncompleteKind()
switch val.IncompleteKind() {
case cue.StructKind:

View File

@@ -479,18 +479,18 @@ func TestExtractParameter(t *testing.T) {
}`,
contains: `### normal-case
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
str | | string | true |
itr | | int | true |
btr | | bool | true |
ct | | [ct](#ct) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
str | | string | true | |
itr | | int | true | |
btr | | bool | true | |
ct | | [ct](#ct) | true | |
#### ct
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
cts | | string | true |`,
},
"normal-map-string-string": {
@@ -499,8 +499,8 @@ func TestExtractParameter(t *testing.T) {
}`,
contains: `### normal-map-string-string
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
envMappings | | map[string]string | true | `,
},
"normal-map-case": {
@@ -514,16 +514,16 @@ func TestExtractParameter(t *testing.T) {
}`,
contains: `### normal-map-case
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
envMappings | The mapping of environment variables to secret. | map[string]KeySecret(#keysecret) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
envMappings | The mapping of environment variables to secret. | map[string]KeySecret(#keysecret) | true | |
#### KeySecret
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
key | | string | false |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
key | | string | false | |
secret | | string | true |`,
},
"or-case-with-type": {
@@ -542,24 +542,24 @@ func TestExtractParameter(t *testing.T) {
}`,
contains: `### or-case-with-type
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
orValue | | [KeyConfig](#keyconfig) or [KeySecret](#keysecret) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
orValue | | [KeyConfig](#keyconfig) or [KeySecret](#keysecret) | true | |
#### KeyConfig
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
key | | string | true |
config | | string | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
key | | string | true | |
config | | string | true | |
#### KeySecret
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
key | | string | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
key | | string | true | |
secret | | string | true | `,
},
"or-type-with-const-str": {
@@ -568,8 +568,8 @@ func TestExtractParameter(t *testing.T) {
}`,
contains: `### or-type-with-const-str
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
type | | "configMap" or "secret" or "emptyDir" or "ephemeral" | false | configMap`,
},
"or-type-with-const-and-string": {
@@ -578,8 +578,8 @@ func TestExtractParameter(t *testing.T) {
}`,
contains: `### or-type-with-const-and-string
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
type | | string | false | configMap`,
},
"var-or-with-struct-var": {
@@ -599,26 +599,41 @@ func TestExtractParameter(t *testing.T) {
}`,
contains: `### var-or-with-struct-var
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
orValue | | [KeyConfig](#keyconfig) or [KeySecret](#keysecret) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
orValue | | [KeyConfig](#keyconfig) or [KeySecret](#keysecret) | true | |
#### KeyConfig
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
key | | string | true |
config | | string | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
key | | string | true | |
config | | string | true | |
#### KeySecret
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
key | | string | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
key | | string | true | |
secret | | string | true | `,
},
"immutable-field": {
cueTemplate: `parameter: {
// +usage=The image to use
// +immutable
image: string
// +usage=The replica count
replicas: *1 | int
}`,
contains: `### immutable-field
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
image | The image to use. | string | true | | true
replicas | The replica count. | int | false | 1 | `,
},
}
ref := &MarkdownReference{}
@@ -640,89 +655,89 @@ func TestExtractParameterFromFiles(t *testing.T) {
path: "testdata/parameter/env.cue",
contains: `### env
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
| | [PatchParams](#patchparams) or [type-option-2](#type-option-2) | false |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
| | [PatchParams](#patchparams) or [type-option-2](#type-option-2) | false | |
#### PatchParams
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty
replace | Specify if replacing the whole environment settings for the container. | bool | false | false
env | Specify the environment variables to merge, if key already existing, override its value. | map[string]string | true |
unset | Specify which existing environment variables to unset. | list | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty |
replace | Specify if replacing the whole environment settings for the container. | bool | false | false |
env | Specify the environment variables to merge, if key already existing, override its value. | map[string]string | true | |
unset | Specify which existing environment variables to unset. | list | true | |
#### type-option-2
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
containers | Specify the environment variables for multiple containers. | [[]containers](#containers) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
containers | Specify the environment variables for multiple containers. | [[]containers](#containers) | true | |
##### containers
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty
replace | Specify if replacing the whole environment settings for the container. | bool | false | false
env | Specify the environment variables to merge, if key already existing, override its value. | map[string]string | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty |
replace | Specify if replacing the whole environment settings for the container. | bool | false | false |
env | Specify the environment variables to merge, if key already existing, override its value. | map[string]string | true | |
unset | Specify which existing environment variables to unset. | list | true |`,
},
"command": {
path: "testdata/parameter/command.cue",
contains: `### command
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
| | [PatchParams](#patchparams) or [type-option-2](#type-option-2) | false |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
| | [PatchParams](#patchparams) or [type-option-2](#type-option-2) | false | |
#### PatchParams
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty
command | Specify the command to use in the target container, if not set, it will not be changed. | null | true |
args | Specify the args to use in the target container, if set, it will override existing args. | null | true |
addArgs | Specify the args to add in the target container, existing args will be kept, cannot be used with args. | null | true |
delArgs | Specify the existing args to delete in the target container, cannot be used with args. | null | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty |
command | Specify the command to use in the target container, if not set, it will not be changed. | null | true | |
args | Specify the args to use in the target container, if set, it will override existing args. | null | true | |
addArgs | Specify the args to add in the target container, existing args will be kept, cannot be used with args. | null | true | |
delArgs | Specify the existing args to delete in the target container, cannot be used with args. | null | true | |
#### type-option-2
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
containers | Specify the commands for multiple containers. | [[]containers](#containers) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
containers | Specify the commands for multiple containers. | [[]containers](#containers) | true | |
##### containers
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty
command | Specify the command to use in the target container, if not set, it will not be changed. | null | true |
args | Specify the args to use in the target container, if set, it will override existing args. | null | true |
addArgs | Specify the args to add in the target container, existing args will be kept, cannot be used with args. | null | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty |
command | Specify the command to use in the target container, if not set, it will not be changed. | null | true | |
args | Specify the args to use in the target container, if set, it will override existing args. | null | true | |
addArgs | Specify the args to add in the target container, existing args will be kept, cannot be used with args. | null | true | |
delArgs | Specify the existing args to delete in the target container, cannot be used with args. | null | true |`,
},
"condition": {
path: "testdata/parameter/condition.cue",
contains: `### condition
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
volumes | | [[]volumes](#volumes) | true |
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
volumes | | [[]volumes](#volumes) | true | |
#### volumes
Name | Description | Type | Required | Default
---- | ----------- | ---- | -------- | -------
name | | string | true |
type | | "configMap" or "secret" or "emptyDir" or "ephemeral" | false | configMap
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
name | | string | true | |
type | | "configMap" or "secret" or "emptyDir" or "ephemeral" | false | configMap |
defaultMode | only works when type equals configmap. | int | false | 420 `,
},
}

View File

@@ -0,0 +1,20 @@
---
title: Trait1
---
## Description
.
### Apply To Component Types
Component based on the following kinds of resources:
## Specification
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
replicas | | int | true | |

View File

@@ -0,0 +1,14 @@
---
title: Workload1
---
## Description
.
## Specification
Name | Description | Type | Required | Default | Immutable
---- | ----------- | ---- | -------- | ------- | ---------
image | Which image would you like to use for your service. | string | true | |

View File

@@ -0,0 +1,33 @@
---
title: Workload2
---
## 描述
## 参数说明
名称 | 描述 | 类型 | 是否必须 | 默认值 | 不可变
------ | ------ | ------ | ------------ | --------- | ---------
acl | OSS bucket ACL, supported 'private', 'public-read', 'public-read-write'。 | string | false | |
bucket | OSS bucket name。 | string | false | |
writeConnectionSecretToRef | The secret which the cloud resource connection will be written to。 | [writeConnectionSecretToRef](#writeConnectionSecretToRef) | false | |
#### writeConnectionSecretToRef
名称 | 描述 | 类型 | 是否必须 | 默认值 | 不可变
------ | ------ | ------ | ------------ | --------- | ---------
name | The secret name which the cloud resource connection will be written to。 | string | true | |
namespace | The secret namespace which the cloud resource connection will be written to。 | string | false | |
### 输出
WriteConnectionSecretToRefIntroduction
名称 | 描述
------------ | -------------
BUCKET_NAME |