From 2645bb285b0981aa78683a4208204b74f5df48c9 Mon Sep 17 00:00:00 2001
From: lijianguo <lijianguo1991@outlook.com>
Date: Thu, 6 Jun 2024 18:00:50 +0800
Subject: [PATCH] chore(workflow-cli): config action add confirm

chore(workflow-cli$): config action add confirm
---
 cmd/cmd.go            |  6 +--
 cmd/config.go         | 91 +++++++++++++++++++++++++++++++++++++++++--
 cmd/config_test.go    | 27 ++++++++-----
 cmd/ps.go             |  2 +-
 parser/config.go      | 16 ++++++--
 parser/config_test.go |  6 +--
 6 files changed, 123 insertions(+), 25 deletions(-)

diff --git a/cmd/cmd.go b/cmd/cmd.go
index 98666e57..38ddb6b2 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -42,10 +42,10 @@ type Commander interface {
 	CertAttach(string, string) error
 	CertDetach(string, string) error
 	ConfigList(string, string) error
-	ConfigSet(string, string, []string) error
-	ConfigUnset(string, string, []string) error
+	ConfigSet(string, string, []string, string) error
+	ConfigUnset(string, string, []string, string) error
 	ConfigPull(string, string, string, bool, bool) error
-	ConfigPush(string, string, string) error
+	ConfigPush(string, string, string, string) error
 	DomainsList(string, int) error
 	DomainsAdd(string, string, string) error
 	DomainsRemove(string, string) error
diff --git a/cmd/config.go b/cmd/config.go
index 25858119..3a93e3de 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -1,11 +1,13 @@
 package cmd
 
 import (
+	"bufio"
 	"bytes"
 	"encoding/base64"
 	"fmt"
 	"os"
 	"regexp"
+	"runtime"
 	"strings"
 
 	"github.com/drycc/controller-sdk-go/api"
@@ -37,18 +39,36 @@ func (d *DryccCmd) ConfigList(appID string, procType string) error {
 			fmt.Sprintf("%v", configValues[key]),
 		})
 	}
+
+	// common config
+	if procType != "" {
+		table.Append([]string{"--- Common Config:"})
+		configValues = config.Values
+		keys = *sortKeys(configValues)
+		for _, key := range keys {
+			table.Append([]string{
+				key,
+				fmt.Sprintf("%v", configValues[key]),
+			})
+		}
+	}
 	table.Render()
 	return nil
 }
 
 // ConfigSet sets an app's config variables.
