From d5b43dfbe545b876c075ff7a3fa18f9fa8fa940a Mon Sep 17 00:00:00 2001 From: Olivier CANO Date: Fri, 31 Jan 2020 15:11:42 +0100 Subject: [PATCH 1/5] feat(core): check version of the CLI --- cmd/scw/main.go | 7 ++- go.mod | 3 +- go.sum | 6 +- internal/core/bootstrap.go | 9 ++- internal/core/build_info.go | 102 ++++++++++++++++++++++++++++++++- internal/core/client.go | 2 +- internal/human/marshal_func.go | 5 ++ internal/sentry/sentry.go | 2 +- 8 files changed, 124 insertions(+), 12 deletions(-) diff --git a/cmd/scw/main.go b/cmd/scw/main.go index e704051627..d97c2e8737 100644 --- a/cmd/scw/main.go +++ b/cmd/scw/main.go @@ -4,13 +4,14 @@ import ( "os" "runtime" + "github.com/hashicorp/go-version" "github.com/scaleway/scaleway-cli/internal/core" autocompleteNamespace "github.com/scaleway/scaleway-cli/internal/namespaces/autocomplete" configNamespace "github.com/scaleway/scaleway-cli/internal/namespaces/config" initNamespace "github.com/scaleway/scaleway-cli/internal/namespaces/init" "github.com/scaleway/scaleway-cli/internal/namespaces/instance/v1" "github.com/scaleway/scaleway-cli/internal/namespaces/marketplace/v1" - "github.com/scaleway/scaleway-cli/internal/namespaces/version" + versionNamespace "github.com/scaleway/scaleway-cli/internal/namespaces/version" "github.com/scaleway/scaleway-cli/internal/sentry" ) @@ -26,7 +27,7 @@ var ( func main() { buildInfo := &core.BuildInfo{ - Version: Version, + Version: version.Must(version.NewSemver(Version)), // panic when version does not respect semantic versionning BuildDate: BuildDate, GoVersion: GoVersion, GitBranch: GitBranch, @@ -45,7 +46,7 @@ func main() { commands.Merge(configNamespace.GetCommands()) commands.Merge(marketplace.GetCommands()) commands.Merge(autocompleteNamespace.GetCommands()) - commands.Merge(version.GetCommands()) + commands.Merge(versionNamespace.GetCommands()) exitCode, _, _ := core.Bootstrap(&core.BootstrapConfig{ Args: os.Args, diff --git a/go.mod b/go.mod index 935c502658..fbeb676db8 100644 --- a/go.mod +++ b/go.mod @@ -15,11 +15,12 @@ require ( github.com/fatih/color v1.7.0 github.com/getsentry/raven-go v0.2.0 github.com/hashicorp/go-multierror v1.0.0 + github.com/hashicorp/go-version v1.2.0 github.com/kr/pretty v0.1.0 // indirect github.com/mattn/go-colorable v0.1.2 // indirect github.com/mattn/go-isatty v0.0.9 github.com/pkg/errors v0.9.1 // indirect - github.com/scaleway/scaleway-sdk-go v1.0.0-beta.5.0.20200129095835-23f29e96b36e + github.com/scaleway/scaleway-sdk-go v1.0.0-beta.5.0.20200130170711-05d27d10a3b8 github.com/sergi/go-diff v1.0.0 // indirect github.com/spf13/cobra v0.0.5 github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index 747bf93449..635bf2e4db 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,8 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -70,8 +72,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.5.0.20200129095835-23f29e96b36e h1:UAYWUW1xKDW6k/KzLWVBcklc66nQlW6lAcM4pXunFqg= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.5.0.20200129095835-23f29e96b36e/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.5.0.20200130170711-05d27d10a3b8 h1:+y+U0MHG110iL4TkTKEb3Wh07OK7ALY2XbNFxeAEb80= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.5.0.20200130170711-05d27d10a3b8/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= diff --git a/internal/core/bootstrap.go b/internal/core/bootstrap.go index caf02c77a5..db29d8b257 100644 --- a/internal/core/bootstrap.go +++ b/internal/core/bootstrap.go @@ -68,7 +68,7 @@ func Bootstrap(config *BootstrapConfig) (exitCode int, result interface{}, err e } matomoErr := matomo.SendCommandTelemetry(&matomo.SendCommandTelemetryRequest{ Command: meta.command.getPath(), - Version: config.BuildInfo.Version, + Version: config.BuildInfo.Version.String(), ExecutionTime: time.Since(start), }) if matomoErr != nil { @@ -79,6 +79,13 @@ func Bootstrap(config *BootstrapConfig) (exitCode int, result interface{}, err e }() } + // Check CLI new version + if interactive.IsInteractive { + defer func() { + config.BuildInfo.checkVersion() + }() + } + // cobraBuilder will build a Cobra root command from a list of Command builder := cobraBuilder{ commands: config.Commands.command, diff --git a/internal/core/build_info.go b/internal/core/build_info.go index defab54b63..1c7bd436d6 100644 --- a/internal/core/build_info.go +++ b/internal/core/build_info.go @@ -1,11 +1,20 @@ package core import ( + "io/ioutil" + "net/http" + "os" + "path/filepath" "strings" + "time" + + "github.com/hashicorp/go-version" + "github.com/scaleway/scaleway-sdk-go/logger" + "github.com/scaleway/scaleway-sdk-go/scw" ) type BuildInfo struct { - Version string + Version *version.Version BuildDate string GoVersion string GitBranch string @@ -14,9 +23,96 @@ type BuildInfo struct { GoOS string } +const ( + scwDisableCheckVersionEnv = "SCW_DISABLE_CHECK_VERSION" + latestVersionFileURL = "https://scw-devtools.s3.nl-ams.scw.cloud/scw-cli-v2-version" + latestVersionUpdateFileLocalName = "latest-cli-version" + latestVersionRequestTimeout = 1 * time.Second +) + // IsRelease returns true when the version of the CLI is an official release: // - version must be non-empty (exclude tests) -// - version must not contain label (e.g. '+dev') +// - version must not contain metadata (e.g. '+dev') func (b *BuildInfo) IsRelease() bool { - return b.Version != "" && !strings.Contains(b.Version, "+") + return b.Version != nil && b.Version.Metadata() == "" +} + +func (b *BuildInfo) checkVersion() { + if !b.IsRelease() || os.Getenv(scwDisableCheckVersionEnv) == "true" { + logger.Debugf("skipping check version") + return + } + + latestVersionUpdateFilePath := filepath.Join(scw.GetCacheDirectory(), latestVersionUpdateFileLocalName) + + // do nothing if last refresh at during the last 24h + if fileUpdateLast24h(latestVersionUpdateFilePath) { + logger.Debugf("version was already checked during past 24 hours") + return + } + + // do nothing if we cannot create the file + if !createAndCloseFile(latestVersionUpdateFilePath) { + return + } + + // pull latest version + latestVersion, err := getLatestVersion() + if err != nil { + logger.Debugf("failed to retrieve latest version: %s", err) + return + } + + if b.Version.LessThan(latestVersion) { + logger.Infof("a new version of scw is available (%s), beware that you are currently running %v", b.Version, latestVersion) + } else { + logger.Infof("version is up to date (%s)", b.Version) + } +} + +// getLatestVersion attempt to read the latest version of the remote file at latestVersionFileURL. +func getLatestVersion() (*version.Version, error) { + resp, err := (&http.Client{ + Timeout: latestVersionRequestTimeout, + }).Get(latestVersionFileURL) + if resp != nil { + defer resp.Body.Close() + } + if err != nil { + return nil, err + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return version.NewSemver(strings.Trim(string(body), "\n")) +} + +// fileUpdateLast24h creates a file and close it. It returns true on succeed, false on failure. +func fileUpdateLast24h(path string) bool { + stat, err := os.Stat(path) + if err != nil { + return false + } + + yesterday := time.Now().AddDate(0, 0, -1) + lastUpdate := stat.ModTime() + return lastUpdate.After(yesterday) +} + +// createAndCloseFile creates a file and close it. It returns true on succeed, false on failure. +func createAndCloseFile(path string) bool { + err := os.MkdirAll(filepath.Dir(path), 0700) + if err != nil { + logger.Debugf("failed creating path %s: %s", path, err) + } + newFile, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0600) + if err != nil { + logger.Debugf("failed creating file %s: %s", path, err) + return false + } + + newFile.Close() + return true } diff --git a/internal/core/client.go b/internal/core/client.go index 44e52edbc3..ec796c1200 100644 --- a/internal/core/client.go +++ b/internal/core/client.go @@ -54,7 +54,7 @@ func createClient(meta *meta) (*scw.Client, error) { } opts := []scw.ClientOption{ - scw.WithUserAgent("scaleway-cli/" + meta.BuildInfo.Version), + scw.WithUserAgent("scaleway-cli/" + meta.BuildInfo.Version.String()), scw.WithProfile(profile), } diff --git a/internal/human/marshal_func.go b/internal/human/marshal_func.go index 43f09da9b3..96acb93b19 100644 --- a/internal/human/marshal_func.go +++ b/internal/human/marshal_func.go @@ -8,6 +8,7 @@ import ( "github.com/dustin/go-humanize" "github.com/fatih/color" + "github.com/hashicorp/go-version" "github.com/scaleway/scaleway-cli/internal/terminal" "github.com/scaleway/scaleway-sdk-go/scw" ) @@ -43,6 +44,10 @@ var marshalerFuncs = map[reflect.Type]MarshalerFunc{ v := i.(scw.IPNet) return v.String(), nil }, + reflect.TypeOf(version.Version{}): func(i interface{}, opt *MarshalOpt) (string, error) { + v := i.(version.Version) + return v.String(), nil + }, } // TODO: implement the same logic as args.RegisterMarshalFunc(), where i must be a pointer diff --git a/internal/sentry/sentry.go b/internal/sentry/sentry.go index e1050e75a4..ed9e5057a5 100644 --- a/internal/sentry/sentry.go +++ b/internal/sentry/sentry.go @@ -52,7 +52,7 @@ func newSentryClient(buildInfo *core.BuildInfo) (*raven.Client, error) { } tagsContext := map[string]string{ - "version": buildInfo.Version, + "version": buildInfo.Version.String(), "go_arch": buildInfo.GoArch, "go_os": buildInfo.GoOS, "go_version": buildInfo.GoVersion, From 94d5d4d6f31120021f73a08fe5d00351cdf860e9 Mon Sep 17 00:00:00 2001 From: Olivier CANO Date: Fri, 31 Jan 2020 16:49:41 +0100 Subject: [PATCH 2/5] few comment --- cmd/scw/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/scw/main.go b/cmd/scw/main.go index d97c2e8737..b6903dd8ae 100644 --- a/cmd/scw/main.go +++ b/cmd/scw/main.go @@ -36,7 +36,7 @@ func main() { GoArch: GoArch, } - // catch every panic after this line + // Catch every panic after this line. This will send an anonymous report on Scaleway's sentry. defer sentry.RecoverPanicAndSendReport(buildInfo) // Import all commands available in CLI from various packages. From a583f6539af5dc4ad3a8692789990ba70d26809c Mon Sep 17 00:00:00 2001 From: Olivier CANO Date: Mon, 3 Feb 2020 13:32:19 +0100 Subject: [PATCH 3/5] address jerome's comments --- internal/core/bootstrap.go | 8 +++----- internal/core/build_info.go | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/internal/core/bootstrap.go b/internal/core/bootstrap.go index db29d8b257..b356a60a2d 100644 --- a/internal/core/bootstrap.go +++ b/internal/core/bootstrap.go @@ -80,11 +80,9 @@ func Bootstrap(config *BootstrapConfig) (exitCode int, result interface{}, err e } // Check CLI new version - if interactive.IsInteractive { - defer func() { - config.BuildInfo.checkVersion() - }() - } + defer func() { + config.BuildInfo.checkVersion() + }() // cobraBuilder will build a Cobra root command from a list of Command builder := cobraBuilder{ diff --git a/internal/core/build_info.go b/internal/core/build_info.go index 1c7bd436d6..375900d65e 100644 --- a/internal/core/build_info.go +++ b/internal/core/build_info.go @@ -46,7 +46,7 @@ func (b *BuildInfo) checkVersion() { latestVersionUpdateFilePath := filepath.Join(scw.GetCacheDirectory(), latestVersionUpdateFileLocalName) // do nothing if last refresh at during the last 24h - if fileUpdateLast24h(latestVersionUpdateFilePath) { + if wasFileModifiedLast24h(latestVersionUpdateFilePath) { logger.Debugf("version was already checked during past 24 hours") return } @@ -89,8 +89,8 @@ func getLatestVersion() (*version.Version, error) { return version.NewSemver(strings.Trim(string(body), "\n")) } -// fileUpdateLast24h creates a file and close it. It returns true on succeed, false on failure. -func fileUpdateLast24h(path string) bool { +// wasFileModifiedLast24h checks that the file has been updated during last 24 hours. +func wasFileModifiedLast24h(path string) bool { stat, err := os.Stat(path) if err != nil { return false From 2b8ede475b5ce409762ae7deed022abb4bd803e7 Mon Sep 17 00:00:00 2001 From: Olivier CANO Date: Wed, 5 Feb 2020 15:09:36 +0100 Subject: [PATCH 4/5] add tests --- internal/core/bootstrap.go | 44 ++++++------ internal/core/build_info.go | 14 ++-- internal/core/build_info_test.go | 69 +++++++++++++++++++ internal/core/cobra_utils.go | 5 +- ...heck-version-already-checked.stderr.golden | 3 + ...eck-version-outdated-version.stderr.golden | 1 + ...k-version-up-to-date-version.stderr.golden | 3 + internal/core/testing.go | 16 ++++- internal/core/validate.go | 2 +- .../instance/v1/custom_server_create.go | 16 ++--- 10 files changed, 134 insertions(+), 39 deletions(-) create mode 100644 internal/core/build_info_test.go create mode 100644 internal/core/testdata/test-check-version-already-checked.stderr.golden create mode 100644 internal/core/testdata/test-check-version-outdated-version.stderr.golden create mode 100644 internal/core/testdata/test-check-version-up-to-date-version.stderr.golden diff --git a/internal/core/bootstrap.go b/internal/core/bootstrap.go index b356a60a2d..c318eb2d2c 100644 --- a/internal/core/bootstrap.go +++ b/internal/core/bootstrap.go @@ -59,27 +59,31 @@ func Bootstrap(config *BootstrapConfig) (exitCode int, result interface{}, err e } // Send Matomo telemetry when exiting the bootstrap - if (matomo.ForceTelemetry || config.BuildInfo.IsRelease()) && matomo.IsTelemetryEnabled() { - start := time.Now() - defer func() { - if meta.command == nil || meta.command.DisableTelemetry { - logger.Debugf("skipping telemetry report") - return - } - matomoErr := matomo.SendCommandTelemetry(&matomo.SendCommandTelemetryRequest{ - Command: meta.command.getPath(), - Version: config.BuildInfo.Version.String(), - ExecutionTime: time.Since(start), - }) - if matomoErr != nil { - logger.Debugf("error during telemetry reporting: %s", matomoErr) - } else { - logger.Debugf("telemetry successfully sent") - } - }() - } + start := time.Now() + defer func() { + // skip telemetry report when at least one of the following criteria matches: + // - version is not a release + // - telemetry is disabled on the current command + // - telemetry is disabled from the config (user must consent) + if (!matomo.ForceTelemetry && !config.BuildInfo.IsRelease()) || + (meta.command == nil || meta.command.DisableTelemetry) || + !matomo.IsTelemetryEnabled() { + logger.Debugf("skipping telemetry report") + return + } + matomoErr := matomo.SendCommandTelemetry(&matomo.SendCommandTelemetryRequest{ + Command: meta.command.getPath(), + Version: config.BuildInfo.Version.String(), + ExecutionTime: time.Since(start), + }) + if matomoErr != nil { + logger.Debugf("error during telemetry reporting: %s", matomoErr) + } else { + logger.Debugf("telemetry successfully sent") + } + }() - // Check CLI new version + // Check CLI new version when exiting the bootstrap defer func() { config.BuildInfo.checkVersion() }() diff --git a/internal/core/build_info.go b/internal/core/build_info.go index 375900d65e..db94d72372 100644 --- a/internal/core/build_info.go +++ b/internal/core/build_info.go @@ -43,7 +43,7 @@ func (b *BuildInfo) checkVersion() { return } - latestVersionUpdateFilePath := filepath.Join(scw.GetCacheDirectory(), latestVersionUpdateFileLocalName) + latestVersionUpdateFilePath := getLatestVersionUpdateFilePath() // do nothing if last refresh at during the last 24h if wasFileModifiedLast24h(latestVersionUpdateFilePath) { @@ -64,12 +64,16 @@ func (b *BuildInfo) checkVersion() { } if b.Version.LessThan(latestVersion) { - logger.Infof("a new version of scw is available (%s), beware that you are currently running %v", b.Version, latestVersion) + logger.Infof("a new version of scw is available (%s), beware that you are currently running %v", latestVersion, b.Version) } else { - logger.Infof("version is up to date (%s)", b.Version) + logger.Debugf("version is up to date (%s)", b.Version) } } +func getLatestVersionUpdateFilePath() string { + return filepath.Join(scw.GetCacheDirectory(), latestVersionUpdateFileLocalName) +} + // getLatestVersion attempt to read the latest version of the remote file at latestVersionFileURL. func getLatestVersion() (*version.Version, error) { resp, err := (&http.Client{ @@ -89,7 +93,7 @@ func getLatestVersion() (*version.Version, error) { return version.NewSemver(strings.Trim(string(body), "\n")) } -// wasFileModifiedLast24h checks that the file has been updated during last 24 hours. +// wasFileModifiedLast24h checks whether the file has been updated during last 24 hours. func wasFileModifiedLast24h(path string) bool { stat, err := os.Stat(path) if err != nil { @@ -101,7 +105,7 @@ func wasFileModifiedLast24h(path string) bool { return lastUpdate.After(yesterday) } -// createAndCloseFile creates a file and close it. It returns true on succeed, false on failure. +// createAndCloseFile creates a file and closes it. It returns true on succeed, false on failure. func createAndCloseFile(path string) bool { err := os.MkdirAll(filepath.Dir(path), 0700) if err != nil { diff --git a/internal/core/build_info_test.go b/internal/core/build_info_test.go new file mode 100644 index 0000000000..0f27fb813c --- /dev/null +++ b/internal/core/build_info_test.go @@ -0,0 +1,69 @@ +package core + +import ( + "context" + "fmt" + "os" + "reflect" + "testing" + + "github.com/hashicorp/go-version" + "github.com/scaleway/scaleway-cli/internal/args" +) + +var fakeCommand = &Command{ + Namespace: "plop", + DisableTelemetry: true, + ArgsType: reflect.TypeOf(args.RawArgs{}), + Run: func(ctx context.Context, argsI interface{}) (i interface{}, e error) { + return &SuccessResult{}, nil + }, +} + +func deleteLatestVersionUpdateFile(*BeforeFuncCtx) error { + os.Remove(getLatestVersionUpdateFilePath()) + return nil +} + +func Test_CheckVersion(t *testing.T) { + t.Run("Outdated version", Test(&TestConfig{ + Commands: NewCommands(fakeCommand), + BuildInfo: BuildInfo{ + Version: version.Must(version.NewSemver("v1.20")), + }, + BeforeFunc: deleteLatestVersionUpdateFile, + Cmd: "scw plop", + Check: TestCheckCombine( + TestCheckStderrGolden(), + ), + })) + + t.Run("Up to date version", Test(&TestConfig{ + Commands: NewCommands(fakeCommand), + BuildInfo: BuildInfo{ + Version: version.Must(version.NewSemver("v99.99")), + }, + BeforeFunc: deleteLatestVersionUpdateFile, + Cmd: "scw plop -D", + Check: TestCheckCombine( + TestCheckStderrGolden(), + ), + })) + + t.Run("Already checked", Test(&TestConfig{ + Commands: NewCommands(fakeCommand), + BuildInfo: BuildInfo{ + Version: version.Must(version.NewSemver("v1.0")), + }, + BeforeFunc: func(ctx *BeforeFuncCtx) error { + if createAndCloseFile(getLatestVersionUpdateFilePath()) { + return nil + } + return fmt.Errorf("failed to create latestVersionUpdateFile") + }, + Cmd: "scw plop -D", + Check: TestCheckCombine( + TestCheckStderrGolden(), + ), + })) +} diff --git a/internal/core/cobra_utils.go b/internal/core/cobra_utils.go index 06fa13a16b..55d92054dd 100644 --- a/internal/core/cobra_utils.go +++ b/internal/core/cobra_utils.go @@ -115,10 +115,11 @@ func cobraPreRunInitMeta(ctx context.Context, cmd *Command) func(cmd *cobra.Comm var err error meta := extractMeta(ctx) - // enable debug mode + logLevel := logger.LogLevelInfo if meta.DebugModeFlag { - logger.EnableDebugMode() + logLevel = logger.LogLevelDebug // enable debug mode } + logger.DefaultLogger.Init(meta.stderr, logLevel) meta.Printer, err = printer.New(meta.PrinterTypeFlag, meta.stdout, meta.stderr) if err != nil { diff --git a/internal/core/testdata/test-check-version-already-checked.stderr.golden b/internal/core/testdata/test-check-version-already-checked.stderr.golden new file mode 100644 index 0000000000..9e6c63f03d --- /dev/null +++ b/internal/core/testdata/test-check-version-already-checked.stderr.golden @@ -0,0 +1,3 @@ +DEBUG: 2019/12/09 16:04:07 marshalling type '*core.SuccessResult' +DEBUG: 2019/12/09 16:04:07 version was already checked during past 24 hours +DEBUG: 2019/12/09 16:04:07 skipping telemetry report diff --git a/internal/core/testdata/test-check-version-outdated-version.stderr.golden b/internal/core/testdata/test-check-version-outdated-version.stderr.golden new file mode 100644 index 0000000000..7a44331f31 --- /dev/null +++ b/internal/core/testdata/test-check-version-outdated-version.stderr.golden @@ -0,0 +1 @@ +INFO: 2019/12/09 16:04:07 a new version of scw is available (2.0.0-alpha1), beware that you are currently running 1.20.0 diff --git a/internal/core/testdata/test-check-version-up-to-date-version.stderr.golden b/internal/core/testdata/test-check-version-up-to-date-version.stderr.golden new file mode 100644 index 0000000000..c53f61a392 --- /dev/null +++ b/internal/core/testdata/test-check-version-up-to-date-version.stderr.golden @@ -0,0 +1,3 @@ +DEBUG: 2019/12/09 16:04:07 marshalling type '*core.SuccessResult' +DEBUG: 2019/12/09 16:04:07 version is up to date (99.99.0) +DEBUG: 2019/12/09 16:04:07 skipping telemetry report diff --git a/internal/core/testing.go b/internal/core/testing.go index f80e240969..757fd747d8 100644 --- a/internal/core/testing.go +++ b/internal/core/testing.go @@ -7,6 +7,7 @@ import ( "os" "path" "path/filepath" + "regexp" "strings" "testing" "text/template" @@ -89,6 +90,9 @@ type TestConfig struct { // Run tests in parallel. DisableParallel bool + + // Fake build info for this test. + BuildInfo BuildInfo } // getTestFilePath returns a valid filename path based on the go test name and suffix. (Take care of non fs friendly char) @@ -166,7 +170,7 @@ func Test(config *TestConfig) func(t *testing.T) { _, result, err := Bootstrap(&BootstrapConfig{ Args: strings.Split(cmdTemplate(cmd), " "), Commands: config.Commands, - BuildInfo: &BuildInfo{}, + BuildInfo: &config.BuildInfo, Stdout: stdoutBuffer, Stderr: stderrBuffer, Client: client, @@ -193,7 +197,7 @@ func Test(config *TestConfig) func(t *testing.T) { exitCode, result, err := Bootstrap(&BootstrapConfig{ Args: strings.Split(cmdTemplate(config.Cmd), " "), Commands: config.Commands, - BuildInfo: &BuildInfo{}, + BuildInfo: &config.BuildInfo, Stdout: stdout, Stderr: stderr, Client: client, @@ -261,7 +265,7 @@ func TestCheckGolden() TestCheck { func testGolden(t *testing.T, goldenPath string, actual []byte) { actualIsEmpty := len(actual) == 0 - + actual = uniformLogTimestamps(actual) if UpdateGoldens { if actualIsEmpty { _ = os.Remove(goldenPath) @@ -280,6 +284,12 @@ func testGolden(t *testing.T, goldenPath string, actual []byte) { } } +var regLogTimestamp = regexp.MustCompile(`((\d)+\/(\d)+\/(\d)+ (\d)+\:(\d)+\:(\d)+)`) + +func uniformLogTimestamps(input []byte) []byte { + return regLogTimestamp.ReplaceAll(input, []byte("2019/12/09 16:04:07")) +} + // getHTTPRecoder creates a new httpClient that records all HTTP requests in a cassette. // This cassette is then replayed whenever tests are executed again. This means that once the // requests are recorded in the cassette, no more real HTTP request must be made to run the tests. diff --git a/internal/core/validate.go b/internal/core/validate.go index 01b5588a4c..0265aaee87 100644 --- a/internal/core/validate.go +++ b/internal/core/validate.go @@ -38,7 +38,7 @@ func validateArgValues(cmd *Command, cmdArgs interface{}) error { fieldName = strings.ReplaceAll(fieldName, "."+mapSchema, "") fieldValue, fieldExists := getValueForFieldByName(cmdArgs, fieldName) if !fieldExists { - logger.Warningf("could not validate arg value for '%v': invalid fieldName: %v", argSpec.Name, fieldName) + logger.Debugf("could not validate arg value for '%v': invalid fieldName: %v", argSpec.Name, fieldName) continue } validateFunc := DefaultArgSpecValidateFunc() diff --git a/internal/namespaces/instance/v1/custom_server_create.go b/internal/namespaces/instance/v1/custom_server_create.go index b9bbc680a2..48326673a6 100644 --- a/internal/namespaces/instance/v1/custom_server_create.go +++ b/internal/namespaces/instance/v1/custom_server_create.go @@ -206,7 +206,7 @@ func instanceServerCreateRun(ctx context.Context, argsI interface{}) (i interfac serverReq.PublicIP = scw.StringPtr(args.IP) case net.ParseIP(args.IP) != nil: // Find the corresponding flexible IP UUID. - logger.Infof("finding public IP UUID from address: %s", args.IP) + logger.Debugf("finding public IP UUID from address: %s", args.IP) res, err := apiInstance.GetIP(&instance.GetIPRequest{ Zone: args.Zone, IP: args.IP, @@ -294,7 +294,7 @@ func instanceServerCreateRun(ctx context.Context, argsI interface{}) (i interfac // IP // if needIPCreation { - logger.Infof("creating IP") + logger.Debugf("creating IP") res, err := apiInstance.CreateIP(&instance.CreateIPRequest{ Zone: args.Zone, Organization: args.OrganizationID, @@ -303,18 +303,18 @@ func instanceServerCreateRun(ctx context.Context, argsI interface{}) (i interfac return nil, fmt.Errorf("error while creating your public IP: %s", err) } serverReq.PublicIP = scw.StringPtr(res.IP.ID) - logger.Infof("IP created: %s", serverReq.PublicIP) + logger.Debugf("IP created: %s", serverReq.PublicIP) } // // Server // - logger.Infof("creating server") + logger.Debugf("creating server") serverRes, err := apiInstance.CreateServer(serverReq) if err != nil { if needIPCreation && serverReq.PublicIP != nil { // Delete the created IP - logger.Infof("deleting created IP: %s", serverReq.PublicIP) + logger.Debugf("deleting created IP: %s", serverReq.PublicIP) err := apiInstance.DeleteIP(&instance.DeleteIPRequest{ Zone: args.Zone, IP: *serverReq.PublicIP, @@ -327,13 +327,13 @@ func instanceServerCreateRun(ctx context.Context, argsI interface{}) (i interfac return nil, fmt.Errorf("cannot create the server: %s", err) } server := serverRes.Server - logger.Infof("server created %s", server.ID) + logger.Debugf("server created %s", server.ID) // // Start server by default // if !args.Stopped { - logger.Infof("starting server") + logger.Debugf("starting server") _, err := apiInstance.ServerAction(&instance.ServerActionRequest{ Zone: args.Zone, ServerID: server.ID, @@ -342,7 +342,7 @@ func instanceServerCreateRun(ctx context.Context, argsI interface{}) (i interfac if err != nil { logger.Warningf("Cannot start the server: %s. Note that the server is successfully created.", err) } else { - logger.Infof("server started") + logger.Debugf("server started") } } From 92f6850673ea8823c6538b0a609fa96e523e3505 Mon Sep 17 00:00:00 2001 From: Olivier CANO Date: Thu, 6 Feb 2020 11:21:51 +0100 Subject: [PATCH 5/5] add comments --- internal/core/bootstrap.go | 2 +- internal/core/testing.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/core/bootstrap.go b/internal/core/bootstrap.go index c318eb2d2c..a651a775e0 100644 --- a/internal/core/bootstrap.go +++ b/internal/core/bootstrap.go @@ -84,7 +84,7 @@ func Bootstrap(config *BootstrapConfig) (exitCode int, result interface{}, err e }() // Check CLI new version when exiting the bootstrap - defer func() { + defer func() { // if we plan to remove defer, do not forget logger is not set until cobra pre init func config.BuildInfo.checkVersion() }() diff --git a/internal/core/testing.go b/internal/core/testing.go index 757fd747d8..d034028f79 100644 --- a/internal/core/testing.go +++ b/internal/core/testing.go @@ -265,6 +265,8 @@ func TestCheckGolden() TestCheck { func testGolden(t *testing.T, goldenPath string, actual []byte) { actualIsEmpty := len(actual) == 0 + + // In order to avoid diff in goldens we set all timestamp to the same date actual = uniformLogTimestamps(actual) if UpdateGoldens { if actualIsEmpty { @@ -286,6 +288,7 @@ func testGolden(t *testing.T, goldenPath string, actual []byte) { var regLogTimestamp = regexp.MustCompile(`((\d)+\/(\d)+\/(\d)+ (\d)+\:(\d)+\:(\d)+)`) +// uniformLogTimestamps replace all log timestamp to the date "2019/12/09 16:04:07" func uniformLogTimestamps(input []byte) []byte { return regLogTimestamp.ReplaceAll(input, []byte("2019/12/09 16:04:07")) }