diff --git a/build/Makefile.build b/build/Makefile.build index 6a51e3f8..fa763ab5 100644 --- a/build/Makefile.build +++ b/build/Makefile.build @@ -6,7 +6,7 @@ CURRENT_ARCH := $(shell uname -s | tr '[:upper:]' '[:lower:]') export OWNER := elastic export REPO := ecctl -DEFAULT_LDFLAGS ?= -X main.version=$(VERSION)-dev -X main.commit=$(shell git rev-parse HEAD) -X main.owner=$(OWNER) -X main.repo=$(REPO) +DEFAULT_LDFLAGS ?= -X main.version=$(VERSION)-dev -X main.commit=$(shell git rev-parse HEAD) -X main.owner=$(OWNER) -X main.repo=$(REPO) -X main.built=$(shell date -u +%a_%d_%b_%H:%M:%S_%Y) REPORT_PATH ?= reports TEST_UNIT_FLAGS ?= -timeout 10s -p 4 -race -cover -coverprofile=$(REPORT_PATH)/c.out diff --git a/cmd/root.go b/cmd/root.go index ec2e039c..4e782c59 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -54,8 +54,8 @@ var ( ) var ( - version, commit, owner, repo string - excludedApplicationCommands = []string{ + versionInfo ecctl.VersionInfo + excludedApplicationCommands = []string{ "help", "version", "generate", "docs", "completions", "init", } messageErrHasNoPreRunCheck = "command %s/%s has no PreRunE check set" @@ -81,11 +81,11 @@ var RootCmd = &cobra.Command{ // Execute adds all child commands to the root command sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. // It returns the statuscode to be used by os.Exit. -func Execute(v, c, o, r string) int { +func Execute(v ecctl.VersionInfo) int { defer stopDebug(defaultViper) populateValidArgs(RootCmd) - version, commit, owner, repo = v, c, o, r + versionInfo = v if err := RootCmd.Execute(); err != nil { fmt.Fprintln(RootCmd.OutOrStderr(), err) diff --git a/cmd/version.go b/cmd/version.go index 7e5f6314..e9ed2d53 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -19,12 +19,15 @@ package cmd import ( "fmt" + "io" "os" "runtime" "github.com/elastic/uptd" "github.com/pkg/errors" "github.com/spf13/cobra" + + "github.com/elastic/ecctl/pkg/ecctl" ) const ( @@ -44,34 +47,9 @@ var versionCmd = &cobra.Command{ Short: "Shows ecctl version", PreRunE: cobra.MaximumNArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - fmt.Printf("%s %s (build %s)\n", RootCmd.Use, version, commit) - - githubUpdateProvider, err := uptd.NewGithubProvider(owner, repo, githubToken()) - if err != nil { - fmt.Fprintln(cmd.OutOrStdout(), errors.Wrap(err, errWrapError.Error())) - return nil - } + fmt.Fprint(cmd.OutOrStdout(), versionInfo) - uptodate, err := uptd.New(githubUpdateProvider, version) - if err != nil { - fmt.Fprintln(cmd.OutOrStdout(), errors.Wrap(err, errWrapError.Error())) - return nil - } - - res, err := uptodate.Check() - if err != nil { - fmt.Fprintln(cmd.OutOrStdout(), errors.Wrap(err, errWrapError.Error())) - return nil - } - - if res.NeedsUpdate { - var message = fmt.Sprintf(updateFmt, RootCmd.Name(), - res.Latest.Version.String(), res.Latest.URL, - ) - fmt.Fprintln(cmd.OutOrStdout(), message) - } - - return nil + return checkUpdate(versionInfo, cmd.OutOrStderr()) }, } @@ -88,6 +66,36 @@ func githubToken() string { return "" } +func checkUpdate(version ecctl.VersionInfo, device io.Writer) error { + githubUpdateProvider, err := uptd.NewGithubProvider( + version.Organization, version.Repository, githubToken(), + ) + if err != nil { + fmt.Fprintln(device, errors.Wrap(err, errWrapError.Error())) + return nil + } + + uptodate, err := uptd.New(githubUpdateProvider, version.Version) + if err != nil { + fmt.Fprintln(device, errors.Wrap(err, errWrapError.Error())) + return nil + } + + res, err := uptodate.Check() + if err != nil { + fmt.Fprintln(device, errors.Wrap(err, errWrapError.Error())) + return nil + } + + if res.NeedsUpdate { + var message = fmt.Sprintf(updateFmt, RootCmd.Name(), + res.Latest.Version.String(), res.Latest.URL, + ) + fmt.Fprintln(device, message) + } + return nil +} + func init() { RootCmd.AddCommand(versionCmd) } diff --git a/go.mod b/go.mod index bf894d5b..2920050a 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/chzyer/logex v1.1.10 // indirect github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect github.com/davecgh/go-spew v1.1.1 - github.com/elastic/cloud-sdk-go v1.0.0-bc4 + github.com/elastic/cloud-sdk-go v1.0.0-bc5 github.com/elastic/uptd v1.0.0 github.com/ghodss/yaml v1.0.0 github.com/go-openapi/runtime v0.19.8 diff --git a/go.sum b/go.sum index fb4cc697..a544cb17 100644 --- a/go.sum +++ b/go.sum @@ -51,8 +51,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/elastic/cloud-sdk-go v1.0.0-bc4 h1:8Gc/gFos+dJv992c8FQ06X9Mx080p2ceuiB1dUPWeUA= -github.com/elastic/cloud-sdk-go v1.0.0-bc4/go.mod h1:19tuRaJglGTECDJfiWEDMOVj23ZL+9+YYoIV1fZIGzc= +github.com/elastic/cloud-sdk-go v1.0.0-bc5 h1:POlV6bafKwT728xJy+did8Q1QlDweE0z/lVfgRY6ic4= +github.com/elastic/cloud-sdk-go v1.0.0-bc5/go.mod h1:19tuRaJglGTECDJfiWEDMOVj23ZL+9+YYoIV1fZIGzc= github.com/elastic/uptd v1.0.0 h1:oUhbbTK6hjFYB5w5dwjo1HtbqrWyLiqj+6Sb05oawU8= github.com/elastic/uptd v1.0.0/go.mod h1:2Pm07gLal/a/gTPq3el2QgOjoxu97pB2I17AprXxa48= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= diff --git a/main.go b/main.go index b7058e28..49a0e0c2 100644 --- a/main.go +++ b/main.go @@ -20,7 +20,10 @@ package main import ( "os" + "github.com/elastic/cloud-sdk-go/pkg/api" + "github.com/elastic/ecctl/cmd" + "github.com/elastic/ecctl/pkg/ecctl" ) var ( @@ -28,10 +31,18 @@ var ( commit string owner string repo string + built string ) func main() { os.Exit( - cmd.Execute(version, commit, owner, repo), + cmd.Execute(ecctl.VersionInfo{ + Version: version, + Commit: commit, + APIVersion: api.Version, + Built: built, + Organization: owner, + Repository: repo, + }), ) } diff --git a/pkg/ecctl/version.go b/pkg/ecctl/version.go new file mode 100644 index 00000000..28b0a74a --- /dev/null +++ b/pkg/ecctl/version.go @@ -0,0 +1,60 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. 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 ecctl + +import ( + "bytes" + "fmt" + "runtime" + "strings" + "text/tabwriter" +) + +// VersionInfo contains detailed information about the binary. +type VersionInfo struct { + Version string + APIVersion string + Commit string + Built string + + // Non Displayed fields + Repository string + Organization string +} + +func (v VersionInfo) String() string { + buf := new(bytes.Buffer) + + w := tabwriter.NewWriter(buf, 2, 2, 3, ' ', 0) + + var commit = v.Commit + if len(commit) >= 8 { + commit = commit[:8] + } + + fmt.Fprintln(w, "Version:\t", v.Version) + fmt.Fprintln(w, "Client API Version:\t", v.APIVersion) + fmt.Fprintln(w, "Go version:\t", runtime.Version()) + fmt.Fprintln(w, "Git commit:\t", commit) + fmt.Fprintln(w, "Built:\t", strings.ReplaceAll(v.Built, "_", " ")) + fmt.Fprintln(w, "OS/Arch:\t", runtime.GOOS, "/", runtime.GOARCH) + + w.Flush() + + return buf.String() +} diff --git a/pkg/ecctl/version_test.go b/pkg/ecctl/version_test.go new file mode 100644 index 00000000..12cbe189 --- /dev/null +++ b/pkg/ecctl/version_test.go @@ -0,0 +1,59 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. 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 ecctl + +import ( + "fmt" + "runtime" + "testing" +) + +const vTemplate = `Version: 1.0.0 +Client API Version: 2.4.2 +Go version: %s +Git commit: 12345678 +Built: Fri 15 Nov 09:24:14 2019 +OS/Arch: %s / %s +` + +func TestVersionInfo_String(t *testing.T) { + tests := []struct { + name string + fields VersionInfo + want string + }{ + { + name: "Prints the version", + fields: VersionInfo{ + Version: "1.0.0", + APIVersion: "2.4.2", + Commit: "12345678910", + Built: "Fri_15_Nov_09:24:14_2019", + }, + want: fmt.Sprintf(vTemplate, runtime.Version(), runtime.GOOS, runtime.GOARCH), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := tt.fields + if got := v.String(); got != tt.want { + t.Errorf("VersionInfo.String() = %v, want %v", got, tt.want) + } + }) + } +}