Skip to content

Commit

Permalink
feat: add new release check (#486)
Browse files Browse the repository at this point in the history
* feat: add new release check
  • Loading branch information
sunny0826 committed Aug 16, 2022
1 parent 1556a76 commit 40f01d7
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 23 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/e2e-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:

- name: Get current date
id: date
run: echo "::set-output name=date::$(date +'%Y-%m-%dT%H:%M:%S')"
run: echo "::set-output name=date::$(date +'%Y-%m-%d')"

- name: Setup Go
uses: actions/setup-go@v3
Expand All @@ -41,9 +41,9 @@ jobs:
- name: Go build
run: |
go build -ldflags="-X github.com/sunny0826/kubecm/cmd.kubecmVersion=${{ github.run_id }} \
-X github.com/sunny0826/kubecm/cmd.gitCommit=${{ github.sha }} \
-X 'github.com/sunny0826/kubecm/cmd.buildDate=${{ steps.date.outputs.date }}'" \
go build -ldflags="-X github.com/sunny0826/kubecm/version.Version=${{ github.run_id }} \
-X github.com/sunny0826/kubecm/version.GitRevision=${{ github.sha }} \
-X 'github.com/sunny0826/kubecm/version.BuildDate=${{ steps.date.outputs.date }}'" \
-o bin/kubecm .
- name: Setup Kind
Expand Down
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
builds:
- env:
- CGO_ENABLED=0
ldflags: -s -X github.com/sunny0826/kubecm/cmd.kubecmVersion={{.Version}} -X github.com/sunny0826/kubecm/cmd.gitCommit={{.Commit}} -X github.com/sunny0826/kubecm/cmd.buildDate={{.Date}}
ldflags: -s -X github.com/sunny0826/kubecm/version.Version={{.Version}} -X github.com/sunny0826/kubecm/version.GitRevision={{.ShortCommit}} -X github.com/sunny0826/kubecm/version.BuildDate={{ time "2006-01-02" }}
goos:
- linux
- darwin
Expand Down
14 changes: 9 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ BUILD_TARGET_PKG_FILE_PATH=$(BUILD_TARGET)/$(BUILD_TARGET_DIR_NAME)

GO_ENV=CGO_ENABLED=0
GO_MODULE=GO111MODULE=on
VERSION_PKG=github.com/sunny0826/kubecm/cmd
GO_FLAGS=-ldflags="-X ${VERSION_PKG}.kubecmVersion=$(KUBECM_VERSION) -X ${VERSION_PKG}.gitCommit=$(GITCOMMIT) -X '${VERSION_PKG}.buildDate=`date`'"
GO=$(GO_ENV) $(GO_MODULE) go
VERSION_PKG=github.com/sunny0826/kubecm/version
GO_FLAGS=-ldflags="-X ${VERSION_PKG}.Version=$(KUBECM_VERSION) -X ${VERSION_PKG}.GitRevision=$(GITCOMMIT) -X ${VERSION_PKG}.BuildDate=$(shell date -u +'%Y-%m-%d')"
GO=go

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
Expand All @@ -29,7 +29,7 @@ GOBIN=$(shell go env GOBIN)
endif

ifeq ($(GOOS), linux)
GO_FLAGS=-ldflags="-linkmode external -extldflags -static -X ${VERSION_PKG}.kubecmVersion=$(KUBECM_VERSION) -X ${VERSION_PKG}.gitCommit=$(GITCOMMIT) -X '${VERSION_PKG}.buildDate=`date`'"
GO_FLAGS=-ldflags="-linkmode external -extldflags -static -X ${VERSION_PKG}.Version=$(KUBECM_VERSION) -X ${VERSION_PKG}.GitRevision=$(GITCOMMIT) -X ${VERSION_PKG}.BuildDate=$(shell date -u +'%Y-%m-%d')"
endif

build: pre_build
Expand Down Expand Up @@ -99,4 +99,8 @@ ifeq (, $(shell which golangci-lint))
GOLANGCILINT=$(GOBIN)/golangci-lint
else
GOLANGCILINT=$(shell which golangci-lint)
endif
endif

goreleaser-snapshot:
goreleaser build --single-target --snapshot --rm-dist
dist/kubecm_darwin_amd64/kubecm version
38 changes: 25 additions & 13 deletions cmd/version.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
package cmd

import (
"runtime"
"fmt"
"strings"

"github.com/mgutz/ansi"
"github.com/spf13/cobra"
v "github.com/sunny0826/kubecm/version"
)

// VersionCommand version cmd struct
type VersionCommand struct {
BaseCommand
}

var (
kubecmVersion = "unknown"
goos = runtime.GOOS
goarch = runtime.GOARCH
)

// version returns the version of kubecm.
type version struct {
// kubecmVersion is a kubecm binary version.
KubecmVersion string `json:"kubecmVersion"`
// GitRevision is the commit of repo
GitRevision string `json:"gitRevision"`
// BuildDate is the build date of kubecm binary.
BuildDate string `json:"buildDate"`
// GoOs holds OS name.
GoOs string `json:"goOs"`
// GoArch holds architecture name.
Expand All @@ -35,18 +36,29 @@ func (vc *VersionCommand) Init() {
Long: "Print version info",
Aliases: []string{"v"},
Run: func(cmd *cobra.Command, args []string) {
cmd.Printf("Version: %s\n", getVersion().KubecmVersion)
cmd.Printf("GoOs: %s\n", getVersion().GoOs)
cmd.Printf("GoArch: %s\n", getVersion().GoArch)
fmt.Printf("%s: %s\n",
ansi.Color("Version:", "blue"),
ansi.Color(strings.TrimPrefix(getVersion().KubecmVersion+fmt.Sprintf("(%s)", getVersion().BuildDate), "v"), "white+h"))
fmt.Printf("%s: %s\n",
ansi.Color("GitRevision:", "blue"),
ansi.Color(getVersion().GitRevision, "white+h"))
fmt.Printf("%s: %s\n",
ansi.Color("GoOs:", "blue"),
ansi.Color(getVersion().GoOs, "white+h"))
fmt.Printf("%s: %s\n",
ansi.Color("GoArch:", "blue"),
ansi.Color(getVersion().GoArch, "white+h"))
},
}
}

// getVersion returns version.
func getVersion() version {
return version{
kubecmVersion,
goos,
goarch,
v.Version,
v.GitRevision,
v.BuildDate,
v.GoOs,
v.GoArch,
}
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ require (
github.com/alibabacloud-go/tea v1.1.19
github.com/alibabacloud-go/tea-utils v1.4.3 // indirect
github.com/bndr/gotabulate v1.1.3-0.20170315142410-bc555436bfd5
github.com/cli/safeexec v1.0.0
github.com/daviddengcn/go-colortext v1.0.0
github.com/imdario/mergo v0.3.13
github.com/manifoldco/promptui v0.3.2
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
github.com/pterm/pterm v0.12.45
github.com/rancher/norman v0.0.0-20200820172041-261460ee9088
github.com/rancher/rancher/pkg/client v0.0.0-20211110212758-cc2b8beb1473
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWs
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI=
github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
Expand Down Expand Up @@ -485,6 +487,8 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
Expand Down
53 changes: 53 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,69 @@ package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/sunny0826/kubecm/version"

"github.com/cli/safeexec"
"github.com/mgutz/ansi"
"github.com/sunny0826/kubecm/pkg/update"

"github.com/sunny0826/kubecm/cmd"
_ "k8s.io/client-go/plugin/pkg/client/auth/azure" // required for Azure
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // required for GKE
)

func main() {
kubecmVersion := version.Version

updateMessageChan := make(chan *update.ReleaseInfo)
go func() {
rel, _ := update.CheckForUpdate("sunny0826/kubecm", kubecmVersion)
updateMessageChan <- rel
}()
baseCommand := cmd.NewBaseCommand()
if err := baseCommand.CobraCmd().Execute(); err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1)
}
newRelease := <-updateMessageChan
if newRelease != nil {
fmt.Printf("\n\n%s %s → %s\n",
ansi.Color("A new release of kubecm is available:", "yellow"),
ansi.Color(strings.TrimPrefix(kubecmVersion, "v"), "cyan"),
ansi.Color(strings.TrimPrefix(newRelease.Version, "v"), "green"))
if isUnderHomebrew() {
fmt.Printf("To upgrade, run: %s\n", "brew update && brew upgrade kubecm")
}
fmt.Printf("%s\n\n",
ansi.Color(newRelease.URL, "yellow"))
}
}

