diff --git a/cmd/root.go b/cmd/root.go index fea7c88b..0ac38613 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -16,7 +16,6 @@ package cmd import ( - "fmt" "os" "strings" @@ -32,11 +31,9 @@ import ( "github.com/yugabyte/ybm-cli/cmd/signup" "github.com/yugabyte/ybm-cli/cmd/util" "github.com/yugabyte/ybm-cli/cmd/vpc" - ybmAuthClient "github.com/yugabyte/ybm-cli/internal/client" - "github.com/yugabyte/ybm-cli/internal/formatter" + "github.com/yugabyte/ybm-cli/internal/log" "github.com/yugabyte/ybm-cli/internal/releases" - "golang.org/x/mod/semver" ) var ( @@ -59,15 +56,7 @@ var rootCmd = &cobra.Command{ if strings.HasPrefix(cmd.CommandPath(), "ybm completion") { return } - // Don't print any error if we are not able to fetch the latest release - latestVersion, err := releases.GetLatestRelease() - if err == nil { - currentVersion := ybmAuthClient.GetVersion() - if semver.Compare(currentVersion, latestVersion) == -1 { - message := fmt.Sprintf("A newer version is available. Please upgrade to the latest version %s\n", latestVersion) - logrus.Println(formatter.Colorize(message, formatter.GREEN_COLOR)) - } - } + releases.PrintUpgradeMessageIfNeeded() }, } diff --git a/go.mod b/go.mod index 4d71ba59..0dae2e9f 100644 --- a/go.mod +++ b/go.mod @@ -13,8 +13,8 @@ require ( github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf github.com/jayco/go-emoji-flag v0.0.0-20190810054606-01604da018da github.com/mattn/go-runewidth v0.0.14 - github.com/onsi/ginkgo/v2 v2.9.1 - github.com/onsi/gomega v1.27.4 + github.com/onsi/ginkgo/v2 v2.9.2 + github.com/onsi/gomega v1.27.5 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.0 @@ -35,7 +35,7 @@ require ( github.com/cloudflare/circl v1.1.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-logr/logr v1.2.3 // indirect - github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-querystring v1.1.0 // indirect diff --git a/go.sum b/go.sum index e8b14d7a..db8130c7 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/golang-jwt/jwt/v5 v5.0.0-rc.1 h1:tDQ1LjKga657layZ4JLsRdxgvupebc0xuPwRNuTfUgs= github.com/golang-jwt/jwt/v5 v5.0.0-rc.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -205,10 +205,10 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= -github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= -github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= +github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= +github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= +github.com/onsi/gomega v1.27.5 h1:T/X6I0RNFw/kTqgfkZPcQ5KU6vCnWNBGdtrIx2dpGeQ= +github.com/onsi/gomega v1.27.5/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= @@ -251,6 +251,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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= diff --git a/internal/releases/releases.go b/internal/releases/releases.go index 27a65be1..1152bfb2 100644 --- a/internal/releases/releases.go +++ b/internal/releases/releases.go @@ -1,9 +1,30 @@ +// Licensed to Yugabyte, Inc. under one or more contributor license +// agreements. See the NOTICE file distributed with this work for +// additional information regarding copyright ownership. Yugabyte +// licenses this file to you under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + package releases import ( "context" + "fmt" + "strings" "github.com/google/go-github/v50/github" + "github.com/sirupsen/logrus" + ybmAuthClient "github.com/yugabyte/ybm-cli/internal/client" + "github.com/yugabyte/ybm-cli/internal/formatter" + "golang.org/x/mod/semver" ) const ( @@ -20,13 +41,37 @@ func GetLatestRelease() (string, error) { } githubReleases, _, err := client.Repositories.ListReleases(context.Background(), org, repo, opts) if err != nil { + logrus.Debugf("Error while fetching the latest release: %v", err) return "", err } for _, release := range githubReleases { + logrus.Debugf("Found Release: %s , Prerelease: %v", release.GetTagName(), release.GetPrerelease()) // Returning the first non-prerelease version - if !*release.Prerelease { + if !release.GetPrerelease() { return release.GetTagName(), nil } } return "", err } + +func PrintUpgradeMessageIfNeeded() { + // Don't print any error if we are not able to fetch the latest release + latestVersion, err := GetLatestRelease() + if err == nil { + currentVersion := ybmAuthClient.GetVersion() + logrus.Debugf("Current version: %s, Latest version: %s\n", currentVersion, latestVersion) + + if ShouldUpgrade(currentVersion, latestVersion) { + message := fmt.Sprintf("A newer version is available. Please upgrade to the latest version %s\n", latestVersion) + logrus.Println(formatter.Colorize(message, formatter.GREEN_COLOR)) + } + } +} + +func ShouldUpgrade(currentVersion string, latestVersion string) bool { + // Strip the leading 'v' from the version string + currentVersion = strings.TrimLeft(currentVersion, "v") + latestVersion = strings.TrimLeft(latestVersion, "v") + logrus.Debugf("[Stripped] Current version: %s, Latest version: %s\n", currentVersion, latestVersion) + return semver.Compare("v"+currentVersion, "v"+latestVersion) == -1 +} diff --git a/internal/releases/releases_suite_test.go b/internal/releases/releases_suite_test.go new file mode 100644 index 00000000..b4ab4a1e --- /dev/null +++ b/internal/releases/releases_suite_test.go @@ -0,0 +1,27 @@ +// Licensed to Yugabyte, Inc. under one or more contributor license +// agreements. See the NOTICE file distributed with this work for +// additional information regarding copyright ownership. Yugabyte +// licenses this file to you under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package releases_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestYbmCli(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Releases Suite") +} diff --git a/internal/releases/releases_test.go b/internal/releases/releases_test.go new file mode 100644 index 00000000..d54b1643 --- /dev/null +++ b/internal/releases/releases_test.go @@ -0,0 +1,50 @@ +// Licensed to Yugabyte, Inc. under one or more contributor license +// agreements. See the NOTICE file distributed with this work for +// additional information regarding copyright ownership. Yugabyte +// licenses this file to you under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package releases_test + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/yugabyte/ybm-cli/internal/log" + "github.com/yugabyte/ybm-cli/internal/releases" +) + +var _ = Describe("Releases", func() { + BeforeEach(func() { + log.SetLogLevel("", true) + log.SetDebugFormatter() + }) + + Context("when checking releases", func() { + DescribeTable("to check if should upgrade", + func(release1, release2 string, expected bool) { + Expect(releases.ShouldUpgrade(release1, release2)).To(Equal(expected)) + }, + Entry("Empty release", "", "", false), + Entry("Equal releases", "1.2.3", "1.2.3", false), + Entry("Release 1 is greater than release 2", "1.2.3", "1.2.2", false), + Entry("Release 1 is less than release 2", "1.2.3", "1.2.4", true), + Entry("[v1] Equal releases", "v1.2.3", "1.2.3", false), + Entry("[v2] Equal releases", "1.2.3", "v1.2.3", false), + Entry("[vv1] Equal releases", "vv1.2.3", "1.2.3", false), + Entry("[vv2] Equal releases", "1.2.3", "vv1.2.3", false), + Entry("[vv1vv2] Equal releases", "vv1.2.3", "vv1.2.3", false), + Entry("[v1]Release 1 is greater than release 2", "v1.2.3", "1.2.2", false), + Entry("[v2]Release 1 is less than release 2", "1.2.3", "v1.2.4", true), + Entry("[vv1]Release 1 is greater than release 2", "vv1.2.3", "1.2.2", false), + Entry("[vv2]Release 1 is less than release 2", "1.2.3", "vv1.2.4", true), + ) + }) +})