-
Notifications
You must be signed in to change notification settings - Fork 369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Check for new krew versions once a day #490
Check for new krew versions once a day #490
Conversation
This will check once a day if a new version of krew is available. The timestamp of the last run is stored in KREW_HOME/last_update_check. As this is a convenience function, silently ignore errors if they occur.
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: corneliusweig The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Codecov Report
@@ Coverage Diff @@
## master #490 +/- ##
==========================================
+ Coverage 56.47% 57.03% +0.55%
==========================================
Files 19 20 +1
Lines 926 966 +40
==========================================
+ Hits 523 551 +28
- Misses 350 357 +7
- Partials 53 58 +5
Continue to review full report at Codecov.
|
internal/assertion/update.go
Outdated
|
||
func saveTimestamp(file string) { | ||
klog.V(4).Info("Saving timestamp for last version check") | ||
timestamp := time.Now().Format(time.RFC1123) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not just use unix time as the persisted format?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean seconds since epoch? I prefer a more readable format. I changed to something which still easy to manipulate.
This code is racey now, because the global variable is accessed without synchronization. Since this is a convenience feature, this is acceptable.
|
||
klog.V(4).Infof("Found latest tag %q", latestTag) | ||
return latestTag | ||
if version.GitTag() == latestTag { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be nicer to actually use our semver pkg to do a >
check here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or rather, maybe don't do the version tag here?
I feel like the CheckVersion
isn't matching what this method does with reading last_update_check time + comparison with current version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather not do any semver parsing here. In tests, version.GitTag
returns unknown
which would not work.
Besides, we only allow the remote version to increase. So checking for equality also does the job.
} | ||
saveTimestamp(f) | ||
|
||
if version.GitTag() == latestTag { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also worth keeping in mind that sometimes version.GitTag() might return malformed or empty string that isn't a semver.
if we actually parse that higher in the stack, we don't even have to fetchLatestTag()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean to say that the update check should not run for development builds? That would make perfect sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? If I want to be in the edge, I would care updating even more than a regular user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not:
- if you are developing krew, you are usually ahead of the latest release. So the "upgrade" notification would recommend a downgrade :)
- the CI runs non-release builds of krew in integration tests. We don't need upgrade notifications there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean to say that the update check should not run for development builds? That would make perfect sense.
Not just development builds.
For example, until recently homebrew formula did not have -ldflags
that stamp the GitTag into the binary.
Also think of people running go get sigs.k8s.io/krew/cmd/krew
, it will not have a GitTag in it.
For those cases, just fail to parse version as semver, and move on.
- if you are developing krew, you are usually ahead of the latest release. So the "upgrade" notification would recommend a downgrade :)
thats why (1) parse strings into SemVer (2) use semver.LessThan to compare instead of !=
.
if err != nil { | ||
return "", errors.Wrapf(err, "could not determine latest tag") | ||
} | ||
saveTimestamp(f) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need defer saveTimestamp()
earlier in this func.
last_update_check shouldn't just count successful checks, but rather "completed attempts".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is that? If a check fails, we should retry soon instead of waiting the full cool-down. So without defer
sounds more reasonable to me.
So right now we check every 24 hours.
we need to be careful about the impact of this. |
} | ||
} | ||
|
||
func Test_fetchTag(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually something more valuable to test than "github returning broken json" would be "github unreachable" case.
it's far more likely to happen (Little Snitch, and other corp firewalls etc.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, but I don't see how I can simulate this situation in tests. From the docs of http.Get
:
An error is returned if there were too many redirects or if there
was an HTTP protocol error.
So I don't see how I could possibly cause an error here :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah well.. I can just use a bad address, which will cause an HTTP error.
klog.V(3).Info("Latest tag is same as ours.") | ||
return "", nil | ||
} | ||
return color.New(color.Bold).Sprintf(upgradeNotification, version.GitTag(), latestTag), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this method doesn't have a good signature.
Returning strings with colors isn't great.
let's change it to something like this
func UpdateAvailable(basePath string, currentVersion semver.Version) (semver.Version, exists bool, error)
then we can curate the message outside.
} | ||
} | ||
|
||
func Test_fetchTag(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add a TestFetchTag that actually queries GitHub?
I know making network calls isn't a great idea during unit tests, but it would help us notice if the Github API breaks somehow under us.
If your really think we could run into problems, let's reset the cooldown also after failed API requests. As long as the cooldown is not too large, this is fine with me. |
content, err := ioutil.ReadFile(file) | ||
if err != nil { | ||
klog.V(4).Infof("Could not read timestamp file %q", file) | ||
return time.Unix(0, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not default? time.Time{}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it’s not supposed to be used when err exists, it practically doesn’t matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering if there was a special reason.
Yes, end result doesn't change but it's like []type
vs nil
, would be more idiomatic.
// will only be emitted once a day. | ||
func CheckVersion(basePath string) (string, error) { | ||
f := filepath.Join(basePath, "last_update_check") | ||
if lastCheck := loadTimestamp(f); time.Since(lastCheck).Hours() <= 24 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you put the range to the top as constant?
an idea might be introducing another environment variable to customize it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just hardcoded const is good
on the contrary, if we fail, I think that still should count as a "completed attempt" –and we should not do any more requests in the next 24h IMO. We want people to eventually update; not right away. However, if a check isn't complete (i.e. krew exists before we can request+print warning), we should not record that and run it again next time. |
the `KREW_NO_UPGRADE_CHECK` environment variable. To permanently disable this, | ||
add the following to your `~/.bashrc`, `~/.bash_profile`, or `~/.zshrc`: | ||
|
||
export KREW_NO_UPGRADE_CHECK=1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An idea: since we don't know how it will affect users in the beginnning, we might make it opt-in to use at first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-1. we discussed at #480 that this isn't sending PII. It's basically almost like a git clone that we already do. I don't wish users to learn yet another thing. Let's keep the interaction surface minimal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, sounds good.
Btw, sorry for skipping the actual discussion and opening them here again.
@@ -104,6 +104,15 @@ without any arguments: | |||
Since `krew` itself is a plugin also managed through `krew`, running the upgrade | |||
command may also upgrade your `krew` version. | |||
|
|||
### Krew upgrade check |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is too high up.
Let's move this below to the main user journey and call it ## Disabling update checks
A major part of the discussion has revolved around the file where the timestamp of the last check is stored. I created an alternate version of this feature where checks are done at random here #494. So I'll close this if favor of the other PR. |
@corneliusweig: Closed this PR. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Fixes #480
This will check once a day if a new version of krew is available.
The timestamp of the last run is stored in KREW_HOME/last_update_check.
As this is a convenience function, silently ignore errors if they occur.
To opt out of this feature, set the
KREW_NO_UPGRADE_CHECK
env variable.