Skip to content

Commit

Permalink
Merge pull request #194 from CircleCI-Public/update-check
Browse files Browse the repository at this point in the history
[CIRCLE-13826]: Periodic update check for user
  • Loading branch information
Zachary Scott authored Nov 13, 2018
2 parents e6cb4f6 + 98eb9c5 commit 6011639
Show file tree
Hide file tree
Showing 32 changed files with 2,602 additions and 113 deletions.
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ builds:
# -w Omit the DWARF symbol table.
# These are the defaults specified by goreleaser:
# https://github.com/goreleaser/goreleaser/blob/682c811106f56ffe06c4212de546aec62161fb9d/internal/builders/golang/build.go#L46
- -s -w -X github.com/CircleCI-Public/circleci-cli/version.Version={{.Version}} -X github.com/CircleCI-Public/circleci-cli/version.Commit={{.Commit}}
- -s -w -X github.com/CircleCI-Public/circleci-cli/version.Version={{.Version}} -X github.com/CircleCI-Public/circleci-cli/version.Commit={{.Commit}} -X github.com/CircleCI-Public/circleci-cli/cmd.PackageManager=release
17 changes: 17 additions & 0 deletions Gopkg.lock

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

77 changes: 77 additions & 0 deletions cmd/check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package cmd

import (
"time"

"github.com/CircleCI-Public/circleci-cli/logger"
"github.com/CircleCI-Public/circleci-cli/settings"
"github.com/CircleCI-Public/circleci-cli/update"
"github.com/CircleCI-Public/circleci-cli/version"
"github.com/briandowns/spinner"
)

func checkForUpdates(opts *settings.Config) error {
if opts.SkipUpdateCheck {
return nil
}

updateCheck := &settings.UpdateCheck{
LastUpdateCheck: time.Time{},
}

err := updateCheck.Load()
if err != nil {
return err
}

if update.ShouldCheckForUpdates(updateCheck) {
log := logger.NewLogger(opts.Debug)
slug := "CircleCI-Public/circleci-cli"

spr := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
spr.Suffix = " Checking for updates..."
spr.Start()

check, err := update.CheckForUpdates(opts.GitHubAPI, slug, version.Version, PackageManager)

if err != nil {
spr.Stop()
return err
}

if !check.Found {
spr.Suffix = "No updates found."
time.Sleep(300 * time.Millisecond)
spr.Stop()

updateCheck.LastUpdateCheck = time.Now()
err = updateCheck.WriteToDisk()
return err
}

if update.IsLatestVersion(check) {
spr.Suffix = "Already up-to-date."
time.Sleep(300 * time.Millisecond)
spr.Stop()

updateCheck.LastUpdateCheck = time.Now()
err = updateCheck.WriteToDisk()
return err
}
spr.Stop()

log.Debug(update.DebugVersion(check))
log.Info(update.ReportVersion(check))
log.Info(update.HowToUpdate(check))

log.Info("\n") // Print a new-line after all of that

updateCheck.LastUpdateCheck = time.Now()
err = updateCheck.WriteToDisk()
if err != nil {
return err
}
}

return nil
}
128 changes: 128 additions & 0 deletions cmd/check_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package cmd_test

import (
"fmt"
"net/http"
"os"
"os/exec"
"time"

"github.com/CircleCI-Public/circleci-cli/settings"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gbytes"
"github.com/onsi/gomega/gexec"
"github.com/onsi/gomega/ghttp"
)

var _ = Describe("Check", func() {
var (
command *exec.Cmd
err error
checkCLI string
tempHome string
testServer *ghttp.Server
updateCheck *settings.UpdateCheck
updateFile *os.File
)

BeforeEach(func() {
checkCLI, err = gexec.Build("github.com/CircleCI-Public/circleci-cli")
Expect(err).ShouldNot(HaveOccurred())

tempHome, _, updateFile = withTempSettings()

updateCheck = &settings.UpdateCheck{
LastUpdateCheck: time.Time{},
}

updateCheck.FileUsed = updateFile.Name()
err = updateCheck.WriteToDisk()
Expect(err).ShouldNot(HaveOccurred())

testServer = ghttp.NewServer()

command = exec.Command(checkCLI, "help",
"--github-api", testServer.URL(),
)

command.Env = append(os.Environ(),
fmt.Sprintf("HOME=%s", tempHome),
)
})

AfterEach(func() {
Expect(os.RemoveAll(tempHome)).To(Succeed())
})

Describe("update auto checks with a new release", func() {
var (
response string
)

BeforeEach(func() {
checkCLI, err = gexec.Build("github.com/CircleCI-Public/circleci-cli",
"-ldflags",
"-X github.com/CircleCI-Public/circleci-cli/cmd.AutoUpdate=false -X github.com/CircleCI-Public/circleci-cli/cmd.PackageManager=release",
)
Expect(err).ShouldNot(HaveOccurred())

tempHome, _, _ = withTempSettings()

command = exec.Command(checkCLI, "help",
"--github-api", testServer.URL(),
)

command.Env = append(os.Environ(),
fmt.Sprintf("HOME=%s", tempHome),
)

response = `
[
{
"id": 1,
"tag_name": "v1.0.0",
"name": "v1.0.0",
"published_at": "2013-02-27T19:35:32Z",
"assets": [
{
"id": 1,
"name": "linux_amd64.zip",
"label": "short description",
"content_type": "application/zip",
"size": 1024
}
]
}
]
`

testServer.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/repos/CircleCI-Public/circleci-cli/releases"),
ghttp.RespondWith(http.StatusOK, response),
),
)

})

AfterEach(func() {
testServer.Close()
})

Context("using a binary release", func() {
It("with flag should tell the user how to update and install", func() {
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
Expect(err).ShouldNot(HaveOccurred())

Eventually(session.Err.Contents()).Should(BeEmpty())

Eventually(session.Out).Should(gbytes.Say("You are running 0.0.0-dev"))
Eventually(session.Out).Should(gbytes.Say("A new release is available (.*)"))
Eventually(session.Out).Should(gbytes.Say("You can update with `circleci update install`"))

Eventually(session).Should(gexec.Exit(0))
})
})
})
})
21 changes: 15 additions & 6 deletions cmd/cmd_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,40 @@ var _ = BeforeSuite(func() {
Ω(err).ShouldNot(HaveOccurred())
})