// Check whether the gh binary was found under the Homebrew prefix
func isUnderHomebrew() bool {
brewExe, err := safeexec.LookPath("brew")
if err != nil {
return false
}

brewPrefixBytes, err := exec.Command(brewExe, "--prefix").Output()
if err != nil {
return false
}

path, err := exec.LookPath(os.Args[0])
if err != nil {
return false
}
kubecmBinary, err := filepath.Abs(path)
if err != nil {
return false
}

brewBinPrefix := filepath.Join(strings.TrimSpace(string(brewPrefixBytes)), "bin") + string(filepath.Separator)
return strings.HasPrefix(kubecmBinary, brewBinPrefix)
}
54 changes: 54 additions & 0 deletions pkg/update/update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package update

import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
)

// ReleaseInfo stores information about a release
// nolint:tagliatelle
type ReleaseInfo struct {
Version string `json:"tag_name"`
URL string `json:"html_url"`
PublishedAt time.Time `json:"published_at"`
}

// CheckForUpdate checks whether this software has had a newer release on GitHub
func CheckForUpdate(repo, currentVersion string) (*ReleaseInfo, error) {
releaseInfo, err := getLatestReleaseInfo(repo)
if err != nil {
return nil, err
}

if releaseInfo.Version != currentVersion {
return releaseInfo, nil
}
return nil, nil
}

