[MM-12623] Create CLI command "config reset" (#10296)

Этот коммит содержится в:
Joshua Bezaleel Abednego
2019-11-02 01:29:02 +07:00
коммит произвёл Ben Schumacher
родитель 3687a0b6c1
Коммит 63a28700f5
2 изменённых файлов: 156 добавлений и 3 удалений

Просмотреть файл

@@ -11,6 +11,7 @@ import (
"strconv"
"strings"
"github.com/mattermost/viper"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -18,7 +19,6 @@ import (
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
"github.com/mattermost/viper"
)
const noSettingsNamed = "unable to find a setting named: %s"
@@ -80,8 +80,17 @@ var MigrateConfigCmd = &cobra.Command{
RunE: configMigrateCmdF,
}
var ConfigResetCmd = &cobra.Command{
Use: "reset",
Short: "Reset config setting",
Long: "Resets the value of a config setting by its name in dot notation or a setting section. Accepts multiple values for array settings.",
Example: "config reset SqlSettings.DriverName LogSettings",
RunE: configResetCmdF,
}
func init() {
ConfigSubpathCmd.Flags().String("path", "", "Optional subpath; defaults to value in SiteURL")
ConfigResetCmd.Flags().Bool("confirm", false, "Confirm you really want to reset all configuration settings to its default value")
ConfigShowCmd.Flags().Bool("json", false, "Output the configuration as JSON.")
ConfigCmd.AddCommand(
@@ -91,6 +100,7 @@ func init() {
ConfigShowCmd,
ConfigSetCmd,
MigrateConfigCmd,
ConfigResetCmd,
)
RootCmd.AddCommand(ConfigCmd)
}
@@ -367,6 +377,92 @@ func UpdateMap(configMap map[string]interface{}, configSettings []string, newVal
}
}
func configResetCmdF(command *cobra.Command, args []string) error {
configStore, err := getConfigStore(command)
if err != nil {
return err
}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
confirmFlag, _ := command.Flags().GetBool("confirm")
if confirmFlag {
if _, err = configStore.Set(defaultConfig); err != nil {
return errors.Wrap(err, "failed to set config")
}
}
if !confirmFlag && len(args) == 0 {
var confirmResetAll string
CommandPrettyPrintln("Are you sure you want to reset all the configuration settings?(YES/NO): ")
fmt.Scanln(&confirmResetAll)
if confirmResetAll == "YES" {
if _, err = configStore.Set(defaultConfig); err != nil {
return errors.Wrap(err, "failed to set config")
}
}
}
tempConfig := configStore.Get()
tempConfigMap := configToMap(*tempConfig)
defaultConfigMap := configToMap(*defaultConfig)
for _, arg := range args {
err = changeMap(tempConfigMap, defaultConfigMap, strings.Split(arg, "."))
if err != nil {
return errors.Wrap(err, "Failed to reset config")
}
}
bs, err := json.Marshal(tempConfigMap)
if err != nil {
fmt.Printf("Error while marshalling map to json %s\n", err)
os.Exit(1)
}
err = json.Unmarshal(bs, tempConfig)
if err != nil {
fmt.Printf("Error while unmarshalling json to struct %s\n", err)
os.Exit(1)
}
if changed := config.FixInvalidLocales(tempConfig); changed {
return errors.New("Invalid locale configuration")
}
if _, err := configStore.Set(tempConfig); err != nil {
return errors.Wrap(err, "failed to set config")
}
return nil
}
func changeMap(oldConfigMap, defaultConfigMap map[string]interface{}, configSettings []string) error {
resOld, ok := oldConfigMap[configSettings[0]]
if !ok {
return fmt.Errorf("Unable to find a setting with that name %s", configSettings[0])
}
resDef := defaultConfigMap[configSettings[0]]
valueOld := reflect.ValueOf(resOld)
if valueOld.Kind() == reflect.Map {
if len(configSettings) == 1 {
return changeSection(resOld.(map[string]interface{}), resDef.(map[string]interface{}))
}
return changeMap(resOld.(map[string]interface{}), resDef.(map[string]interface{}), configSettings[1:])
}
if len(configSettings) == 1 {
oldConfigMap[configSettings[0]] = defaultConfigMap[configSettings[0]]
return nil
}
return fmt.Errorf("Unable to find a setting with that name %s", configSettings[0])
}
func changeSection(oldConfigMap, defaultConfigMap map[string]interface{}) error {
valueOld := reflect.ValueOf(oldConfigMap)
for _, key := range valueOld.MapKeys() {
oldConfigMap[key.String()] = defaultConfigMap[key.String()]
}
return nil
}
// configToMap converts our config into a map
func configToMap(s interface{}) map[string]interface{} {
return structToMap(s)

Просмотреть файл

@@ -13,11 +13,10 @@ import (
"strings"
"testing"
"github.com/mattermost/mattermost-server/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/config"
"github.com/mattermost/mattermost-server/model"
)
@@ -168,6 +167,64 @@ func TestConfigSet(t *testing.T) {
})
}
func TestConfigReset(t *testing.T) {
th := Setup()
defer th.TearDown()
t.Run("No Error when no arguments are given (reset all the configurations)", func(t *testing.T) {
assert.NoError(t, th.RunCommand(t, "config", "reset"))
})
t.Run("No Error when a configuration section is given", func(t *testing.T) {
assert.NoError(t, th.RunCommand(t, "config", "reset", "JobSettings"))
})
t.Run("No Error when a configuration setting is given", func(t *testing.T) {
assert.NoError(t, th.RunCommand(t, "config", "reset", "JobSettings.RunJobs"))
})
t.Run("Error when the wrong configuration section is given", func(t *testing.T) {
assert.Error(t, th.RunCommand(t, "config", "reset", "InvalidSettings"))
})
t.Run("Error when the wrong configuration setting is given", func(t *testing.T) {
assert.Error(t, th.RunCommand(t, "config", "reset", "JobSettings.InvalidConfiguration"))
})
t.Run("Success when the confirm boolean flag is given", func(t *testing.T) {
assert.NoError(t, th.RunCommand(t, "config", "set", "JobSettings.RunJobs", "false"))
assert.NoError(t, th.RunCommand(t, "config", "set", "PrivacySettings.ShowFullName", "false"))
assert.NoError(t, th.RunCommand(t, "config", "reset", "--confirm"))
output1 := th.CheckCommand(t, "config", "get", "JobSettings.RunJobs")
output2 := th.CheckCommand(t, "config", "get", "PrivacySettings.ShowFullName")
assert.Contains(t, output1, "true")
assert.Contains(t, output2, "true")
})
t.Run("Success when a configuration section is given", func(t *testing.T) {
assert.NoError(t, th.RunCommand(t, "config", "set", "JobSettings.RunJobs", "false"))
assert.NoError(t, th.RunCommand(t, "config", "set", "JobSettings.RunScheduler", "false"))
assert.NoError(t, th.RunCommand(t, "config", "set", "PrivacySettings.ShowFullName", "false"))
assert.NoError(t, th.RunCommand(t, "config", "reset", "JobSettings"))
output1 := th.CheckCommand(t, "config", "get", "JobSettings.RunJobs")
output2 := th.CheckCommand(t, "config", "get", "JobSettings.RunScheduler")
output3 := th.CheckCommand(t, "config", "get", "PrivacySettings.ShowFullName")
assert.Contains(t, output1, "true")
assert.Contains(t, output2, "true")
assert.Contains(t, output3, "false")
})
t.Run("Success when a configuration setting is given", func(t *testing.T) {
assert.NoError(t, th.RunCommand(t, "config", "set", "JobSettings.RunJobs", "false"))
assert.NoError(t, th.RunCommand(t, "config", "set", "JobSettings.RunScheduler", "false"))
assert.NoError(t, th.RunCommand(t, "config", "reset", "JobSettings.RunJobs"))
output1 := th.CheckCommand(t, "config", "get", "JobSettings.RunJobs")
output2 := th.CheckCommand(t, "config", "get", "JobSettings.RunScheduler")
assert.Contains(t, output1, "true")
assert.Contains(t, output2, "false")
})
}
func TestConfigToMap(t *testing.T) {
// This test is almost the same as TestStructToMap, but I have it here for the sake of completions
cases := []struct {