diff --git a/commands/doctor.go b/commands/doctor.go index fba4675..7c4ef1a 100644 --- a/commands/doctor.go +++ b/commands/doctor.go @@ -206,5 +206,12 @@ func (cmd *Doctor) Run(c *cli.Context) error { } } + // 7. Check for availability of a rig upgrade + cmd.out.Spin("Checking for available rig updates...") + if msg := util.CheckForRigUpdate(c.App.Version); msg != "" { + cmd.out.Info(msg) + } else { + cmd.out.Info("rig is up-to-date") + } return nil } diff --git a/commands/start.go b/commands/start.go index a4150f8..d200be1 100644 --- a/commands/start.go +++ b/commands/start.go @@ -145,6 +145,12 @@ func (cmd *Start) Run(c *cli.Context) error { dash.LaunchDashboard(cmd.machine) cmd.out.Info("Dashboard is ready") + // Check for availability of a rig upgrade + cmd.out.Spin("Checking for available rig updates...") + if msg := util.CheckForRigUpdate(c.App.Version); msg != "" { + cmd.out.Info(msg) + } + cmd.out.Info("Run 'eval \"$(rig config)\"' to execute docker or docker-compose commands in your terminal.") return cmd.Success("Outrigger is ready to use") } diff --git a/util/update.go b/util/update.go new file mode 100644 index 0000000..842676a --- /dev/null +++ b/util/update.go @@ -0,0 +1,77 @@ +package util + +import ( + "encoding/json" + "errors" + "io/ioutil" + "net/http" + "time" + + "github.com/hashicorp/go-version" +) + +type githubResponse struct { + Name string `json:"name"` +} + +// CheckForRigUpdate checks to see if an upgrdate to rig is available, if so, return a message +func CheckForRigUpdate(curRigVersion string) string { + // Local dev, version == "master" which isn't going to parse. + curVer, verr := version.NewVersion(curRigVersion) + if tag, err := currentRigReleaseTag(); err == nil { + if tagVer, verr2 := version.NewVersion(tag); verr2 == nil { + // Show the message if we're on master or there's an update. + if verr != nil || tagVer.Compare(curVer) > 0 { + return "An update for rig is available: " + tag + } + } + } + return "" +} + +// Return the current release tag for rig +func currentRigReleaseTag() (string, error) { + // Fetch some json from github containing the latest release name + url := "https://api.github.com/repos/phase2/rig/releases/latest" + response, err := getRigReleaseTagResponse(url) + if err != nil { + return "", err + } + defer response.Body.Close() + // Collect the response + body, err := ioutil.ReadAll(response.Body) + if err != nil { + Logger().Verbose("ReadAll %s failed:\n%s", url, err) + return "", err + } + if response.StatusCode != 200 { + Logger().Verbose("ReadAll %s failed: %s", url, response.Status) + return "", errors.New(response.Status) + } + // Decode the json, pick off the name field + decoder := githubResponse{} + if err = json.Unmarshal(body, &decoder); err != nil { + Logger().Verbose("Unmarshal %s failed:\n%s", url, err) + return "", err + } + Logger().Verbose("rig current release tag: %s", decoder.Name) + return decoder.Name, nil +} + +func getRigReleaseTagResponse(url string) (*http.Response, error) { + client := http.Client{ + Timeout: time.Second * 2, // Maximum of 2 secs + } + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + Logger().Verbose("NewRequest %s failed:\n%s", url, err) + return nil, err + } + // Execute the request + response, err := client.Do(req) + if err != nil { + Logger().Verbose("GET %s failed:\n%s", url, err) + return nil, err + } + return response, nil +} diff --git a/util/update_test.go b/util/update_test.go new file mode 100644 index 0000000..b4ed113 --- /dev/null +++ b/util/update_test.go @@ -0,0 +1,22 @@ +package util + +import ( + "fmt" + "testing" +) + +func TestUpgradeCheck(t *testing.T) { + Logger().SetVerbose(true) + // Local dev uses version "master" + if msg := CheckForRigUpdate("master"); msg == "" { + t.Error("well that didn't work.") + } else { + fmt.Println(msg) + } + // Test no update available + if curVersion, err := currentRigReleaseTag(); err != nil { + t.Error(err) + } else if msg := CheckForRigUpdate(curVersion); msg != "" { + t.Error(msg) + } +}