diff --git a/.golangci.yml b/.golangci.yml index af674dc..32cb7a7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -11,4 +11,5 @@ linters: - exhaustruct - varnamelen - musttag - - depguard \ No newline at end of file + - depguard + - gochecknoglobals \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index a7c2031..95aa9ac 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -25,13 +25,15 @@ import ( "github.com/maksim-paskal/hcloud-k8s-ctl/internal" "github.com/maksim-paskal/hcloud-k8s-ctl/pkg/api" "github.com/maksim-paskal/hcloud-k8s-ctl/pkg/config" + "github.com/maksim-paskal/hcloud-k8s-ctl/pkg/version" log "github.com/sirupsen/logrus" ) //nolint:gochecknoglobals var ( - gitVersion = "dev" - versionFlag = flag.Bool("version", false, "version") + gitVersion = "dev" + versionFlag = flag.Bool("version", false, "version") + checkNewVersion = flag.Bool("check-new-version", true, "check new version") ) func main() { //nolint:cyclop,funlen @@ -59,6 +61,12 @@ func main() { //nolint:cyclop,funlen log.SetLevel(logLevel) + if *checkNewVersion { + if err := version.CheckLatest(ctx, gitVersion); err != nil { + log.WithError(err).Warn("error check latest version") + } + } + if err := config.Check(); err != nil { log.WithError(err).Fatal("error checking config") } diff --git a/go.mod b/go.mod index 18c2bbb..8fc159f 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/maksim-paskal/hcloud-k8s-ctl go 1.21 require ( + github.com/hashicorp/go-version v1.6.0 github.com/hetznercloud/hcloud-go/v2 v2.5.1 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 diff --git a/go.sum b/go.sum index 0039931..a5ccc4e 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hetznercloud/hcloud-go/v2 v2.5.1 h1:tJQxd+Qyd9CwGOFL0og80zZ3a4Z5p9+iIRTnUPlvOgc= github.com/hetznercloud/hcloud-go/v2 v2.5.1/go.mod h1:y75vdFT0eNNnYyGWO55Qv0LI23kSgsQZl3Gyy0KMrI4= github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= diff --git a/pkg/version/version.go b/pkg/version/version.go new file mode 100644 index 0000000..3400613 --- /dev/null +++ b/pkg/version/version.go @@ -0,0 +1,74 @@ +/* +Copyright paskal.maksim@gmail.com +Licensed 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 version + +import ( + "context" + "net/http" + "strings" + "time" + + semver "github.com/hashicorp/go-version" + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" +) + +var versionClient = http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, +} + +const ( + httpTimeout = 10 * time.Second + githubURL = "https://github.com/maksim-paskal/hcloud-k8s-ctl" + githubVersionLatest = githubURL + "/releases/latest" + githubVersionPrefix = githubURL + "/releases/tag/" +) + +func CheckLatest(ctx context.Context, myVersion string) error { + ctx, cancel := context.WithTimeout(ctx, httpTimeout) + defer cancel() + + currentVersion, err := semver.NewSemver(myVersion) + if err != nil { + return errors.Wrap(err, "error parse version") + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, githubVersionLatest, nil) + if err != nil { + return errors.Wrap(err, "error create request") + } + + resp, err := versionClient.Do(req) + if err != nil { + return errors.Wrap(err, "error do request") + } + + defer resp.Body.Close() + + versionURL := resp.Header.Get("Location") + + latestTag := strings.TrimPrefix(versionURL, githubVersionPrefix) + + versionGithub, err := semver.NewSemver(latestTag) + if err != nil { + return errors.Wrap(err, "error parse version") + } + + if currentVersion.Core().LessThan(versionGithub) { + log.Infof("new version available: %s", versionURL) + } + + return nil +} diff --git a/pkg/version/version_test.go b/pkg/version/version_test.go new file mode 100644 index 0000000..fc8911a --- /dev/null +++ b/pkg/version/version_test.go @@ -0,0 +1,29 @@ +/* +Copyright paskal.maksim@gmail.com +Licensed 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 version_test + +import ( + "context" + "testing" + + "github.com/maksim-paskal/hcloud-k8s-ctl/pkg/version" +) + +func TestVersion(t *testing.T) { + t.Parallel() + + err := version.CheckLatest(context.TODO(), "0.3.0-86191bc-1701335786") + if err != nil { + t.Fatal(err) + } +}