From 1231ddd01cd831bc2ddf39ca4ed7b52199df4c79 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Mon, 2 Dec 2019 15:08:36 -0800 Subject: [PATCH] Add test --- api/client.go | 34 ++++++++++++++ command/root.go | 8 +++- main.go | 36 +++++++++++---- test/fixtures/latestRelease.json | 4 ++ update/checkForUpdate.go | 79 -------------------------------- update/update.go | 43 +++++++++++++++++ update/update_test.go | 36 +++++++++++++++ 7 files changed, 149 insertions(+), 91 deletions(-) create mode 100644 test/fixtures/latestRelease.json delete mode 100644 update/checkForUpdate.go create mode 100644 update/update.go create mode 100644 update/update_test.go diff --git a/api/client.go b/api/client.go index a3fa8e72a..e3e340a17 100644 --- a/api/client.go +++ b/api/client.go @@ -7,6 +7,7 @@ import ( "io" "io/ioutil" "net/http" + "path" ) // ClientOption represents an argument to NewClient @@ -98,6 +99,39 @@ func (c Client) GraphQL(query string, variables map[string]interface{}, data int return handleResponse(resp, data) } +// REST performs a REST request and parses the response. +func (c Client) REST(method string, p string, data interface{}) error { + url := path.Join("https://api.github.com/", p) + req, err := http.NewRequest(method, url, nil) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json; charset=utf-8") + + resp, err := c.http.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + success := resp.StatusCode >= 200 && resp.StatusCode < 300 + if !success { + return handleHTTPError(resp) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + err = json.Unmarshal(body, &data) + if err != nil { + return err + } + + return nil +} + func handleResponse(resp *http.Response, data interface{}) error { success := resp.StatusCode >= 200 && resp.StatusCode < 300 diff --git a/command/root.go b/command/root.go index 085d1758b..be46358e6 100644 --- a/command/root.go +++ b/command/root.go @@ -21,9 +21,9 @@ var BuildDate = "YYYY-MM-DD" func init() { RootCmd.Version = fmt.Sprintf("%s (%s)", strings.TrimPrefix(Version, "v"), BuildDate) - RootCmd.AddCommand(versionCmd) + RootCmd.AddCommand(versionCmd) - RootCmd.PersistentFlags().StringP("repo", "R", "", "Current GitHub repository") + RootCmd.PersistentFlags().StringP("repo", "R", "", "Current GitHub repository") RootCmd.PersistentFlags().Bool("help", false, "Show help for command") RootCmd.Flags().Bool("version", false, "Print gh version") // TODO: @@ -66,6 +66,10 @@ var initContext = func() context.Context { return ctx } +func BasicClient() (*api.Client, error) { + return apiClientForContext(initContext()) +} + func contextForCommand(cmd *cobra.Command) context.Context { ctx := initContext() if repo, err := cmd.Flags().GetString("repo"); err == nil && repo != "" { diff --git a/main.go b/main.go index 7508db223..35ae078b0 100644 --- a/main.go +++ b/main.go @@ -10,15 +10,31 @@ import ( ) func main() { - isProduction := os.Getenv("APP_ENV") != "production" - update.RunWhileCheckingForUpdate(isProduction, func() { - if cmd, err := command.RootCmd.ExecuteC(); err != nil { - fmt.Fprintln(os.Stderr, err) - _, isFlagError := err.(command.FlagError) - if isFlagError || strings.HasPrefix(err.Error(), "unknown command ") { - fmt.Fprintln(os.Stderr, cmd.UsageString()) - } - os.Exit(1) + alertMsgChan := make(chan *string) + go updateInBackground(alertMsgChan) + + if cmd, err := command.RootCmd.ExecuteC(); err != nil { + fmt.Fprintln(os.Stderr, err) + _, isFlagError := err.(command.FlagError) + if isFlagError || strings.HasPrefix(err.Error(), "unknown command ") { + fmt.Fprintln(os.Stderr, cmd.UsageString()) } - }) + os.Exit(1) + } + + alertMsg := <-alertMsgChan + if alertMsg != nil { + fmt.Fprintf(os.Stderr, *alertMsg) + } +} + +func updateInBackground(alertMsgChan chan *string) { + client, err := command.BasicClient() + if err != nil { + alertMsgChan <- nil + return + } + + alertMsg := update.UpdateMessage(client) + alertMsgChan <- alertMsg } diff --git a/test/fixtures/latestRelease.json b/test/fixtures/latestRelease.json new file mode 100644 index 000000000..feb26a258 --- /dev/null +++ b/test/fixtures/latestRelease.json @@ -0,0 +1,4 @@ +{ + "tag_name": "v1.0.0", + "html_url": "https://www.spacejam.com/archive/spacejam/movie/jam.htm" +} diff --git a/update/checkForUpdate.go b/update/checkForUpdate.go deleted file mode 100644 index 3c0e1c905..000000000 --- a/update/checkForUpdate.go +++ /dev/null @@ -1,79 +0,0 @@ -package update - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "os" - - "github.com/github/gh-cli/command" - "github.com/github/gh-cli/utils" - "golang.org/x/crypto/ssh/terminal" -) - -const nwo = "github/homebrew-gh" - -type releaseInfo struct { - Version string `json:"tag_name"` - URL string `json:"html_url"` -} - -func RunWhileCheckingForUpdate(isProduction bool, f func()) { - if isProduction { - f() - return - } - - newReleaseChan := make(chan *releaseInfo) - go checkForUpdate(newReleaseChan) - f() - - newRelease := <-newReleaseChan - if newRelease != nil { - fmt.Printf(utils.Cyan(` -A new version of gh is available! %s → %s -Changelog: %s -Run 'brew upgrade gh' to update!`)+"\n\n", command.Version, newRelease.Version, newRelease.URL) - } -} - -func checkForUpdate(newReleaseChan chan *releaseInfo) { - // Ignore if this stdout is not a tty - if !terminal.IsTerminal(int(os.Stdout.Fd())) { - newReleaseChan <- nil - return - } - - latestRelease, err := getLatestRelease() - if err != nil { - newReleaseChan <- nil - return - } - - updateAvailable := latestRelease.Version != command.Version - - if updateAvailable { - newReleaseChan <- latestRelease - } else { - newReleaseChan <- nil - } -} - -func getLatestRelease() (*releaseInfo, error) { - url := fmt.Sprintf("https://api.github.com/repos/%s/releases/latest", nwo) - resp, err := http.Get(url) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - var r releaseInfo - json.Unmarshal(data, &r) - return &r, nil -} diff --git a/update/update.go b/update/update.go new file mode 100644 index 000000000..b0627789e --- /dev/null +++ b/update/update.go @@ -0,0 +1,43 @@ +package update + +import ( + "fmt" + "os" + + "github.com/github/gh-cli/api" + "github.com/github/gh-cli/command" + "github.com/github/gh-cli/utils" +) + +const nwo = "github/homebrew-gh" + +type releaseInfo struct { + Version string `json:"tag_name"` + URL string `json:"html_url"` +} + +func UpdateMessage(client *api.Client) *string { + latestRelease, err := getLatestRelease(client) + if err != nil { + fmt.Fprintf(os.Stderr, "%+v", err) + return nil + } + + updateAvailable := latestRelease.Version != command.Version + if updateAvailable { + alertMsg := fmt.Sprintf(utils.Cyan(` + A new version of gh is available! %s → %s + Changelog: %s + Run 'brew upgrade gh' to update!`)+"\n\n", command.Version, latestRelease.Version, latestRelease.URL) + return &alertMsg + } + + return nil +} + +func getLatestRelease(client *api.Client) (*releaseInfo, error) { + path := fmt.Sprintf("repos/%s/releases/latest", nwo) + var r releaseInfo + err := client.REST("GET", path, &r) + return &r, err +} diff --git a/update/update_test.go b/update/update_test.go new file mode 100644 index 000000000..f217fb65e --- /dev/null +++ b/update/update_test.go @@ -0,0 +1,36 @@ +package update + +import ( + "fmt" + "os" + "strings" + "testing" + + "github.com/github/gh-cli/api" + "github.com/github/gh-cli/command" +) + +func TestRunWhileCheckingForUpdate(t *testing.T) { + originalVersion := command.Version + command.Version = "v0.0.0" + defer func() { + command.Version = originalVersion + }() + + http := &api.FakeHTTP{} + jsonFile, _ := os.Open("../test/fixtures/latestRelease.json") + defer jsonFile.Close() + http.StubResponse(200, jsonFile) + + client := api.NewClient(api.ReplaceTripper(http)) + alertMsg := *UpdateMessage(client) + fmt.Printf("🌭 %+v\n", alertMsg) + + if !strings.Contains(alertMsg, command.Version) { + t.Errorf("expected: \"%v\" to contain \"%v\"", alertMsg, command.Version) + } + + if !strings.Contains(alertMsg, "v1.0.0") { + t.Errorf("expected: \"%v\" to contain \"%v\"", alertMsg, "v1.0.0") + } +}