Repository: kubevela/kubevela

Issue:
[Feature] Deliver debug info in addon enable process
**Is your feature request related to a problem? Please describe.**
<!--
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-->

Now, the addon enable process can fail and there are no more debug info. 

**Describe the solution you'd like**
<!--
A clear and concise description of what you want to happen.
-->

Given the the most addons contain at lease one `helm` component and it may be the most errors happen, we can add trace for helmrelease/helmchart/helmrepo resources. 

cc @wonderflow @BinaryHB0916 

**Describe alternatives you've considered**
<!--
A clear and concise description of any alternative solutions or features you've considered.
-->

**Additional context**
<!--
Add any other context or screenshots about the feature request here.
-->


Discussion:
@chivalryq: In addon enable process, we should deliver Application status infomation. The info are gathered from components' healthCheck.
Here's an TODO: #2372 @briankane: This issue has been inactive for over 2 years and is scheduled for closure as part of our backlog maintenance.

  **If this issue is still relevant:**
  - Please comment below to keep it open
  - Provide updated context if the original description is outdated

  **Timeline:** If there's no activity by **Friday, October 24th**, this issue will be automatically closed.

  **Note:** Issues can always be reopened if they become relevant again. We encourage the community to reopen and reprioritize any incorrectly 
  closed issues.@briankane: This issue has been closed following the stale issue notice. 

If this issue is still relevant and should remain open, please:
1. Reopen the issue
2. Remove the 'stale' label
3. Provide an update on the current status or importance

Thank you for your understanding and contribution to KubeVela!

Solution patch:
diff --git a/charts/vela-core/templates/addons/fluxcd.yaml b/charts/vela-core/templates/addons/fluxcd.yaml
index a03bd67e..ed1737aa 100644
--- a/charts/vela-core/templates/addons/fluxcd.yaml
+++ b/charts/vela-core/templates/addons/fluxcd.yaml
@@ -5818,6 +5818,20 @@ data:
                   +usage=The release name\n\treleaseName?: string\n\t// +usage=Chart values\n\tvalues?:
                   #nestedmap\n}\n\n#nestedmap: {\n\t...\n}\n"
             status:
