diff --git a/cmd/agent_profiles.go b/cmd/agent_profiles.go index 13a6cc3..df0402d 100644 --- a/cmd/agent_profiles.go +++ b/cmd/agent_profiles.go @@ -210,11 +210,11 @@ gocd-cli elastic-agent-profile delete sample_kubernetes -y`, if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/cmd/agents.go b/cmd/agents.go index d492480..46f914f 100644 --- a/cmd/agents.go +++ b/cmd/agents.go @@ -217,11 +217,11 @@ gocd-cli agents delete --id 938d1935-bdca-4728-83d5-e96cbf0a4f8b`, if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/cmd/artifacts.go b/cmd/artifacts.go index 97225e3..ae818ae 100644 --- a/cmd/artifacts.go +++ b/cmd/artifacts.go @@ -280,11 +280,11 @@ func deleteArtifactStoreCommand() *cobra.Command { if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/cmd/backup.go b/cmd/backup.go index b82134f..6fc8f8f 100644 --- a/cmd/backup.go +++ b/cmd/backup.go @@ -116,11 +116,11 @@ func deleteBackupConfig() *cobra.Command { if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/cmd/client.go b/cmd/client.go index f38a62b..95386e1 100644 --- a/cmd/client.go +++ b/cmd/client.go @@ -2,75 +2,57 @@ package cmd import ( "fmt" - "log" "os" "path/filepath" "strings" + "github.com/ghodss/yaml" "github.com/nikhilsbhat/common/renderer" + "github.com/nikhilsbhat/gocd-cli/pkg/diff" "github.com/nikhilsbhat/gocd-cli/pkg/errors" "github.com/nikhilsbhat/gocd-cli/pkg/utils" "github.com/nikhilsbhat/gocd-sdk-go" "github.com/spf13/cobra" "github.com/thoas/go-funk" - "gopkg.in/yaml.v3" ) var ( client gocd.GoCd cliRenderer renderer.Config cliShellReadConfig *utils.ReadConfig + diffCfg diff.Config supportedOutputFormats = []string{"yaml", "json", "csv", "table"} ) func setCLIClient(_ *cobra.Command, _ []string) error { - var caContent []byte - SetLogger(cliCfg.LogLevel) - localConfig, localConfigPath, err := checkForConfig() - if err != nil { + if localConfig, localConfigPath, err := checkForConfig(); err != nil { return err - } - - if localConfig && !cliCfg.skipCacheConfig { - cliLogger.Debugf("found authorisation configuration in cache, loading config from %s", localConfigPath) - - yamlConfig, err := os.ReadFile(localConfigPath) - if err != nil { + } else if localConfig && !cliCfg.skipCacheConfig { + cliLogger.Debugf("found authorization configuration in cache, loading config from %s", localConfigPath) + if yamlConfig, err := os.ReadFile(localConfigPath); err != nil { return err - } - - if err = yaml.Unmarshal(yamlConfig, &cliCfg); err != nil { + } else if err := yaml.Unmarshal(yamlConfig, &cliCfg); err != nil { return err } - - cliLogger.Debug("authorisation configuration loaded from cache successfully") + cliLogger.Debug("authorization configuration loaded from cache successfully") } if len(cliCfg.CaPath) != 0 { - cliLogger.Debug("CA based auth is enabled, hence reading ca from the path") + cliLogger.Debug("CA based auth is enabled, hence reading CA from the path") - caAbs, err := filepath.Abs(cliCfg.CaPath) - if err != nil { + if caAbs, err := filepath.Abs(cliCfg.CaPath); err != nil { return err + } else if caContent, err := os.ReadFile(caAbs); err != nil { + return err + } else { + client = gocd.NewClient(cliCfg.URL, cliCfg.Auth, cliCfg.APILogLevel, caContent) } - - caContent, err = os.ReadFile(caAbs) - if err != nil { - log.Fatal(err) - } + } else { + client = gocd.NewClient(cliCfg.URL, cliCfg.Auth, cliCfg.APILogLevel, nil) } - goCDClient := gocd.NewClient( - cliCfg.URL, - cliCfg.Auth, - cliCfg.APILogLevel, - caContent, - ) - - client = goCDClient - writer := os.Stdout if len(cliCfg.ToFile) != 0 { @@ -86,17 +68,15 @@ func setCLIClient(_ *cobra.Command, _ []string) error { if !cliCfg.validateOutputFormats() { supportedOutputFormatsString := strings.Join(supportedOutputFormats, "|") - cliLogger.Errorf("unsupported output format '%s', the value should be one of %s", - cliCfg.OutputFormat, supportedOutputFormatsString) + errMsg := fmt.Sprintf("unsupported output format '%s', the value should be one of %s", cliCfg.OutputFormat, supportedOutputFormatsString) + cliLogger.Errorf(errMsg) - return &errors.CLIError{ - Message: fmt.Sprintf("unsupported output format '%s', the value should be one of %s", - cliCfg.OutputFormat, supportedOutputFormatsString), - } + return &errors.CLIError{Message: errMsg} } + diffCfg = diff.Config{Format: cliCfg.OutputFormat} + diffCfg.SetLogger(cliLogger) cliCfg.setOutputFormats() - cliRenderer = renderer.GetRenderer(writer, cliLogger, cliCfg.NoColor, cliCfg.yaml, cliCfg.json, cliCfg.csv, cliCfg.table) inputOptions := []utils.Options{{Name: "yes", Short: "y"}, {Name: "no", Short: "n"}} @@ -126,3 +106,18 @@ func (cfg *Config) setOutputFormats() { default: } } + +func (cfg *Config) GetOutputFormat() string { + switch { + case cfg.yaml: + return "yaml" + case cfg.json: + return "json" + case cfg.table: + return "table" + case cfg.csv: + return "csv" + default: + return "" + } +} diff --git a/cmd/cluster_profiles.go b/cmd/cluster_profiles.go index 2317d0e..62b6a02 100644 --- a/cmd/cluster_profiles.go +++ b/cmd/cluster_profiles.go @@ -202,11 +202,11 @@ func deleteClusterProfileCommand() *cobra.Command { if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/cmd/config_repos.go b/cmd/config_repos.go index 2155a67..0bf60b8 100644 --- a/cmd/config_repos.go +++ b/cmd/config_repos.go @@ -366,6 +366,24 @@ func getUpdateConfigRepoCommand() *cobra.Command { return &errors.UnknownObjectTypeError{Name: objType} } + configRepoFetched, err := client.GetConfigRepo(configRepo.ID) + if err != nil { + return err + } + + cliShellReadConfig.ShellMessage = fmt.Sprintf(updateMessage, "config-repo", configRepoFetched.ID) + + existing, err := diffCfg.String(configRepoFetched) + if err != nil { + return err + } + + if !cliCfg.Yes { + if err = CheckDiffAndAllow(existing, object.String()); err != nil { + return err + } + } + response, err := client.UpdateConfigRepo(configRepo) if err != nil { return err @@ -394,11 +412,11 @@ func getDeleteConfigRepoCommand() *cobra.Command { if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/cmd/constants.go b/cmd/constants.go index 1d619dd..2d1108f 100644 --- a/cmd/constants.go +++ b/cmd/constants.go @@ -1 +1,7 @@ package cmd + +const ( + updateMessage = "do you want to update '%s' '%s' [y/n]" + inputValidationFailureMessage = "user input validation failed, cannot proceed further" + optingOutMessage = "not proceeding further since 'no' was opted" +) diff --git a/cmd/diff.go b/cmd/diff.go new file mode 100644 index 0000000..83bdab4 --- /dev/null +++ b/cmd/diff.go @@ -0,0 +1,33 @@ +package cmd + +import ( + "fmt" + "os" +) + +func CheckDiffAndAllow(oldData, newData string) error { + hasDiff, diff, err := diffCfg.Diff(oldData, newData) + if err != nil { + return err + } + + if !hasDiff { + cliLogger.Info("no changes to the input file, nothing to update, quitting") + os.Exit(0) + } + + fmt.Printf("%s\n", diff) + + contains, option := cliShellReadConfig.Reader() + if !contains { + cliLogger.Fatalln(inputValidationFailureMessage) + } + + if option.Short == "n" { + cliLogger.Warn(optingOutMessage) + + os.Exit(0) + } + + return nil +} diff --git a/cmd/environments.go b/cmd/environments.go index ea1f207..2e3a58e 100644 --- a/cmd/environments.go +++ b/cmd/environments.go @@ -318,11 +318,11 @@ func deleteEnvironmentCommand() *cobra.Command { if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/cmd/pipeline_groups.go b/cmd/pipeline_groups.go index d3e31ec..b00fd96 100644 --- a/cmd/pipeline_groups.go +++ b/cmd/pipeline_groups.go @@ -208,11 +208,11 @@ func deletePipelineGroupCommand() *cobra.Command { if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/cmd/pipelines.go b/cmd/pipelines.go index d94b44d..7f45bed 100644 --- a/cmd/pipelines.go +++ b/cmd/pipelines.go @@ -592,11 +592,11 @@ func deletePipelineCommand() *cobra.Command { if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/cmd/server_configurations.go b/cmd/server_configurations.go index 581a76b..2f2c7e7 100644 --- a/cmd/server_configurations.go +++ b/cmd/server_configurations.go @@ -377,11 +377,11 @@ func deleteMailServerConfigCommand() *cobra.Command { if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/cmd/users.go b/cmd/users.go index 640c3ea..7708e39 100644 --- a/cmd/users.go +++ b/cmd/users.go @@ -166,11 +166,11 @@ func userDeleteCommand() *cobra.Command { if !cliCfg.Yes { contains, option := cliShellReadConfig.Reader() if !contains { - cliLogger.Fatalln("user input validation failed, cannot proceed further") + cliLogger.Fatalln(inputValidationFailureMessage) } if option.Short == "n" { - cliLogger.Warn("not proceeding further since 'no' was opted") + cliLogger.Warn(optingOutMessage) os.Exit(0) } diff --git a/go.mod b/go.mod index bde5df8..600b6d6 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,15 @@ module github.com/nikhilsbhat/gocd-cli go 1.21.1 require ( - github.com/goccy/go-yaml v1.11.2 - github.com/nikhilsbhat/common v0.0.4-0.20240127094948-85c315a50de3 + github.com/fatih/color v1.16.0 + github.com/ghodss/yaml v1.0.0 + github.com/goccy/go-yaml v1.11.3 + github.com/nikhilsbhat/common v0.0.5-0.20240330150338-6dad4cae0c57 github.com/nikhilsbhat/gocd-sdk-go v0.1.9 + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.6.1 - github.com/stretchr/testify v1.8.4 + github.com/spf13/cobra v1.7.0 + github.com/stretchr/testify v1.9.0 github.com/thedevsaddam/gojsonq/v2 v2.5.2 github.com/thoas/go-funk v0.9.3 github.com/tidwall/gjson v1.16.0 @@ -18,26 +21,24 @@ require ( require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fatih/color v1.16.0 // indirect - github.com/ghodss/yaml v1.0.0 // indirect github.com/go-resty/resty/v2 v2.11.0 // indirect github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/imdario/mergo v0.3.15 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jinzhu/copier v0.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/neilotoole/jsoncolor v0.7.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.15.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/term v0.16.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 3a7e9c1..4490873 100644 --- a/go.sum +++ b/go.sum @@ -18,14 +18,14 @@ github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqx github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a h1:RYfmiM0zluBJOiPDJseKLEN4BapJ42uSi9SZBQ2YyiA= github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= -github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ= -github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= +github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -46,8 +46,8 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/neilotoole/jsoncolor v0.7.1 h1:/MoU7KPLcto+ykcy592Y8eX9WFQhoi3IBEbwrP89dgs= github.com/neilotoole/jsoncolor v0.7.1/go.mod h1:KZ9hUYN5xMrvyhqlFQ3QTmu11OcoqFgSnWAcYkN6abg= -github.com/nikhilsbhat/common v0.0.4-0.20240127094948-85c315a50de3 h1:NAQEpaBRA8K3FcAO5/Lw5jat6Ub/Ua64+njOaSYRqE8= -github.com/nikhilsbhat/common v0.0.4-0.20240127094948-85c315a50de3/go.mod h1:ldoLjRsIaskDbouPaQ0ujVKbW8su3mI1MPQIaD24twQ= +github.com/nikhilsbhat/common v0.0.5-0.20240330150338-6dad4cae0c57 h1:6BYXfUsKO7xwzfA5a2xtY14i90xqiHLCJDV0epRHJU8= +github.com/nikhilsbhat/common v0.0.5-0.20240330150338-6dad4cae0c57/go.mod h1:ldoLjRsIaskDbouPaQ0ujVKbW8su3mI1MPQIaD24twQ= github.com/nikhilsbhat/gocd-sdk-go v0.1.9 h1:QG16EwKhxocn0Imza6S+/lE8S0MOw54UDebfJotQx2s= github.com/nikhilsbhat/gocd-sdk-go v0.1.9/go.mod h1:FFVOLXPhn55evuuyfiRJ23R8I5Ks2n31/DXLBQmaNsw= github.com/nwidger/jsoncolor v0.3.2 h1:rVJJlwAWDJShnbTYOQ5RM7yTA20INyKXlJ/fg4JMhHQ= @@ -67,8 +67,8 @@ github.com/segmentio/encoding v0.3.6 h1:E6lVLyDPseWEulBmCmAKPanDd3jiyGDo5gMcugCR github.com/segmentio/encoding v0.3.6/go.mod h1:n0JeuIqEQrQoPDGsjo8UNd1iA0U8d8+oHAA4E3G3OxM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -78,8 +78,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/thedevsaddam/gojsonq/v2 v2.5.2 h1:CoMVaYyKFsVj6TjU6APqAhAvC07hTI6IQen8PHzHYY0= github.com/thedevsaddam/gojsonq/v2 v2.5.2/go.mod h1:bv6Xa7kWy82uT0LnXPE2SzGqTj33TAEeR560MdJkiXs= github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw= @@ -94,8 +95,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -104,8 +105,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -124,16 +125,16 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -147,8 +148,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/diff/diff.go b/pkg/diff/diff.go new file mode 100644 index 0000000..169a0c4 --- /dev/null +++ b/pkg/diff/diff.go @@ -0,0 +1,105 @@ +package diff + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/fatih/color" + "github.com/ghodss/yaml" + "github.com/nikhilsbhat/gocd-cli/pkg/errors" + "github.com/pmezard/go-difflib/difflib" + "github.com/sirupsen/logrus" +) + +const ( + contextLines = 2000000 +) + +type Config struct { + NoColor bool + Format string + log *logrus.Logger +} + +func (cfg *Config) Diff(oldData, newData string) (bool, string, error) { + switch cfg.Format { + case "yaml": + cfg.log.Debug("loading diff in yaml format") + case "json": + cfg.log.Debug("loading diff in json format") + default: + return false, "", &errors.CLIError{Message: fmt.Sprintf("unknown format, cannot calculate diff for the format '%s'", cfg.Format)} + } + + diffIdentified, err := diff(oldData, newData) + if err != nil { + return false, "", err + } + + if len(diffIdentified) == 0 { + return false, "", nil + } + + return true, strings.Join(diffIdentified, "\n"), nil +} + +func (cfg *Config) String(input interface{}) (string, error) { + switch strings.ToLower(cfg.Format) { + case "yaml": + out, err := yaml.Marshal(input) + if err != nil { + return "", err + } + + yamlString := strings.Join([]string{"---", string(out)}, "\n") + + return yamlString, nil + case "json": + out, err := json.MarshalIndent(input, "", " ") + if err != nil { + return "", err + } + + return string(out), nil + default: + return "", &errors.CLIError{ + Message: fmt.Sprintf("type '%s' is not supported for loading diff", cfg.Format), + } + } +} + +func (cfg *Config) SetLogger(log *logrus.Logger) { + cfg.log = log +} + +func diff(content1, content2 string) ([]string, error) { + lines := make([]string, 0) + diffVal := difflib.UnifiedDiff{ + A: difflib.SplitLines(content1), + B: difflib.SplitLines(content2), + FromFile: "old", + ToFile: "new", + Context: contextLines, + } + + text, err := difflib.GetUnifiedDiffString(diffVal) + if err != nil { + return nil, err + } + + if len(text) == 0 { + return lines, nil + } + + lines = strings.Split(text, "\n") + for i, line := range lines { + if strings.HasPrefix(line, "-") { + lines[i] = color.RedString(line) + } else if strings.HasPrefix(line, "+") { + lines[i] = color.GreenString(line) + } + } + + return lines, nil +}