Skip to content

Commit

Permalink
impl update checker (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
ktr authored Feb 11, 2018
1 parent b332725 commit 7b0affd
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
SHELL := /bin/bash
VERSION := $(shell grep 'version = ' < main.go | sed -r 's/\sversion = "(.*)".*/\1/')
VERSION := $(shell grep 'Version = ' < meta/meta.go | sed -r 's/\sVersion = "(.*)".*/\1/')

.PHONY: version
version:
Expand Down
41 changes: 39 additions & 2 deletions adapter/controller/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package controller

import (
"bytes"
"context"
"fmt"
"path/filepath"
"strconv"
Expand All @@ -12,8 +13,10 @@ import (
"github.com/ktr0731/evans/adapter/gateway"
"github.com/ktr0731/evans/adapter/parser"
"github.com/ktr0731/evans/adapter/presenter"
"github.com/ktr0731/evans/adapter/update_checker"
"github.com/ktr0731/evans/config"
"github.com/ktr0731/evans/entity"
"github.com/ktr0731/evans/meta"
"github.com/ktr0731/evans/usecase"
"github.com/ktr0731/evans/usecase/port"
isatty "github.com/mattn/go-isatty"
Expand Down Expand Up @@ -112,6 +115,19 @@ func (c *CLI) Run(args []string) int {
DynamicBuilder: gateway.NewDynamicBuilder(),
}

// check latest update
var tag *update_checker.ReleaseTag
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // for non-zero return value
go func() {
defer cancel()
var err error
tag, err = update_checker.NewUpdateChecker().Check(ctx)
if err != nil {
tag.CurrentIsLatest = true
}
}()

if isCommandLineMode(c.options) {
var in io.Reader
if c.options.File != "" {
Expand Down Expand Up @@ -153,17 +169,38 @@ func (c *CLI) Run(args []string) int {
ui = newREPLUI("")
}
r := NewREPL(c.config.REPL, env, ui, interactor)
defer r.Close()

if err := r.Start(); err != nil {
c.Error(err)
return 1
}
}

// cancel update checking
cancel()
<-ctx.Done()

if tag != nil && !tag.CurrentIsLatest {
c.printUpdateInfo(tag.LatestVersion)
}

return 0
}

var updateInfoFormat string = `
new update available:
old version: %s
new version: %s
$ brew upgrade evans
$ go get -u github.com/ktr0731/evans
$ curl -sL https://github.com/ktr0731/evans/releases/download/%s/evans_{OS}_{ARCH}.tar.gz | tar xf -
`

func (c *CLI) printUpdateInfo(latestVersion string) {
c.ui.Println(fmt.Sprintf(updateInfoFormat, meta.Version, latestVersion, latestVersion))
}

func checkPrecondition(config *config.Config, opt *Options) error {
if len(opt.Proto) == 0 {
return errors.New("invalid argument")
Expand Down
20 changes: 13 additions & 7 deletions adapter/controller/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ import (
"os"
"testing"

"github.com/ktr0731/evans/tests/helper"
"github.com/ktr0731/evans/config"
"github.com/stretchr/testify/require"
)

func TestCLI(t *testing.T) {
newConfig := func() *config.Config {
return &config.Config{
Default: &config.Default{},
}
}

t.Run("proto path (option)", func(t *testing.T) {
conf := helper.TestConfig()
conf := newConfig()
opt := &Options{
Path: []string{"foo", "foo", "bar"},
}
Expand All @@ -20,7 +26,7 @@ func TestCLI(t *testing.T) {
})

t.Run("proto path (config)", func(t *testing.T) {
conf := helper.TestConfig()
conf := newConfig()
conf.Default.ProtoPath = []string{"foo", "foo", "bar"}
opt := &Options{}
paths, err := collectProtoPaths(conf, opt)
Expand All @@ -29,7 +35,7 @@ func TestCLI(t *testing.T) {
})

t.Run("proto path (both)", func(t *testing.T) {
conf := helper.TestConfig()
conf := newConfig()
conf.Default.ProtoPath = []string{"foo", "foo", "bar"}
opt := &Options{
Path: []string{"foo", "baz", "bar"},
Expand All @@ -40,7 +46,7 @@ func TestCLI(t *testing.T) {
})

t.Run("proto path (from file)", func(t *testing.T) {
conf := helper.TestConfig()
conf := newConfig()
opt := &Options{
Proto: []string{"./hoge", "./foo/bar"},
}
Expand All @@ -59,7 +65,7 @@ func TestCLI(t *testing.T) {
}

t.Run("proto path (env)", func(t *testing.T) {
conf := helper.TestConfig()
conf := newConfig()
opt := &Options{
Proto: []string{"$hoge/foo", "/fuga/bar"},
}
Expand All @@ -74,7 +80,7 @@ func TestCLI(t *testing.T) {
})

t.Run("error/proto path", func(t *testing.T) {
conf := helper.TestConfig()
conf := newConfig()
opt := &Options{
Proto: []string{"foo bar"},
}
Expand Down
6 changes: 2 additions & 4 deletions adapter/controller/repl.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func NewREPL(config *config.REPL, env *entity.Env, ui ui, inputPort port.InputPo
"show": &showCommand{inputPort},
"header": &headerCommand{inputPort},
}

repl := &REPL{
ui: ui,
config: config,
Expand Down Expand Up @@ -107,10 +108,7 @@ func (r *REPL) eval(l string) (string, error) {
func (r *REPL) Start() error {
r.printSplash(r.config.SplashTextPath)
r.prompt.Run()
return nil
}

func (r *REPL) Close() error {
r.ui.InfoPrintln("Good Bye :)")
return nil
}
Expand All @@ -137,7 +135,7 @@ Available commands:
Show more details:
<command> --help
`, cmdText)
r.ui.InfoPrintln(strings.TrimRight(msg, "\n"))
r.ui.Println(strings.TrimRight(msg, "\n"))
}

func (r *REPL) getPrompt() string {
Expand Down
35 changes: 35 additions & 0 deletions adapter/update_checker/checker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package update_checker

import (
"context"

"github.com/ktr0731/evans/meta"
)

type UpdateChecker struct {
client client
version string
}

func NewUpdateChecker() *UpdateChecker {
return &UpdateChecker{
client: newGitHubClient(),
version: meta.Version,
}
}

type ReleaseTag struct {
LatestVersion string
CurrentIsLatest bool
}

func (u *UpdateChecker) Check(ctx context.Context) (*ReleaseTag, error) {
tag, err := u.client.FetchLatestTag(ctx)
if err != nil {
return nil, err
}
return &ReleaseTag{
LatestVersion: tag,
CurrentIsLatest: tag == u.version,
}, nil
}
49 changes: 49 additions & 0 deletions adapter/update_checker/checker_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package update_checker

import (
"context"
"errors"
"testing"

"github.com/stretchr/testify/require"
)

type mockClient struct {
tag string
err error
}

func (c *mockClient) FetchLatestTag(ctx context.Context) (string, error) {
return c.tag, c.err
}

func TestUpdateChecker(t *testing.T) {
client := &mockClient{
tag: "0.1.0",
}
u := &UpdateChecker{
client: client,
version: "0.1.0",
}

t.Run("latest", func(t *testing.T) {
tag, err := u.Check(context.TODO())
require.NoError(t, err)
require.True(t, tag.CurrentIsLatest)
require.Equal(t, "0.1.0", tag.LatestVersion)
})

t.Run("old", func(t *testing.T) {
client.tag = "0.1.1"
tag, err := u.Check(context.TODO())
require.NoError(t, err)
require.False(t, tag.CurrentIsLatest)
require.Equal(t, "0.1.1", tag.LatestVersion)
})

t.Run("error", func(t *testing.T) {
client.err = errors.New("an error")
_, err := u.Check(context.TODO())
require.Error(t, err)
})
}
34 changes: 34 additions & 0 deletions adapter/update_checker/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package update_checker

import (
"context"

"github.com/google/go-github/github"
)

const (
owner = "ktr0731"
repo = "evans"
)

type client interface {
FetchLatestTag(context.Context) (string, error)
}

type gitHubClient struct {
client *github.Client
}

func newGitHubClient() client {
return &gitHubClient{
client: github.NewClient(nil),
}
}

func (c *gitHubClient) FetchLatestTag(ctx context.Context) (string, error) {
r, _, err := c.client.Repositories.GetLatestRelease(ctx, owner, repo)
if err != nil {
return "", err
}
return r.GetTagName(), nil
}
10 changes: 9 additions & 1 deletion glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 2 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@ import (
"os"

"github.com/ktr0731/evans/adapter/controller"
)

const (
name = "evans"
version = "0.2.4"
"github.com/ktr0731/evans/meta"
)

func main() {
os.Exit(run(controller.NewCLI(name, version)))
os.Exit(run(controller.NewCLI(meta.Name, meta.Version)))
}

func run(runnable controller.Runnable) int {
Expand Down
6 changes: 6 additions & 0 deletions meta/meta.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package meta

const (
Name = "evans"
Version = "0.2.5"
)

0 comments on commit 7b0affd

Please sign in to comment.