+              customStatus: "repoMessage:    string\nreleaseMessage: string\nif context.output.status
+                == _|_ {\n\trepoMessage:    \"Fetching repository\"\n\treleaseMessage:
+                \"Wating repository ready\"\n}\nif context.output.status != _|_ {\n\trepoStatus:
+                context.output.status\n\tif repoStatus.conditions[0][\"type\"] != \"Ready\"
+                {\n\t\trepoMessage: \"Fetch repository fail\"\n\t}\n\tif repoStatus.conditions[0][\"type\"]
+                == \"Ready\" {\n\t\trepoMessage: \"Fetch repository successfully\"\n\t}\n\n\tif
+                context.outputs.release.status == _|_ {\n\t\treleaseMessage: \"Creating
+                helm release\"\n\t}\n\tif context.outputs.release.status != _|_ {\n\t\tif
+                context.outputs.release.status.conditions[0][\"message\"] == \"Release
+                reconciliation succeeded\" {\n\t\t\treleaseMessage: \"Create helm release
+                successfully\"\n\t\t}\n\t\tif context.outputs.release.status.conditions[0][\"message\"]
+                != \"Release reconciliation succeeded\" {\n\t\t\treleaseMessage: \"Create
+                helm release fail, message: \" + context.outputs.release.status.conditions[0][\"message\"]\n\t\t}\n\t}\n\n}\nmessage:
+                repoMessage + \", \" + releaseMessage"
               healthPolicy: 'isHealth: len(context.outputs.release.status.conditions)
                 != 0 && context.outputs.release.status.conditions[0]["status"]=="True"'
             workload:
diff --git a/docs/examples/workflow/webhook-notification/app.yaml b/docs/examples/workflow/webhook-notification/app.yaml
index 874c8965..8d1fb8b7 100644
--- a/docs/examples/workflow/webhook-notification/app.yaml
+++ b/docs/examples/workflow/webhook-notification/app.yaml
@@ -22,13 +22,19 @@ spec:
         type: webhook-notification
         properties:
           dingding:
-            url: ding url
+            # directly specify the webhook url
+            url:
+              address: <dingding-url>
             message:
               msgtype: text
               text:
                 content: Hello KubeVela
           slack:
-            url: slack url
+            url:
+              # use url in secret
+              formSecret:
+                name: <secret-name>
+                key: <secret-key>
             message:
               text: Hello KubeVela
       - name: first-server
diff --git a/references/cli/workflow.go b/references/cli/workflow.go
index 87fc62a3..769ee006 100644
--- a/references/cli/workflow.go
+++ b/references/cli/workflow.go
@@ -51,7 +51,7 @@ func NewWorkflowCommand(c common.Args, ioStreams cmdutil.IOStreams) *cobra.Comma
 
 // NewWorkflowSuspendCommand create workflow suspend command
 func NewWorkflowSuspendCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
-	return &cobra.Command{
+	cmd := &cobra.Command{
 		Use:     "suspend",
 		Short:   "Suspend an application workflow",
 		Long:    "Suspend an application workflow in cluster",
@@ -60,11 +60,18 @@ func NewWorkflowSuspendCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
 			if len(args) < 1 {
 				return fmt.Errorf("must specify application name")
 			}
-			env, err := GetFlagEnvOrCurrent(cmd, c)
+			namespace, err := cmd.Flags().GetString(FlagNamespace)
 			if err != nil {
 				return err
 			}
-			app, err := appfile.LoadApplication(env.Namespace, args[0], c)
+			if namespace == "" {
+				env, err := GetFlagEnvOrCurrent(cmd, c)
+				if err != nil {
+					return err
+				}
+				namespace = env.Namespace
+			}
+			app, err := appfile.LoadApplication(namespace, args[0], c)
 			if err != nil {
 				return err
 			}
@@ -86,11 +93,13 @@ func NewWorkflowSuspendCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
 			return nil
 		},
 	}
+	cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to get. If empty, uses namespace in env.")
+	return cmd
 }
 
 // NewWorkflowResumeCommand create workflow resume command
 func NewWorkflowResumeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
-	return &cobra.Command{
+	cmd := &cobra.Command{
 		Use:     "resume",
 		Short:   "Resume a suspend application workflow",
 		Long:    "Resume a suspend application workflow in cluster",
@@ -99,11 +108,18 @@ func NewWorkflowResumeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.
 			if len(args) < 1 {
 				return fmt.Errorf("must specify application name")
 			}
-			env, err := GetFlagEnvOrCurrent(cmd, c)
+			namespace, err := cmd.Flags().GetString(FlagNamespace)
 			if err != nil {
 				return err
 			}
-			app, err := appfile.LoadApplication(env.Namespace, args[0], c)
+			if namespace == "" {
+				env, err := GetFlagEnvOrCurrent(cmd, c)
+				if err != nil {
+					return err
+				}
+				namespace = env.Namespace
+			}
+			app, err := appfile.LoadApplication(namespace, args[0], c)
 			if err != nil {
 				return err
 			}
@@ -135,11 +151,13 @@ func NewWorkflowResumeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.
 			return nil
 		},
 	}
+	cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to get. If empty, uses namespace in env.")
+	return cmd
 }
 
 // NewWorkflowTerminateCommand create workflow terminate command
 func NewWorkflowTerminateCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
-	return &cobra.Command{
+	cmd := &cobra.Command{
 		Use:     "terminate",
 		Short:   "Terminate an application workflow",
 		Long:    "Terminate an application workflow in cluster",
@@ -148,11 +166,18 @@ func NewWorkflowTerminateCommand(c common.Args, ioStream cmdutil.IOStreams) *cob
 			if len(args) < 1 {
 				return fmt.Errorf("must specify application name")
 			}
-			env, err := GetFlagEnvOrCurrent(cmd, c)
+			namespace, err := cmd.Flags().GetString(FlagNamespace)
 			if err != nil {
 				return err
 			}
-			app, err := appfile.LoadApplication(env.Namespace, args[0], c)
+			if namespace == "" {
+				env, err := GetFlagEnvOrCurrent(cmd, c)
+				if err != nil {
+					return err
+				}
+				namespace = env.Namespace
+			}
+			app, err := appfile.LoadApplication(namespace, args[0], c)
 			if err != nil {
 				return err
 			}
@@ -174,11 +199,13 @@ func NewWorkflowTerminateCommand(c common.Args, ioStream cmdutil.IOStreams) *cob
 			return nil
 		},
 	}
+	cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to get. If empty, uses namespace in env.")
+	return cmd
 }
 
 // NewWorkflowRestartCommand create workflow restart command
 func NewWorkflowRestartCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.Command {
-	return &cobra.Command{
+	cmd := &cobra.Command{
 		Use:     "restart",
 		Short:   "Restart an application workflow",
 		Long:    "Restart an application workflow in cluster",
@@ -187,11 +214,18 @@ func NewWorkflowRestartCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
 			if len(args) < 1 {
 				return fmt.Errorf("must specify application name")
 			}
-			env, err := GetFlagEnvOrCurrent(cmd, c)
+			namespace, err := cmd.Flags().GetString(FlagNamespace)
 			if err != nil {
 				return err
 			}
-			app, err := appfile.LoadApplication(env.Namespace, args[0], c)
+			if namespace == "" {
+				env, err := GetFlagEnvOrCurrent(cmd, c)
+				if err != nil {
+					return err
+				}
+				namespace = env.Namespace
+			}
+			app, err := appfile.LoadApplication(namespace, args[0], c)
 			if err != nil {
 				return err
 			}
@@ -213,6 +247,8 @@ func NewWorkflowRestartCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
 			return nil
 		},
 	}
+	cmd.Flags().StringP(FlagNamespace, "n", "", "Specify which namespace to get. If empty, uses namespace in env.")
+	return cmd
 }
 
 func suspendWorkflow(kubecli client.Client, app *v1beta1.Application) error {
diff --git a/vela-templates/addons/auto-gen/fluxcd.yaml b/vela-templates/addons/auto-gen/fluxcd.yaml
index 849d0010..73acbe3d 100644
--- a/vela-templates/addons/auto-gen/fluxcd.yaml
+++ b/vela-templates/addons/auto-gen/fluxcd.yaml
@@ -5815,6 +5815,20 @@ spec:
               +usage=The release name\n\treleaseName?: string\n\t// +usage=Chart values\n\tvalues?:
               #nestedmap\n}\n\n#nestedmap: {\n\t...\n}\n"
         status:
+          customStatus: "repoMessage:    string\nreleaseMessage: string\nif context.output.status
+            == _|_ {\n\trepoMessage:    \"Fetching repository\"\n\treleaseMessage:
+            \"Wating repository ready\"\n}\nif context.output.status != _|_ {\n\trepoStatus:
+            context.output.status\n\tif repoStatus.conditions[0][\"type\"] != \"Ready\"
+            {\n\t\trepoMessage: \"Fetch repository fail\"\n\t}\n\tif repoStatus.conditions[0][\"type\"]
+            == \"Ready\" {\n\t\trepoMessage: \"Fetch repository successfully\"\n\t}\n\n\tif
+            context.outputs.release.status == _|_ {\n\t\treleaseMessage: \"Creating
+            helm release\"\n\t}\n\tif context.outputs.release.status != _|_ {\n\t\tif
+            context.outputs.release.status.conditions[0][\"message\"] == \"Release
+            reconciliation succeeded\" {\n\t\t\treleaseMessage: \"Create helm release
+            successfully\"\n\t\t}\n\t\tif context.outputs.release.status.conditions[0][\"message\"]
+            != \"Release reconciliation succeeded\" {\n\t\t\treleaseMessage: \"Create
+            helm release fail, message: \" + context.outputs.release.status.conditions[0][\"message\"]\n\t\t}\n\t}\n\n}\nmessage:
+            repoMessage + \", \" + releaseMessage"
           healthPolicy: 'isHealth: len(context.outputs.release.status.conditions)
             != 0 && context.outputs.release.status.conditions[0]["status"]=="True"'
         workload:
diff --git a/vela-templates/addons/fluxcd/definitions/helm-release.yaml b/vela-templates/addons/fluxcd/definitions/helm-release.yaml
index 24d28dc0..9f0a4e2e 100644
--- a/vela-templates/addons/fluxcd/definitions/helm-release.yaml
+++ b/vela-templates/addons/fluxcd/definitions/helm-release.yaml
@@ -146,4 +146,34 @@ spec:
         }
   status:
     # helmRelease's `ready` condition must be the first one
-    healthPolicy: 'isHealth: len(context.outputs.release.status.conditions) != 0 && context.outputs.release.status.conditions[0]["status"]=="True"'
\ No newline at end of file
+    healthPolicy: 'isHealth: len(context.outputs.release.status.conditions) != 0 && context.outputs.release.status.conditions[0]["status"]=="True"'
+    customStatus: |-
+      repoMessage:    string
+      releaseMessage: string
+      if context.output.status == _|_ {
+      	repoMessage:    "Fetching repository"
+      	releaseMessage: "Wating repository ready"
+      }
+      if context.output.status != _|_ {
+      	repoStatus: context.output.status
+      	if repoStatus.conditions[0]["type"] != "Ready" {
+      		repoMessage: "Fetch repository fail"
+      	}
+      	if repoStatus.conditions[0]["type"] == "Ready" {
+      		repoMessage: "Fetch repository successfully"
+      	}
+
+      	if context.outputs.release.status == _|_ {
+      		releaseMessage: "Creating helm release"
+      	}
+      	if context.outputs.release.status != _|_ {
+      		if context.outputs.release.status.conditions[0]["message"] == "Release reconciliation succeeded" {
+      			releaseMessage: "Create helm release successfully"
+      		}
+      		if context.outputs.release.status.conditions[0]["message"] != "Release reconciliation succeeded" {
+      			releaseMessage: "Create helm release fail, message: " + context.outputs.release.status.conditions[0]["message"]
+      		}
+      	}
+
+      }
+      message: repoMessage + ", " + releaseMessage



Test patch:
diff --git a/references/cli/workflow_test.go b/references/cli/workflow_test.go
index c69c47bf..4d8edd28 100644
--- a/references/cli/workflow_test.go
+++ b/references/cli/workflow_test.go
@@ -23,6 +23,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/require"
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/types"
@@ -83,7 +84,7 @@ func TestWorkflowSuspend(t *testing.T) {
 			app: &v1beta1.Application{
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "workflow",
-					Namespace: "default",
+					Namespace: "test",
 				},
 				Spec: workflowSpec,
 				Status: common.AppStatus{
@@ -105,7 +106,17 @@ func TestWorkflowSuspend(t *testing.T) {
 				err := c.Client.Create(ctx, tc.app)
 				r.NoError(err)
 
-				cmd.SetArgs([]string{tc.app.Name})
+				if tc.app.Namespace != corev1.NamespaceDefault {
+					err := c.Client.Create(ctx, &corev1.Namespace{
+						ObjectMeta: metav1.ObjectMeta{
+							Name: tc.app.Namespace,
+						},
+					})
+					r.NoError(err)
+					cmd.SetArgs([]string{tc.app.Name, "-n", tc.app.Namespace})
+				} else {
+					cmd.SetArgs([]string{tc.app.Name})
+				}
 			}
 			err := cmd.Execute()
 			if tc.expectedErr != nil {
@@ -190,7 +201,7 @@ func TestWorkflowResume(t *testing.T) {
 			app: &v1beta1.Application{
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "workflow",
-					Namespace: "default",
+					Namespace: "test",
 				},
 				Spec: workflowSpec,
 				Status: common.AppStatus{
@@ -212,7 +223,17 @@ func TestWorkflowResume(t *testing.T) {
 				err := c.Client.Create(ctx, tc.app)
 				r.NoError(err)
 
-				cmd.SetArgs([]string{tc.app.Name})
+				if tc.app.Namespace != corev1.NamespaceDefault {
+					err := c.Client.Create(ctx, &corev1.Namespace{
+						ObjectMeta: metav1.ObjectMeta{
+							Name: tc.app.Namespace,
+						},
+					})
+					r.NoError(err)
+					cmd.SetArgs([]string{tc.app.Name, "-n", tc.app.Namespace})
+				} else {
+					cmd.SetArgs([]string{tc.app.Name})
+				}
 			}
 			err := cmd.Execute()
 			if tc.expectedErr != nil {
@@ -268,7 +289,7 @@ func TestWorkflowTerminate(t *testing.T) {
 			app: &v1beta1.Application{
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "workflow",
-					Namespace: "default",
+					Namespace: "test",
 				},
 				Spec: workflowSpec,
 				Status: common.AppStatus{
@@ -290,7 +311,17 @@ func TestWorkflowTerminate(t *testing.T) {
 				err := c.Client.Create(ctx, tc.app)
 				r.NoError(err)
 
-				cmd.SetArgs([]string{tc.app.Name})
+				if tc.app.Namespace != corev1.NamespaceDefault {
+					err := c.Client.Create(ctx, &corev1.Namespace{
+						ObjectMeta: metav1.ObjectMeta{
+							Name: tc.app.Namespace,
+						},
+					})
+					r.NoError(err)
+					cmd.SetArgs([]string{tc.app.Name, "-n", tc.app.Namespace})
+				} else {
+					cmd.SetArgs([]string{tc.app.Name})
+				}
 			}
 			err := cmd.Execute()
 			if tc.expectedErr != nil {
@@ -346,7 +377,7 @@ func TestWorkflowRestart(t *testing.T) {
 			app: &v1beta1.Application{
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "workflow",
-					Namespace: "default",
+					Namespace: "test",
 				},
 				Spec: workflowSpec,
 				Status: common.AppStatus{
@@ -368,7 +399,17 @@ func TestWorkflowRestart(t *testing.T) {
 				err := c.Client.Create(ctx, tc.app)
 				r.NoError(err)
 
-				cmd.SetArgs([]string{tc.app.Name})
+				if tc.app.Namespace != corev1.NamespaceDefault {
+					err := c.Client.Create(ctx, &corev1.Namespace{
+						ObjectMeta: metav1.ObjectMeta{
+							Name: tc.app.Namespace,
+						},
+					})
+					r.NoError(err)
+					cmd.SetArgs([]string{tc.app.Name, "-n", tc.app.Namespace})
+				} else {
+					cmd.SetArgs([]string{tc.app.Name})
+				}
 			}
 			err := cmd.Execute()
 			if tc.expectedErr != nil {