func getLatestReleaseInfo(repo string) (*ReleaseInfo, error) {
var latestRelease ReleaseInfo
resp, err := http.Get(fmt.Sprintf("https://api.github.com/repos/%s/releases/latest", repo))
if err != nil {
return nil, err
}

if resp.StatusCode != 200 {
return nil, fmt.Errorf("unexpected response status code: %v", resp.StatusCode)
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}

err = json.Unmarshal(body, &latestRelease)
if err != nil {
return nil, err
}
return &latestRelease, nil
}
99 changes: 99 additions & 0 deletions pkg/update/update_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package update

import (
"reflect"
"testing"
"time"
)

func Test_getLatestReleaseInfo(t *testing.T) {
type args struct {
repo string
}
tests := []struct {
name string
args args
want *ReleaseInfo
wantErr bool
}{
// TODO: Add test cases.
{
name: "test lastest release info",
args: args{
repo: "sunny0826/kubectl-pod-lens",
},
want: &ReleaseInfo{
Version: "v0.2.2",
URL: "https://github.com/sunny0826/kubectl-pod-lens/releases/tag/v0.2.2",
PublishedAt: time.Date(2021, 8, 29, 10, 19, 42, 0, time.UTC),
},
},
{
name: "repo not found",
args: args{
repo: "bar/foo",
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := getLatestReleaseInfo(tt.args.repo)
if (err != nil) != tt.wantErr {
t.Errorf("getLatestReleaseInfo() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("getLatestReleaseInfo() got = %v, want %v", got, tt.want)
}
})
}
}

func TestCheckForUpdate(t *testing.T) {
type args struct {
repo string
currentVersion string
}
tests := []struct {
name string
args args
want *ReleaseInfo
wantErr bool
}{
// TODO: Add test cases.
{
name: "need update",
args: args{
repo: "sunny0826/kubectl-pod-lens",
currentVersion: "v0.2.1",
},
want: &ReleaseInfo{
Version: "v0.2.2",
URL: "https://github.com/sunny0826/kubectl-pod-lens/releases/tag/v0.2.2",
PublishedAt: time.Date(2021, 8, 29, 10, 19, 42, 0, time.UTC),
},
},
{
name: "do not need update",
args: args{
repo: "sunny0826/kubectl-pod-lens",
currentVersion: "v0.2.2",
},
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := CheckForUpdate(tt.args.repo, tt.args.currentVersion)
if (err != nil) != tt.wantErr {
t.Errorf("CheckForUpdate() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("CheckForUpdate() got = %v, want %v", got, tt.want)
}
})
}
}
Loading

0 comments on commit 40f01d7

Please sign in to comment.