Repository: oam-dev/kubevela (go)

Issue:
we should add some `keyword` such as `//+ignore` to let the user can't see the parameter and only be used by system.
we should add some `keyword` such as `//+ignore` to let the user can't see the parameter and only be used by system.

_Originally posted by @wonderflow in https://github.com/oam-dev/kubevela/pull/1748#r644563466_

Pull request:
Add ignore feature for cue parameter
When there are some cue parameters described in system level which we don't want to exposed to end user, we can use  //+ignore  to cue parameter, and through vela show we can see the corresponding field disappear.

cue template:
![image](https://user-images.githubusercontent.com/35907099/120622256-3a290180-c491-11eb-95db-57fc517c9fcc.png)

vela show result:
![image](https://user-images.githubusercontent.com/35907099/120622102-182f7f00-c491-11eb-86b0-d443715732eb.png)
fix #1754 


Patch:
diff --git a/apis/types/capability.go b/apis/types/capability.go
index e0fd1c18..55093073 100644
--- a/apis/types/capability.go
+++ b/apis/types/capability.go
@@ -134,6 +134,7 @@ type Parameter struct {
 	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"`
diff --git a/charts/vela-core/templates/defwithtemplate/webservice.yaml b/charts/vela-core/templates/defwithtemplate/webservice.yaml
index dd1dd73e..a1d38e3e 100644
--- a/charts/vela-core/templates/defwithtemplate/webservice.yaml
+++ b/charts/vela-core/templates/defwithtemplate/webservice.yaml
@@ -136,7 +136,8 @@ spec:
         	// +short=p
         	port: *80 | int
         
-        	// If addRevisionLabel is true, the appRevision label will be added to the underlying pods
+        	// +ignore
+        	// +usage=If addRevisionLabel is true, the appRevision label will be added to the underlying pods
         	addRevisionLabel: *false | bool
         
         	// +usage=Commands to run in the container
diff --git a/pkg/cue/convert.go b/pkg/cue/convert.go
index 4236c087..5e8d5d82 100644
--- a/pkg/cue/convert.go
+++ b/pkg/cue/convert.go
@@ -79,7 +79,7 @@ func GetParameters(templateStr string) ([]types.Parameter, error) {
 		if param.Default == nil {
 			param.Default = getDefaultByKind(param.Type)
 		}
-		param.Short, param.Usage, param.Alias = RetrieveComments(val)
+		param.Short, param.Usage, param.Alias, param.Ignore = RetrieveComments(val)
 
 		params = append(params, param)
 	}
@@ -139,11 +139,14 @@ const (
 	ShortPrefix = "+short="
 	// AliasPrefix is an alias of the name of a parameter element, in order to making it more friendly to Cli users
 	AliasPrefix = "+alias="
+	// IgnorePrefix defines parameter in system level which we don't want our end user to see for KubeVela CLI
+	IgnorePrefix = "+ignore"
 )
 
-// RetrieveComments will retrieve Usage, Short and Alias from CUE Value
-func RetrieveComments(value cue.Value) (string, string, string) {
+// 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
 	docs := value.Doc()
 	for _, doc := range docs {
 		lines := strings.Split(doc.Text(), "\n")
@@ -154,6 +157,9 @@ func RetrieveComments(value cue.Value) (string, string, string) {
 			if strings.HasPrefix(line, ShortPrefix) {
 				short = strings.TrimPrefix(line, ShortPrefix)
 			}
+			if strings.HasPrefix(line, IgnorePrefix) {
+				ignore = true
+			}
 			if strings.HasPrefix(line, UsagePrefix) {
 				usage = strings.TrimPrefix(line, UsagePrefix)
 			}
@@ -162,5 +168,5 @@ func RetrieveComments(value cue.Value) (string, string, string) {
 			}
 		}
 	}
-	return short, usage, alias
+	return short, usage, alias, ignore
 }
diff --git a/references/plugins/references.go b/references/plugins/references.go
index 9cd9e4f7..2442af61 100644
--- a/references/plugins/references.go
+++ b/references/plugins/references.go
@@ -469,8 +469,10 @@ func (ref *MarkdownReference) prepareParameter(tableName string, parameterList [
 	switch category {
 	case types.CUECategory:
 		for _, p := range parameterList {
-			printableDefaultValue := ref.getCUEPrintableDefaultValue(p.Default)
-			refContent += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, p.Usage, p.PrintableType, p.Required, printableDefaultValue)
+			if !p.Ignore {
+				printableDefaultValue := ref.getCUEPrintableDefaultValue(p.Default)
+				refContent += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, p.Usage, p.PrintableType, p.Required, printableDefaultValue)
+			}
 		}
 	case types.HelmCategory:
 		for _, p := range parameterList {
@@ -500,8 +502,10 @@ func (ref *ParseReference) prepareParameter(tableName string, parameterList []Re
 	switch category {
 	case types.CUECategory:
 		for _, p := range parameterList {
-			printableDefaultValue := ref.getCUEPrintableDefaultValue(p.Default)
-			table.Append([]string{p.Name, p.Usage, p.PrintableType, strconv.FormatBool(p.Required), printableDefaultValue})
+			if !p.Ignore {
+				printableDefaultValue := ref.getCUEPrintableDefaultValue(p.Default)
+				table.Append([]string{p.Name, p.Usage, p.PrintableType, strconv.FormatBool(p.Required), printableDefaultValue})
+			}
 		}
 	case types.HelmCategory:
 		for _, p := range parameterList {
@@ -558,7 +562,7 @@ func (ref *ParseReference) parseParameters(paraValue cue.Value, paramKey string,
 			if def, ok := val.Default(); ok && def.IsConcrete() {
 				param.Default = velacue.GetDefault(def)
 			}
-			param.Short, param.Usage, param.Alias = velacue.RetrieveComments(val)
+			param.Short, param.Usage, param.Alias, param.Ignore = velacue.RetrieveComments(val)
 			param.Type = val.IncompleteKind()
 			switch val.IncompleteKind() {
 			case cue.StructKind:
diff --git a/vela-templates/internal/cue/webservice.cue b/vela-templates/internal/cue/webservice.cue
index 5c09dc08..3e3231a0 100644
--- a/vela-templates/internal/cue/webservice.cue
+++ b/vela-templates/internal/cue/webservice.cue
@@ -120,7 +120,8 @@ parameter: {
 	// +short=p
 	port: *80 | int
 
-	// If addRevisionLabel is true, the appRevision label will be added to the underlying pods
+	// +ignore
+	// +usage=If addRevisionLabel is true, the appRevision label will be added to the underlying pods
 	addRevisionLabel: *false | bool
 
 	// +usage=Commands to run in the container


Test patch:
diff --git a/e2e/application/application_test.go b/e2e/application/application_test.go
index 279674a2..be2faa93 100644
--- a/e2e/application/application_test.go
+++ b/e2e/application/application_test.go
@@ -157,7 +157,7 @@ var ApplicationInitIntercativeCliContext = func(context string, appName string,
 						a: "mysvc",
 					},
 					{
-						q: "what would you configure for parameter 'addRevisionLabel' (optional, default is false):",
+						q: "If addRevisionLabel is true, the appRevision label will be added to the underlying pods (optional, default is false):",
 						a: "N",
 					},
 					{
diff --git a/e2e/plugin/plugin_suit_test.go b/e2e/plugin/plugin_suit_test.go
index 74ebe9db..cb054328 100644
--- a/e2e/plugin/plugin_suit_test.go
+++ b/e2e/plugin/plugin_suit_test.go
@@ -46,6 +46,7 @@ var testShowTdDef v1beta1.TraitDefinition
 var testCdDef v1beta1.ComponentDefinition
 var testCdDefWithHelm v1beta1.ComponentDefinition
 var testCdDefWithKube v1beta1.ComponentDefinition
+var testCdWithDeepCue v1beta1.ComponentDefinition
 var testTdDef v1beta1.TraitDefinition
 var testTdDefWithKube v1beta1.TraitDefinition
 
@@ -88,6 +89,10 @@ var _ = BeforeSuite(func(done Done) {
 	err = k8sClient.Create(ctx, &testCdDefWithKube)
 	Expect(err).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
 
+	Expect(yaml.Unmarshal([]byte(componentWithDeepCue), &testCdWithDeepCue)).Should(BeNil())
+	err = k8sClient.Create(ctx, &testCdWithDeepCue)
+	Expect(err).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
+
 	Expect(yaml.Unmarshal([]byte(traitDef), &testTdDef)).Should(BeNil())
 	err = k8sClient.Create(ctx, &testTdDef)
 	Expect(err).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
@@ -122,6 +127,7 @@ var _ = AfterSuite(func() {
 	Expect(k8sClient.Delete(ctx, &testCdDef)).Should(BeNil())
 	Expect(k8sClient.Delete(ctx, &testCdDefWithHelm)).Should(BeNil())
 	Expect(k8sClient.Delete(ctx, &testCdDefWithKube)).Should(BeNil())
+	Expect(k8sClient.Delete(ctx, &testCdWithDeepCue)).Should(BeNil())
 	Expect(k8sClient.Delete(ctx, &testTdDef)).Should(BeNil())
 	Expect(k8sClient.Delete(ctx, &testTdDefWithKube)).Should(BeNil())
 	Expect(k8sClient.Delete(ctx, &testShowCdDef)).Should(BeNil())
diff --git a/e2e/plugin/plugin_test.go b/e2e/plugin/plugin_test.go
index ef680544..abe3c6d4 100644
--- a/e2e/plugin/plugin_test.go
+++ b/e2e/plugin/plugin_test.go
@@ -146,6 +146,19 @@ var _ = Describe("Test Kubectl Plugin", func() {
 			Expect(err).NotTo(HaveOccurred())
 			Expect(output).Should(ContainSubstring("map[string]string"))
 		})
+		It("Test show webservice def with cue ignore annotation ", func() {
+			tdName := "webservice"
+			output, err := e2e.Exec(fmt.Sprintf("kubectl-vela show %s", tdName))
+			Expect(err).NotTo(HaveOccurred())
+			Expect(output).ShouldNot(ContainSubstring("addRevisionLabel"))
+		})
+		It("Test show webservice def with cue ignore annotation ", func() {
+			tdName := "mywebservice"
+			output, err := e2e.Exec(fmt.Sprintf("kubectl-vela show %s", tdName))
+			Expect(err).NotTo(HaveOccurred())
+			Expect(output).ShouldNot(ContainSubstring("addRevisionLabel"))
+			Expect(output).ShouldNot(ContainSubstring("mySecretKey"))
+		})
 	})
 
 	Context("Test kubectl vela comp discover", func() {
@@ -603,6 +616,85 @@ spec:
           description: "target port num for service provider."
 `
 
+var componentWithDeepCue = `
+# Test for deeper parameter in cue Template
+apiVersion: core.oam.dev/v1beta1
+kind: ComponentDefinition
+metadata:
+ name: mywebservice
+ namespace: default
+ annotations:
+   definition.oam.dev/description: "Describes long-running, scalable, containerized services that have a stable network endpoint to receive external network traffic from customers."
+spec:
+ workload:
+   definition:
+     apiVersion: apps/v1
+     kind: Deployment
+ schematic:
+   cue:
+     template: |
+       output: {
+       	apiVersion: "apps/v1"
+       	kind:       "Deployment"
+       	spec: {
+       		selector: matchLabels: {
+       			"app.oam.dev/component": context.name
+       			if parameter.addRevisionLabel {
+       				"app.oam.dev/appRevision": context.appRevision
+       			}
+       		}
+
+       		template: {
+       			metadata: labels: {
+       				"app.oam.dev/component": context.name
+       				if parameter.addRevisionLabel {
+       					"app.oam.dev/appRevision": context.appRevision
+       				}
+       			}
+
+       			spec: {
+       				containers: [{
+       					name:  context.name
+       					image: parameter.image
+
+       					if parameter["env"] != _|_ {
+       						env: parameter.env
+       					}
+       				}]
+       		    }
+       	    }
+           }
+       }
+       parameter: {
+       	// +usage=Which image would you like to use for your service
+       	// +short=i
+       	image: string
+
+       	// +ignore
+       	// +usage=If addRevisionLabel is true, the appRevision label will be added to the underlying pods
+       	addRevisionLabel: *false | bool
+
+       	// +usage=Define arguments by using environment variables
+       	env?: [...{
+       		// +usage=Environment variable name
+       		name: string
+       		// +usage=The value of the environment variable
+       		value?: string
+       		// +usage=Specifies a source the value of this var should come from
+       		valueFrom?: {
+       			// +usage=Selects a key of a secret in the pod's namespace
+       			secretKeyRef: {
+       				// +usage=The name of the secret in the pod's namespace to select from
+       				name: string
+                       // +ignore
+       				// +usage=The key of the secret to select from. Must be a valid secret key
+       				mySecretKey: string
+       			}
+       		}
+       	}]
+       }
+`
+
 var dryRunResult = `---
 # Application(test-vela-app) -- Comopnent(express-server) 
 ---
diff --git a/pkg/cue/convert_test.go b/pkg/cue/convert_test.go
index 9a10b5d2..4634a00f 100644
--- a/pkg/cue/convert_test.go
+++ b/pkg/cue/convert_test.go
@@ -65,4 +65,17 @@ func TestGetParameter(t *testing.T) {
 	assert.NoError(t, err)
 	var exp []types.Parameter
 	assert.Equal(t, exp, params)
+
+	data, _ = ioutil.ReadFile("testdata/workloads/webservice.cue") // test cue parameter with "// +ignore" annotation
+	params, err = GetParameters(string(data))                      // Only test for func RetrieveComments
+	assert.NoError(t, err)
+	var flag bool
+	for _, para := range params {
+		if para.Name == "addRevisionLabel" {
+			flag = true
+			assert.Equal(t, para.Usage, "If addRevisionLabel is true, the appRevision label will be added to the underlying pods")
+			assert.Equal(t, para.Ignore, true)
+		}
+	}
+	assert.Equal(t, flag, true)
 }
diff --git a/pkg/cue/testdata/workloads/webservice.cue b/pkg/cue/testdata/workloads/webservice.cue
new file mode 100644
index 00000000..b0d9b0af
--- /dev/null
+++ b/pkg/cue/testdata/workloads/webservice.cue
@@ -0,0 +1,56 @@
+output: {
+	apiVersion: "apps/v1"
+	kind:       "Deployment"
+	spec: {
+		selector: matchLabels: {
+			"app.oam.dev/component": context.name
+			if parameter.addRevisionLabel {
+				"app.oam.dev/appRevision": context.appRevision
+			}
+		}
+		template: {
+			metadata: labels: {
+				"app.oam.dev/component": context.name
+				if parameter.addRevisionLabel {
+					"app.oam.dev/appRevision": context.appRevision
+				}
+			}
+			spec: {
+				containers: [{
+					name:  context.name
+					image: parameter.image
+					if parameter["env"] != _|_ {
+						env: parameter.env
+					}
+				}]
+		  }
+		}
+	}
+}
+parameter: {
+	// +usage=Which image would you like to use for your service
+	// +short=i
+	image: string
+	// +usage=Define arguments by using environment variables
+	env?: [...{
+		// +usage=Environment variable name
+		name: string
+		// +usage=The value of the environment variable
+		value?: string
+		// +usage=Specifies a source the value of this var should come from
+		valueFrom?: {
+			// +usage=Selects a key of a secret in the pod's namespace
+			secretKeyRef: {
+				// +usage=The name of the secret in the pod's namespace to select from
+				name: string
+				// +ignore
+				// +usage=The key of the secret to select from. Must be a valid secret key
+				secretKey: string
+			}
+		}
+	}]
+  // +ignore
+	// +usage=If addRevisionLabel is true, the appRevision label will be added to the underlying pods
+	addRevisionLabel: *false | bool
+}
+