-
Notifications
You must be signed in to change notification settings - Fork 368
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
Show updated plugin manifests and available upgrades #457
Show updated plugin manifests and available upgrades #457
Conversation
Welcome @artmello! |
First of all, thanks for taking a shot at this! |
27f50e0
to
9e65c53
Compare
Hi @corneliusweig, thanks for taking a look on this! I agree that we should avoid scanning index when not necessary. I tried to implement suggested approach using This is current output:
|
For now let’s just show the same output for all (install/update/upgrade). I initially proposed we only show a summary (items combined into single line). Maybe it’s not worth it. Let’s get a feel for it. |
Hello, would like to help if it's possible, still ongoing ? |
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.
Sorry for my response time. I must have lost the notification and only stumbled over this today.
You did a great job integrating git
into this logic. But I think you can use git even more to simplify the logic (see my inline comment).
In general, I like the index summary and would love to see that merged at some point. In order to get there fast, please add tests as soon as you can. This will also force you to structure the code in a testable way.
Lastly, I think we should switch to a oneline report for starters (maybe one line per added/updated but not more :) ). Otherwise we take up too much space and people will hate the feature, because they don't see what is most relevant to them anymore.
internal/gitutil/git.go
Outdated
return modifiedFiles, nil | ||
} | ||
|
||
func exec(pwd string, args ...string) (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.
Can you add an exec
and execOut
variant, so that the out
return argument does not have to be ignored in so many places?
internal/gitutil/git.go
Outdated
|
||
var modifiedFiles []string | ||
for _, f := range strings.Split(output, "\n") { | ||
if len(f) > 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.
Simpler: if f == "" {
internal/gitutil/git.go
Outdated
} | ||
|
||
var modifiedFiles []string | ||
for _, f := range strings.Split(output, "\n") { |
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.
The only empty line is the last one, right? Then you can do this simpler as
modifiedFiles := strings.Split(strings.Trim(output), "\n")
internal/gitutil/git.go
Outdated
@@ -69,7 +70,27 @@ func EnsureUpdated(uri, destinationPath string) error { | |||
return updateAndCleanUntracked(destinationPath) | |||
} | |||
|
|||
func exec(pwd string, args ...string) error { | |||
// ListModifiedFiles will fetch origin and list modified files | |||
func ListModifiedFiles(uri, destinationPath string) ([]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.
ListModifiedFiles
is a slight misnomer, because no files are actually modified. What about ListUpstreamChanges
?
cmd/krew/cmd/update.go
Outdated
m := make(map[string]string, len(names)) | ||
for _, n := range names { | ||
plugin, err := indexscanner.LoadPluginByName(paths.IndexPluginsPath(), n) | ||
if err != 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.
You should only continue for os.IsNoExist(err)
. All other errors should abort the function.
cmd/krew/cmd/update.go
Outdated
if !ok { | ||
newPluginList = append(newPluginList, newPlugin{ | ||
name: name, | ||
version: version, | ||
}) | ||
continue | ||
} |
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 could also be a
newVersionPlugin{
...,
oldVersion: "",
installed: false,
}
That could simplify things a little. WDYT?
cmd/krew/cmd/update.go
Outdated
if len(newPluginList) > 0 { | ||
fmt.Fprintln(os.Stderr, " New plugins available:") | ||
for _, np := range newPluginList { | ||
fmt.Fprintf(os.Stderr, " * %s %s\n", np.name, np.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 think a TabWriter
would produce more legible output here.
But as far as I understand, a one-line report would be preferable anyways.
cmd/krew/cmd/update.go
Outdated
} | ||
|
||
var oldMap map[string]string | ||
if len(updatedPlugins) > 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.
If len(updatedPlugins) == 0
, you can return early here, because this means the index is already up-to-date.
internal/gitutil/git.go
Outdated
return []string{}, errors.Wrapf(err, "fetch index at %q failed", destinationPath) | ||
} | ||
|
||
output, err := exec(destinationPath, "diff", "--name-only", "@{upstream}", "--", ".") |
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.
Sorry if I come up with those ideas bit by bit. But you can also use git diff --name-status
which will add a mark each change as modified/added/deleted...
You can use that to further simplify the logic you need to build the report. I suggest that you play around with a toy git repo to see how this works. Try to offload as much as possible to git :)
Hey @corneliusweig thanks a lot for reviewing it. I will work on your comments and let you know when it is good for another round. Hey @aimbot31, thanks for the interest. I plan to work on Cornelius comments and on adding tests (as mentioned this may need some refactor). Not sure how we could split it, but let me know if you have any suggestion :) |
cmd/krew/cmd/update.go
Outdated
func retrieveInstalledPluginMap() (map[string]bool, error) { | ||
plugins, err := installation.ListInstalledPlugins(paths.InstallReceiptsPath()) | ||
if err != nil { | ||
return map[string]bool{}, 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 can use nil here.
consider wrapping err. (e.g. "failed during listing installed plugins")
cmd/krew/cmd/update.go
Outdated
return m | ||
} | ||
|
||
func retrieveInstalledPluginMap() (map[string]bool, 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.
why's the return type a map here?
you only need to just return names, i.e. []string
?
cmd/krew/cmd/update.go
Outdated
|
||
func showUpdatedPlugins(newPluginList []newPlugin, newVersionList []newVersionPlugin) { | ||
if len(newPluginList) > 0 { | ||
fmt.Fprintln(os.Stderr, " New plugins available:") |
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 would be better if you just accept out io.Writer
here, so that you don't repeat os.Stderr everywhere.
cmd/krew/cmd/update.go
Outdated
return plugins, nil | ||
} | ||
|
||
func retrievePluginNameVersionMap(names []string) map[string]string { |
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'm not convinced this should be map[string]string.
It's not great for extensibility or readability.
Feel free to either,
- just create a
type pluginInfo struct {name, version string }
, or - just return the
[]*Plugin
objects.
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 it seems like you have a type newPlugin struct
, so let's follow suit here. either create a new type or find a way of reusing.
cmd/krew/cmd/update.go
Outdated
sort.Slice(newPluginList, func(i, j int) bool { | ||
return newPluginList[i].name < newPluginList[j].name | ||
}) | ||
|
||
sort.Slice(newVersionList, func(i, j int) bool { | ||
if newVersionList[i].installed && !newVersionList[j].installed { | ||
return true | ||
} | ||
|
||
if !newVersionList[i].installed && newVersionList[j].installed { | ||
return false | ||
} | ||
|
||
return newVersionList[i].name < newVersionList[j].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.
pro-tip:
if you don't do maps (which I don't see a reason why you'd need maps here), you don't need to worry about sorting at all.
all the methods we have already are returning *index.Plugin
types sorted by name. :)
cmd/krew/cmd/update.go
Outdated
return newVersionList[i].name < newVersionList[j].name | ||
}) | ||
|
||
return newPluginList, newVersionList |
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.
shout-out to my comment above, this looks odd.
just create an internal type (struct) to carry these.
cmd/krew/cmd/update.go
Outdated
var newPluginList []newPlugin | ||
var newVersionList []newVersionPlugin |
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 I noticed throughout your coding style is how you prefix things with their types (e.g. xxxMap xxxList). let's avoid that. :)
you can simply use newPlugins
, updatedPlugins
here.
cmd/krew/cmd/update.go
Outdated
version string | ||
} | ||
|
||
type newVersionPlugin struct { |
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.
rename: updatedPlugin
cmd/krew/cmd/update.go
Outdated
"sigs.k8s.io/krew/pkg/constants" | ||
) | ||
|
||
type newPlugin struct { |
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 feel like you can simply have 1 type to carry out everything
type pluginInfo struct {
name, version string
}
If you simply return []pluginInfo
from everywhere, when the time comes to printing, just diff two []pluginInfo
slices to find the "new" and "updated" plugins.
Correct me if I'm wrong but this can even help reduce some of the code.
bea76ce
to
d2bb438
Compare
Thanks a lot for the detailed review. I tried to address all your comments, please, let me know if I missed some. Here is a sample output:
|
Can I just say: I LOVEEEEE how small this PR is. I have only 2 concerns atm:
I am on the fence about whether we should add integration tests for this? Probably not in this PR since it’s not critical functionality. |
Also it seems like there are a couple lint and test errors. |
@artmello pinging if you've still got time to pursue. it seems like we're pretty close :) |
- Do not raise an error if no index was found before an update - Do not print updated plugins output if no index was found before an update - Split output lines on chuncks of 5 plugins - Fix complains from linter
Codecov Report
@@ Coverage Diff @@
## master #457 +/- ##
=======================================
Coverage 56.52% 56.52%
=======================================
Files 19 19
Lines 927 927
=======================================
Hits 524 524
Misses 350 350
Partials 53 53 Continue to review full report at Codecov.
|
Hi @ahmetb, once again thanks for reviewing it and sorry for the sparse answers. I believe all your last comments are addressed with latest commits. Output has changed, now we are splitting plugins list on chuncks of 5.
|
/lgtm I might write a few integration tests for this. |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: ahmetb, artmello 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 |
This is great! Thanks for your contribution @artmello |
Thanks a lot @ahmetb and @corneliusweig for all the help on it. Looking forward to contribute again soon :) |
Closes #443