func withTempHomeConfig() (string, *os.File) {
func withTempSettings() (string, *os.File, *os.File) {
var (
tempHome string
err error
config *os.File
update *os.File
)

tempHome, err = ioutil.TempDir("", "circleci-cli-test-")
Expect(err).ToNot(HaveOccurred())

const (
configDir = ".circleci"
configFile = "cli.yml"
settingsPath = ".circleci"
configFilename = "cli.yml"
updateCheckFilename = "update_check.yml"
)

Expect(os.Mkdir(filepath.Join(tempHome, configDir), 0700)).To(Succeed())
Expect(os.Mkdir(filepath.Join(tempHome, settingsPath), 0700)).To(Succeed())

config, err = os.OpenFile(
filepath.Join(tempHome, configDir, configFile),
filepath.Join(tempHome, settingsPath, configFilename),
os.O_RDWR|os.O_CREATE,
0600,
)
Expect(err).ToNot(HaveOccurred())

return tempHome, config
update, err = os.OpenFile(
filepath.Join(tempHome, settingsPath, updateCheckFilename),
os.O_RDWR|os.O_CREATE,
0600,
)
Expect(err).ToNot(HaveOccurred())

return tempHome, config, update
}

var _ = AfterSuite(func() {
Expand Down
22 changes: 18 additions & 4 deletions cmd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ var _ = Describe("Config", func() {
token = "testtoken"
command = exec.Command(pathCLI,
"config", "validate",
"--skip-update-check",
"--token", token,
"--host", testServer.URL(),
config.Path,
Expand Down Expand Up @@ -133,6 +134,7 @@ var _ = Describe("Config", func() {
token = "testtoken"
command = exec.Command(pathCLI,
"config", "process",
"--skip-update-check",
"--token", token,
"--host", testServer.URL(),
config.Path,
Expand Down Expand Up @@ -217,7 +219,10 @@ var _ = Describe("Config", func() {
Describe("a .circleci folder with config.yml and local orbs folder containing the hugo orb", func() {
BeforeEach(func() {
var err error
command = exec.Command(pathCLI, "config", "pack", "testdata/hugo-pack/.circleci")
command = exec.Command(pathCLI,
"config", "pack",
"--skip-update-check",
"testdata/hugo-pack/.circleci")
results, err = ioutil.ReadFile("testdata/hugo-pack/result.yml")
Expect(err).ShouldNot(HaveOccurred())
})
Expand All @@ -236,7 +241,10 @@ var _ = Describe("Config", func() {
BeforeEach(func() {
var err error
var path string = "nested-orbs-and-local-commands-etc"
command = exec.Command(pathCLI, "config", "pack", filepath.Join("testdata", path, "test"))
command = exec.Command(pathCLI,
"config", "pack",
"--skip-update-check",
filepath.Join("testdata", path, "test"))
results, err = ioutil.ReadFile(filepath.Join("testdata", path, "result.yml"))
Expect(err).ShouldNot(HaveOccurred())
})
Expand All @@ -254,7 +262,10 @@ var _ = Describe("Config", func() {
Describe("an orb containing local executors and commands in folder", func() {
BeforeEach(func() {
var err error
command = exec.Command(pathCLI, "config", "pack", "testdata/myorb/test")
command = exec.Command(pathCLI,
"config", "pack",
"--skip-update-check",
"testdata/myorb/test")
results, err = ioutil.ReadFile("testdata/myorb/result.yml")
Expect(err).ShouldNot(HaveOccurred())
})
Expand All @@ -273,7 +284,10 @@ var _ = Describe("Config", func() {
BeforeEach(func() {
var err error
var path string = "test-with-large-nested-rails-orb"
command = exec.Command(pathCLI, "config", "pack", filepath.Join("testdata", path, "test"))
command = exec.Command(pathCLI,
"config", "pack",
"--skip-update-check",
filepath.Join("testdata", path, "test"))
results, err = ioutil.ReadFile(filepath.Join("testdata", path, "result.yml"))
Expect(err).ShouldNot(HaveOccurred())
})
Expand Down
2 changes: 2 additions & 0 deletions cmd/diagnostic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var _ = Describe("Diagnostic", func() {

command = exec.Command(pathCLI,
"diagnostic",
"--skip-update-check",
"--endpoint", testServer.URL())

command.Env = append(os.Environ(),
Expand Down Expand Up @@ -153,6 +154,7 @@ token: mytoken

command = exec.Command(pathCLI,
"diagnostic",
"--skip-update-check",
"--endpoint", testServer.URL(),
"--debug",
)
Expand Down
3 changes: 3 additions & 0 deletions cmd/disabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ func newDisabledCommand(config *settings.Config, command string) *cobra.Command
disable := &cobra.Command{
Use: opts.command,
Short: "This command is unavailable on your platform",
PersistentPreRun: func(_ *cobra.Command, _ []string) {
opts.cfg.SkipUpdateCheck = true
},
PreRun: func(cmd *cobra.Command, args []string) {
opts.args = args
opts.log = logger.NewLogger(config.Debug)
Expand Down
Loading

0 comments on commit 6011639

Please sign in to comment.