Skip to content

Commit

Permalink
add opt-in notifications for beta releases
Browse files Browse the repository at this point in the history
  • Loading branch information
spowelljr committed Apr 22, 2021
1 parent 24a759f commit 2974543
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 2 deletions.
4 changes: 4 additions & 0 deletions cmd/minikube/cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ var settings = []Setting{
name: config.WantUpdateNotification,
set: SetBool,
},
{
name: config.WantBetaUpdateNotification,
set: SetBool,
},
{
name: config.ReminderWaitPeriodInHours,
set: SetInt,
Expand Down
2 changes: 2 additions & 0 deletions deploy/minikube/releases-beta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[
]
4 changes: 3 additions & 1 deletion pkg/minikube/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ import (
const (
// WantUpdateNotification is the key for WantUpdateNotification
WantUpdateNotification = "WantUpdateNotification"
// ReminderWaitPeriodInHours is the key for WantUpdateNotification
// WantBetaUpdateNotification is the key for WantBetaUpdateNotification
WantBetaUpdateNotification = "WantBetaUpdateNotification"
// ReminderWaitPeriodInHours is the key for ReminderWaitPeriodInHours
ReminderWaitPeriodInHours = "ReminderWaitPeriodInHours"
// WantReportError is the key for WantReportError
WantReportError = "WantReportError"
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/notify/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ package notify
const (
// GithubMinikubeReleasesURL is the URL of the minikube github releases JSON file
GithubMinikubeReleasesURL = "https://storage.googleapis.com/minikube/releases.json"
// GithubMinikubeBetaReleasesURL is the URL of the minikube Github beta releases JSON file
GithubMinikubeBetaReleasesURL = "https://storage.googleapis.com/minikube/releases-beta.json"
)
40 changes: 40 additions & 0 deletions pkg/minikube/notify/notify.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ var (

// MaybePrintUpdateTextFromGithub prints update text if needed, from github
func MaybePrintUpdateTextFromGithub() bool {
if notified := MaybePrintBetaUpdateText(GithubMinikubeBetaReleasesURL, lastUpdateCheckFilePath); notified {
return true
}
return MaybePrintUpdateText(GithubMinikubeReleasesURL, lastUpdateCheckFilePath)
}

Expand Down Expand Up @@ -74,6 +77,35 @@ func MaybePrintUpdateText(url string, lastUpdatePath string) bool {
return false
}

// MaybePrintBetaUpdateText returns true and prints update text of a new beta version of minikube is available.
func MaybePrintBetaUpdateText(url string, lastUpdatePath string) bool {
if !shouldCheckURLBetaVersion(lastUpdatePath) {
return false
}
latestVersion, err := getLatestVersionFromURL(url)
if err != nil {
klog.Warning(err)
return false
}
localVersion, err := version.GetSemverVersion()
if err != nil {
klog.Warning(err)
return false
}
if localVersion.Compare(latestVersion) >= 0 {
return false
}
if err := writeTimeToFile(lastUpdateCheckFilePath, time.Now().UTC()); err != nil {
klog.Errorf("write time failed: %v", err)
}
url = "https://github.com/kubernetes/minikube/releases/tag/v" + latestVersion.String()
out.Styled(style.Celebrate, `minikube {{.version}} is available! Download it: {{.url}}`, out.V{"version": latestVersion, "url": url})
out.Styled(style.Tip, "To disable beta notices, run: 'minikube config set WantBetaUpdateNotification false'\n")
out.Styled(style.Tip, "To disable update notices in general, run: 'minikube config set WantUpdateNotification false'\n")

return true
}

func shouldCheckURLVersion(filePath string) bool {
if !viper.GetBool(config.WantUpdateNotification) {
return false
Expand All @@ -82,6 +114,14 @@ func shouldCheckURLVersion(filePath string) bool {
return time.Since(lastUpdateTime).Hours() >= viper.GetFloat64(config.ReminderWaitPeriodInHours)
}

func shouldCheckURLBetaVersion(filePath string) bool {
if !viper.GetBool(config.WantBetaUpdateNotification) {
return false
}

return shouldCheckURLVersion(filePath)
}

// Release represents a release
type Release struct {
Name string
Expand Down
148 changes: 147 additions & 1 deletion pkg/minikube/notify/notify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestMaybePrintUpdateTextFromGithub(t *testing.T) {
}
}

func TestShouldCheckURL(t *testing.T) {
func TestShouldCheckURLVersion(t *testing.T) {
tempDir := tests.MakeTempDir()
defer tests.RemoveTempDir(tempDir)

Expand Down Expand Up @@ -80,6 +80,52 @@ func TestShouldCheckURL(t *testing.T) {

}

func TestShouldCheckURLBetaVersion(t *testing.T) {
tempDir := tests.MakeTempDir()
defer tests.RemoveTempDir(tempDir)

lastUpdateCheckFilePath := filepath.Join(tempDir, "last_update_check")

// test that if users disable update notification in config, the URL version does not get checked
viper.Set(config.WantUpdateNotification, true)
viper.Set(config.WantBetaUpdateNotification, false)
if shouldCheckURLBetaVersion(lastUpdateCheckFilePath) {
t.Fatalf("shouldCheckURLBetaVersion returned true even though config had WantBetaUpdateNotification: false")
}

viper.Set(config.WantUpdateNotification, false)
viper.Set(config.WantBetaUpdateNotification, true)
if shouldCheckURLBetaVersion(lastUpdateCheckFilePath) {
t.Fatalf("shouldCheckURLBetaVersion returned true even though config had WantUpdateNotification: false")
}

// test that if users want update notification, the URL version does get checked
viper.Set(config.WantUpdateNotification, true)
if !shouldCheckURLBetaVersion(lastUpdateCheckFilePath) {
t.Fatalf("shouldCheckURLBetaVersion returned false even though there was no last_update_check file")
}

// test that update notifications get triggered if it has been longer than 24 hours
viper.Set(config.ReminderWaitPeriodInHours, 24)

//time.Time{} returns time -> January 1, year 1, 00:00:00.000000000 UTC.
if err := writeTimeToFile(lastUpdateCheckFilePath, time.Time{}); err != nil {
t.Errorf("write failed: %v", err)
}
if !shouldCheckURLBetaVersion(lastUpdateCheckFilePath) {
t.Fatalf("shouldCheckURLBetaVersion returned false even though longer than 24 hours since last update")
}

// test that update notifications do not get triggered if it has been less than 24 hours
if err := writeTimeToFile(lastUpdateCheckFilePath, time.Now().UTC()); err != nil {
t.Errorf("write failed: %v", err)
}
if shouldCheckURLBetaVersion(lastUpdateCheckFilePath) {
t.Fatalf("shouldCheckURLBetaVersion returned true even though less than 24 hours since last update")
}

}

type URLHandlerCorrect struct {
releases Releases
}
Expand Down Expand Up @@ -236,6 +282,106 @@ func TestMaybePrintUpdateText(t *testing.T) {
}
}

func TestMaybePrintBetaUpdateText(t *testing.T) {
tempDir := tests.MakeTempDir()
defer tests.RemoveTempDir(tempDir)
outputBuffer := tests.NewFakeFile()
out.SetOutFile(outputBuffer)

var tc = []struct {
len int
wantUpdateNotification bool
wantBetaUpdateNotification bool
latestVersionFromURL string
description string
status bool
url string
lastUpdateCheckFilePath string
}{
{
len: 1,
latestVersionFromURL: "0.0.0-dev",
wantUpdateNotification: true,
wantBetaUpdateNotification: true,
description: "latest version lower or equal",
},
{
len: 0,
latestVersionFromURL: "100.0.0-dev",
wantUpdateNotification: true,
wantBetaUpdateNotification: true,
description: "latest version greater",
status: true,
},
{
len: 1,
latestVersionFromURL: "100.0.0-dev",
wantUpdateNotification: false,
wantBetaUpdateNotification: true,
description: "notification unwanted",
},
{
len: 1,
latestVersionFromURL: "100.0.0-dev",
wantUpdateNotification: true,
wantBetaUpdateNotification: false,
description: "beta notification unwanted",
},
{
len: 1,
latestVersionFromURL: "100.0.0-dev",
wantUpdateNotification: true,
wantBetaUpdateNotification: true,
description: "bad url",
url: "this is not valid url",
status: false,
},
{
len: 1,
latestVersionFromURL: "10.0.0-dev",
wantUpdateNotification: true,
wantBetaUpdateNotification: true,
description: "bad lastUpdateCheckFilePath",
lastUpdateCheckFilePath: "/etc/passwd",
status: true,
},
}

viper.Set(config.ReminderWaitPeriodInHours, 24)
for _, test := range tc {
t.Run(test.description, func(t *testing.T) {
viper.Set(config.WantUpdateNotification, test.wantUpdateNotification)
viper.Set(config.WantBetaUpdateNotification, test.wantBetaUpdateNotification)
lastUpdateCheckFilePath = filepath.Join(tempDir, "last_update_check")
if test.lastUpdateCheckFilePath != "" {
lastUpdateCheckFilePath = test.lastUpdateCheckFilePath
}
latestVersionFromURL := test.latestVersionFromURL
handler := &URLHandlerCorrect{
releases: []Release{{Name: version.VersionPrefix + latestVersionFromURL}},
}
server := httptest.NewServer(handler)
defer server.Close()
if test.url == "" {
test.url = server.URL
}
tmpfile, err := ioutil.TempFile("", "")
if err != nil {
t.Fatalf("Cannot create temp file: %v", err)
}
defer os.Remove(tmpfile.Name())
status := MaybePrintBetaUpdateText(test.url, tmpfile.Name())
if test.status != status {
t.Fatalf("MaybePrintBetaUpdateText expected to return %v, but got %v", test.status, status)
}
if len(outputBuffer.String()) == test.len {
t.Fatalf("Expected MaybePrintBetaUpdateText to output text as the current version is %s and version %s was served from URL but output was [%s]",
version.GetVersion(), latestVersionFromURL, outputBuffer.String())
}
})
}
}

func TestDownloadURL(t *testing.T) {
const urlBase = "https://github.com/kubernetes/minikube/releases/download/"
type args struct {
Expand Down
1 change: 1 addition & 0 deletions site/content/en/docs/commands/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Configurable fields:
* kubernetes-version
* iso-url
* WantUpdateNotification
* WantBetaUpdateNotification
* ReminderWaitPeriodInHours
* WantReportError
* WantReportErrorPrompt
Expand Down

0 comments on commit 2974543

Please sign in to comment.