[MM-12623] Create CLI command "config reset" (#10296)
Этот коммит содержится в:
коммит произвёл
Ben Schumacher
родитель
3687a0b6c1
Коммит
63a28700f5
@@ -11,6 +11,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mattermost/viper"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
@@ -18,7 +19,6 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/mlog"
|
"github.com/mattermost/mattermost-server/mlog"
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
"github.com/mattermost/mattermost-server/utils"
|
"github.com/mattermost/mattermost-server/utils"
|
||||||
"github.com/mattermost/viper"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const noSettingsNamed = "unable to find a setting named: %s"
|
const noSettingsNamed = "unable to find a setting named: %s"
|
||||||
@@ -80,8 +80,17 @@ var MigrateConfigCmd = &cobra.Command{
|
|||||||
RunE: configMigrateCmdF,
|
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() {
|
func init() {
|
||||||
ConfigSubpathCmd.Flags().String("path", "", "Optional subpath; defaults to value in SiteURL")
|
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.")
|
ConfigShowCmd.Flags().Bool("json", false, "Output the configuration as JSON.")
|
||||||
|
|
||||||
ConfigCmd.AddCommand(
|
ConfigCmd.AddCommand(
|
||||||
@@ -91,6 +100,7 @@ func init() {
|
|||||||
ConfigShowCmd,
|
ConfigShowCmd,
|
||||||
ConfigSetCmd,
|
ConfigSetCmd,
|
||||||
MigrateConfigCmd,
|
MigrateConfigCmd,
|
||||||
|
ConfigResetCmd,
|
||||||
)
|
)
|
||||||
RootCmd.AddCommand(ConfigCmd)
|
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
|
// configToMap converts our config into a map
|
||||||
func configToMap(s interface{}) map[string]interface{} {
|
func configToMap(s interface{}) map[string]interface{} {
|
||||||
return structToMap(s)
|
return structToMap(s)
|
||||||
|
|||||||
@@ -13,11 +13,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/config"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/config"
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"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) {
|
func TestConfigToMap(t *testing.T) {
|
||||||
// This test is almost the same as TestStructToMap, but I have it here for the sake of completions
|
// This test is almost the same as TestStructToMap, but I have it here for the sake of completions
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user