-func (d *DryccCmd) ConfigSet(appID string, procType string, configVars []string) error {
+func (d *DryccCmd) ConfigSet(appID string, procType string, configVars []string, confirm string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
 	}
 
+	err = configConfirmAction(procType, confirm)
+	if err != nil {
+		return err
+	}
+
 	configMap, err := parseConfig(configVars)
 	if err != nil {
 		return err
@@ -97,13 +117,18 @@ to set up healthchecks. This functionality has been deprecated. In the future, p
 }
 
 // ConfigUnset removes a config variable from an app.
-func (d *DryccCmd) ConfigUnset(appID string, procType string, configVars []string) error {
+func (d *DryccCmd) ConfigUnset(appID string, procType string, configVars []string, confirm string) error {
 	s, appID, err := load(d.ConfigFile, appID)
 
 	if err != nil {
 		return err
 	}
 
+	err = configConfirmAction(procType, confirm)
+	if err != nil {
+		return err
+	}
+
 	d.Print("Removing config... ")
 
 	quit := progress(d.WOut)
@@ -207,7 +232,7 @@ func (d *DryccCmd) ConfigPull(appID, procType, fileName string, interactive bool
 }
 
 // ConfigPush pushes an app's config from a file.
-func (d *DryccCmd) ConfigPush(appID, procType string, fileName string) error {
+func (d *DryccCmd) ConfigPush(appID, procType string, fileName string, confirm string) error {
 	stat, err := os.Stdin.Stat()
 
 	if err != nil {
@@ -217,10 +242,19 @@ func (d *DryccCmd) ConfigPush(appID, procType string, fileName string) error {
 	var contents []byte
 
 	if (stat.Mode() & os.ModeCharDevice) == 0 {
+		err = configConfirmActionStdin(procType, confirm)
+		if err != nil {
+			return err
+		}
 		buffer := new(bytes.Buffer)
 		buffer.ReadFrom(os.Stdin)
 		contents = buffer.Bytes()
 	} else {
+		err = configConfirmAction(procType, confirm)
+		if err != nil {
+			return err
+		}
+
 		contents, err = os.ReadFile(fileName)
 
 		if err != nil {
@@ -239,7 +273,7 @@ func (d *DryccCmd) ConfigPush(appID, procType string, fileName string) error {
 		}
 	}
 
-	return d.ConfigSet(appID, procType, config)
+	return d.ConfigSet(appID, procType, config, "yes")
 }
 
 func parseConfig(configVars []string) (api.ConfigValues, error) {
@@ -304,3 +338,52 @@ func formatConfig(configVars map[string]interface{}) string {
 
 	return formattedConfig
 }
+
+func configConfirmAction(procType string, confirm string) error {
+	if procType == "" && (confirm == "" || confirm != "yes") {
+		fmt.Printf(` !    WARNING: Potentially Config Action
+ !    This command will deploy all processes of the application
+ !    To proceed, type "yes" !
+
+> `)
+
+		fmt.Scanln(&confirm)
+		if confirm != "yes" {
+			return fmt.Errorf("cancel the config action")
+		}
+	}
+	return nil
+}
+
+func configConfirmActionStdin(procType string, confirm string) error {
+	var reader *bufio.Reader
+	if runtime.GOOS == "windows" {
+		reader = bufio.NewReader(os.Stdin)
+	} else {
+		file, err := os.Open("/dev/tty")
+		if err != nil {
+			return err
+		}
+		defer file.Close()
+		reader = bufio.NewReader(file)
+	}
+
+	if procType == "" && (confirm == "" || confirm != "yes") {
+		fmt.Printf(` !    WARNING: Potentially Config Action
+ !    This command will deploy all processes of the application
+ !    To proceed, type "yes" !
+
+> `)
+
+		confirm, err := reader.ReadString('\n')
+		if err != nil {
+			return err
+		}
+
+		confirm = strings.TrimSpace(confirm)
+		if confirm != "yes" {
+			return fmt.Errorf("cancel the config action")
+		}
+	}
+	return nil
+}
diff --git a/cmd/config_test.go b/cmd/config_test.go
index 12457a32..760d3501 100644
--- a/cmd/config_test.go
+++ b/cmd/config_test.go
@@ -136,8 +136,13 @@ TRUE     false
 	b.Reset()
 	err = cmdr.ConfigList("foo", "web")
 	assert.NoError(t, err)
-	assert.Equal(t, b.String(), `NAME    VALUE 
-PORT    9000     
+	assert.Equal(t, b.String(), `NAME                  VALUE   
+PORT                  9000       
+--- Common Config:    
+FLOAT                 12.34      
+NCC                   1701       
+TEST                  testing    
+TRUE                  false      
 `, "output")
 
 }
@@ -184,7 +189,7 @@ func TestConfigSet(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	err = cmdr.ConfigSet("foo", "", []string{"TRUE=false", "SSH_KEY=-----BEGIN OPENSSH PRIVATE KEY-----"})
+	err = cmdr.ConfigSet("foo", "", []string{"TRUE=false", "SSH_KEY=-----BEGIN OPENSSH PRIVATE KEY-----"}, "yes")
 	assert.NoError(t, err)
 
 	assert.Equal(t, testutil.StripProgress(b.String()), `Creating config... done
@@ -238,7 +243,7 @@ func TestConfigUnset(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	err = cmdr.ConfigUnset("foo", "", []string{"FOO"})
+	err = cmdr.ConfigUnset("foo", "", []string{"FOO"}, "yes")
 	assert.NoError(t, err)
 
 	assert.Equal(t, testutil.StripProgress(b.String()), `Removing config... done
@@ -298,15 +303,17 @@ func TestConfigUnsetTypedValues(t *testing.T) {
 	var b bytes.Buffer
 	cmdr := DryccCmd{WOut: &b, ConfigFile: cf}
 
-	err = cmdr.ConfigUnset("foo", "web", []string{"FOO"})
+	err = cmdr.ConfigUnset("foo", "web", []string{"FOO"}, "")
 	assert.NoError(t, err)
 
 	assert.Equal(t, testutil.StripProgress(b.String()), `Removing config... done
 
-NAME     VALUE   
-FLOAT    12.34      
-NCC      1701       
-TEST     testing    
-TRUE     false      
+NAME                  VALUE   
+FLOAT                 12.34      
+NCC                   1701       
+TEST                  testing    
+TRUE                  false      
+--- Common Config:    
+RELEASE_VERSION       v1         
 `, "output")
 }
diff --git a/cmd/ps.go b/cmd/ps.go
index dd45e02e..cf07d08e 100644
--- a/cmd/ps.go
+++ b/cmd/ps.go
@@ -143,7 +143,7 @@ func (d *DryccCmd) PsRestart(appID string, targets []string, confirm string) err
 	if err != nil {
 		return err
 	}
-	if len(targets) == 0 && confirm == "" {
+	if len(targets) == 0 && (confirm == "" || confirm != "yes") {
 		d.Printf(` !    WARNING: Potentially Restart Action
  !    This command will restart all processes of the application
  !    To proceed, type "yes" !
diff --git a/parser/config.go b/parser/config.go
index 9dcfc7ab..5a06d14f 100644
--- a/parser/config.go
+++ b/parser/config.go
@@ -85,6 +85,8 @@ Options:
     the application that you wish to set.
   --type=<type>
     the procType for which the config needs to be set.
+  --confirm=yes
+    To proceed, type "yes".
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -95,8 +97,8 @@ Options:
 
 	app := safeGetString(args, "--app")
 	procType := safeGetString(args, "--type")
-
-	return cmdr.ConfigSet(app, procType, args["<var>=<value>"].([]string))
+	confirm := safeGetString(args, "--confirm")
+	return cmdr.ConfigSet(app, procType, args["<var>=<value>"].([]string), confirm)
 }
 
 func configUnset(argv []string, cmdr cmd.Commander) error {
@@ -114,6 +116,8 @@ Options:
     the application that you wish to unset.
   --type=<type>
     the procType for which the config needs to be unset.
+  --confirm=yes
+    To proceed, type "yes".
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -123,7 +127,8 @@ Options:
 	}
 	app := safeGetString(args, "--app")
 	procType := safeGetString(args, "--type")
-	return cmdr.ConfigUnset(app, procType, args["<key>"].([]string))
+	confirm := safeGetString(args, "--confirm")
+	return cmdr.ConfigUnset(app, procType, args["<key>"].([]string), confirm)
 }
 
 func configPull(argv []string, cmdr cmd.Commander) error {
@@ -181,6 +186,8 @@ Options:
     the procType for which the config needs to be push.
   --path=<path>
     a path leading to an environment file [default: .env]
+  --confirm=yes
+    To proceed, type "yes".
 `
 
 	args, err := docopt.ParseArgs(usage, argv, "")
@@ -192,5 +199,6 @@ Options:
 	app := safeGetString(args, "--app")
 	procType := safeGetString(args, "--type")
 	path := safeGetValue(args, "--path", ".env")
-	return cmdr.ConfigPush(app, procType, path)
+	confirm := safeGetString(args, "--confirm")
+	return cmdr.ConfigPush(app, procType, path, confirm)
 }
diff --git a/parser/config_test.go b/parser/config_test.go
index a9b9b465..624f65a1 100644
--- a/parser/config_test.go
+++ b/parser/config_test.go
@@ -16,11 +16,11 @@ func (d FakeDryccCmd) ConfigList(string, string) error {
 	return errors.New("config:list")
 }
 
-func (d FakeDryccCmd) ConfigSet(string, string, []string) error {
+func (d FakeDryccCmd) ConfigSet(string, string, []string, string) error {
 	return errors.New("config:set")
 }
 
-func (d FakeDryccCmd) ConfigUnset(string, string, []string) error {
+func (d FakeDryccCmd) ConfigUnset(string, string, []string, string) error {
 	return errors.New("config:unset")
 }
 
@@ -28,7 +28,7 @@ func (d FakeDryccCmd) ConfigPull(string, string, string, bool, bool) error {
 	return errors.New("config:pull")
 }
 
-func (d FakeDryccCmd) ConfigPush(string, string, string) error {
+func (d FakeDryccCmd) ConfigPush(string, string, string, string) error {
 	return errors.New("config:push")
 }
 
