-
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
cmd: Update each index instead of just default #588
cmd: Update each index instead of just default #588
Conversation
cmd/krew/cmd/namingutils.go
Outdated
// allIndexes returns a slice of index name and URL pairs | ||
func allIndexes(p environment.Paths) ([]indexoperations.Index, error) { | ||
indexes := []indexoperations.Index{ | ||
{ | ||
Name: constants.DefaultIndexName, | ||
URL: constants.DefaultIndexURI, | ||
}, | ||
} | ||
if os.Getenv(constants.EnableMultiIndexSwitch) != "" { | ||
out, err := indexoperations.ListIndexes(p) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "failed to list plugin indexes available") | ||
} | ||
if len(out) != 0 { | ||
indexes = out | ||
} | ||
} | ||
return indexes, 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.
It might've been better if we extracted the feature gate into indexoperations.ListIndexes
so we don't reimplement it here.
IIRC there's at least one more place we hardcode this:
[]indexoperations.Index{
{
Name: constants.DefaultIndexName,
URL: constants.DefaultIndexURI,
},
you should be able to find very easily.
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.
yeah if you handle it in one place (for now, until we remove the feature gate saves the following +60 lines in namingutils_test.go
for us, and reduces duplication)
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 good call, I didn't think about that.
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.
So this was something that we talked about when going over the proposal:
If no indexes are configured, a message is printed explaining how to add krew-index as default
I just want to make sure we're cool with that. The current functionality is that krew-index gets added by default, but once multi-index is out that means that users won't be able to krew install ctx
right after install.
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're conflating the two issues here:
-
You should hardcode that index to that method only when X_KREW_MULTI_INDEX is "not" set.
-
How do we add the
default
=krew-index (once multi-index work is complete) is another discussion which I'm tracking at Implement custom plugin indexes #566. (Right now we're auto-adding it if it's missing on install/update/upgrade) but this is a side-effect of old code, and it's not about this PR.
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.
You should hardcode that index to that method only when X_KREW_MULTI_INDEX is "not" set.
We decided before that krew index list
after a fresh install should work and return an empty list. Do you want me to change that behavior and accompanying tests if we want it to return the hardcoded index when env var isn't set?
How do we add the default=krew-index (once multi-index work is complete) is another discussion which I'm tracking at #566. (Right now we're auto-adding it if it's missing on install/update/upgrade) but this is a side-effect of old code, and it's not about this PR.
I brought it up because that was part of the proposal and it seemed like this would be the PR to take care of the help message when no indexes are configured. If that's not the case then what should I do for now when the env var is set, but no indexes are configured?
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.
We decided before that krew index list after a fresh install should work and return an empty list. Do you want me to change that behavior and accompanying tests if we want it to return the hardcoded index when env var isn't set?
We should keep this behavior. I only wanted that we call indexoperations.ListIndexes always, but without the feature flag, it returns default index, with the feature flag it lists from filesystem.
I can make this change if you want me to.
I brought it up because that was part of the proposal and it seemed like this would be the PR to take care of the help message when no indexes are configured
That can be a separate PR, let's keep this one small.
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.
Ok I can take care of it here 👍
cmd/krew/cmd/update.go
Outdated
return errors.Wrap(err, "failed to update the local index") | ||
indexes, err := allIndexes(paths) | ||
if err != nil { | ||
return err |
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.
wrap
cmd/krew/cmd/update.go
Outdated
@@ -105,9 +105,16 @@ func showUpdatedPlugins(out io.Writer, preUpdate, posUpdate []index.Plugin, inst | |||
func ensureIndexUpdated(_ *cobra.Command, _ []string) error { |
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.
method needs rename? :)
cmd/krew/cmd/update.go
Outdated
indexPath := paths.IndexPath(idx.Name) | ||
klog.V(1).Infof("Updating the local copy of plugin index (%s)", indexPath) | ||
if err := gitutil.EnsureUpdated(idx.URL, indexPath); err != nil { | ||
return errors.Wrapf(err, "failed to update the local index %s", idx.Name) |
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.
potentially the most interesting part of the PR here:
Do we bail out on the first index failed to update ––OR–– do we go ahead and update all possible indexes, and collect the errors (or at least one of them) + report it at the end.
For example, today, krew install ctx BAD_PLUGIN ns
will install ctx & ns, but the overall command will fail. This was intentionally designed for good UX.
With krew install
and krew upgrade
both calling ensureIndexUpdated
every time before they do their job, I think a bad index (e.g. deleted repo) will render the majority of krew user surface unusable ––especially if that index has a name that's alphabetically earlier than "default"
.
Thoughts @corneliusweig ?
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.
In the long run, we might want to update indexes in parallel. If doing this in parallel, it is no longer possible to fail on the first index update, because "first" is not a proper concept then. So to avoid behaviour change in the future, we should strive to update everything and collect errors.
Besides, it's just better UX IMO.
0c7d67e
to
6717fe8
Compare
I switched this back to sequentially updating the indexes for now, I ran into an issue with the test that checks for the index failed update. The test hangs when the update fails in a goroutine for some reason and I've been trying to figure out why. Would it be ok to create an issue and follow up PR for making the update concurrent? |
Switch back to sequential updates. The test where gitutil.EnsureUpdated fails seems to hang when it happens in a goroutine for some reason.
integration_test/update_test.go
Outdated
if len(out) == 0 { | ||
t.Error("no plugins in index foo after update") | ||
} |
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.
shouldn't you be also checking what's in default
index now?
also you can use something like krew search
here to find plugins in all indexes.
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.
Ya good call 👍
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 should be enough to look for two plugin names in the output. For example, ctx
and foo/ctx
.
cmd/krew/cmd/update.go
Outdated
indexPath := paths.IndexPath(idx.Name) | ||
klog.V(1).Infof("Updating the local copy of plugin index (%s)", indexPath) | ||
if err := gitutil.EnsureUpdated(idx.URL, indexPath); err != nil { | ||
klog.V(1).Infof("error updating index %s: %s", idx.Name, err) |
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.
you should probably do this as klog.Warningf
otherwise the user will never know (unless they use -v) what the error is.
See how we handle multiple plugin install failures in install.go
.
Line 160 in b2b8a40
klog.Warningf("failed to install plugin %q: %v", plugin.Name, err) |
cmd/krew/cmd/update.go
Outdated
@@ -132,6 +145,9 @@ func ensureIndexUpdated(_ *cobra.Command, _ []string) error { | |||
// TODO(chriskim06) consider commenting this out when refactoring for custom indexes | |||
showUpdatedPlugins(os.Stderr, preUpdateIndex, posUpdateIndex, installedPlugins) | |||
|
|||
if len(failed) != 0 { | |||
return errors.Errorf("failed to update the following indexes: %s\n", strings.Join(failed, ", ")) |
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.
Something else we do in install.go is that we collect the first error as returnErr
and wrap+return it.
Lines 161 to 163 in b2b8a40
if returnErr == nil { | |
returnErr = err | |
} |
Lines 178 to 180 in b2b8a40
if len(failed) > 0 { | |
return errors.Wrapf(returnErr, "failed to install some plugins: %+v", failed) | |
} |
The reason for this is that when you wrap+return errors, when executed with -v 1
or above, we the retain ability to print full stack trace (in this case, at least for 1 error which is good enough).
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.
When you update with the comments by Ahmet, this looks pretty good to me.
Thanks for bringing the multi-index project one step further ahead!
defer cleanup() | ||
|
||
test = test.WithEnv(constants.EnableMultiIndexSwitch, 1).WithIndex() | ||
os.Setenv(constants.EnableMultiIndexSwitch, "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.
Please add a comment like
// to enable new paths in environment.NewPaths()
integration_test/update_test.go
Outdated
if len(out) == 0 { | ||
t.Error("no plugins in index foo after update") | ||
} |
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 should be enough to look for two plugin names in the output. For example, ctx
and foo/ctx
.
@@ -132,6 +149,9 @@ func ensureIndexUpdated(_ *cobra.Command, _ []string) error { | |||
// TODO(chriskim06) consider commenting this out when refactoring for custom indexes | |||
showUpdatedPlugins(os.Stderr, preUpdateIndex, posUpdateIndex, installedPlugins) | |||
|
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’ve realized this if (+counting) isnt necessary since errors.Wrap already handles nil err. Maybe remove?
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.
Sure I can do that. Do you think it will look weird if this ends with the return errors.Wrapf(...)
?
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’s fine. I just realized the check is redundant.
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.
Ok I'll remove the check then.
integration_test/update_test.go
Outdated
t.Error("expected update to fail") | ||
} | ||
if !strings.Contains(string(out), "failed to update the following indexes: foo") { | ||
t.Error("expected index update to fail for foo") |
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.
Try doing this for debuggability:
%q doesn’t contain msg=%q
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.
What are the two strings in the example you gave? I'm guessing the output of krew update
and foo
but want to make sure.
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.
Out & “failed to ...foo”
You can export latter into a variable.
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: ahmetb, chriskim06 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 |
Here's the first part to getting update to work with multiple indexes (second part to show updated/new plugins is in progress).
I extracted some of the new code that was added for search into the
namingutils.go
file. I'm not exactly sure it fits there, it was originally namedutils.go
where I think it could have made more sense. Let me know if this isn't the right place to put the functionality to get a list of index name/URLs. I also moved the helper function for creating an empty git repo to a method onTempDir
to use in the new test.Related issue: #483
/area multi-index