From 1c51f37104d49b6e085c059b541cb24b5cd4b03a Mon Sep 17 00:00:00 2001 From: Mihael Rodek Date: Mon, 9 May 2022 14:44:52 +0200 Subject: [PATCH] Updated plugin update and install to handle plugin versioning Signed-off-by: Mihael Rodek --- cmd/helm/plugin_update.go | 29 ++++++++++++++------ pkg/plugin/installer/installer.go | 4 +-- pkg/plugin/installer/vcs_installer.go | 38 ++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/cmd/helm/plugin_update.go b/cmd/helm/plugin_update.go index 4515acdbb..6a0998b20 100644 --- a/cmd/helm/plugin_update.go +++ b/cmd/helm/plugin_update.go @@ -29,16 +29,22 @@ import ( ) type pluginUpdateOptions struct { - names []string + names map[string]string + version string } +const pluginUpdateDesc = ` +This command allows you to update one or more Helm plugins. +` + func newPluginUpdateCmd(out io.Writer) *cobra.Command { o := &pluginUpdateOptions{} cmd := &cobra.Command{ - Use: "update ...", + Use: "update ...", Aliases: []string{"up"}, Short: "update one or more Helm plugins", + Long: pluginUpdateDesc, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return compListPlugins(toComplete, args), cobra.ShellCompDirectiveNoFileComp }, @@ -49,6 +55,7 @@ func newPluginUpdateCmd(out io.Writer) *cobra.Command { return o.run(out) }, } + cmd.Flags().StringVar(&o.version, "version", "", "specify a version constraint. If this is not specified, the latest version is installed") return cmd } @@ -56,7 +63,14 @@ func (o *pluginUpdateOptions) complete(args []string) error { if len(args) == 0 { return errors.New("please provide plugin name to update") } - o.names = args + o.names = make(map[string]string) + for _, arg := range args { + if strings.ContainsAny(arg, ":") { + o.names[arg[:strings.LastIndex(arg, ":")]] = arg[strings.LastIndex(arg, ":")+1:] + } else { + o.names[arg] = "" + } + } return nil } @@ -68,10 +82,9 @@ func (o *pluginUpdateOptions) run(out io.Writer) error { return err } var errorPlugins []string - - for _, name := range o.names { + for name, version := range o.names { if found := findPlugin(plugins, name); found != nil { - if err := updatePlugin(found); err != nil { + if err := updatePlugin(found, version); err != nil { errorPlugins = append(errorPlugins, fmt.Sprintf("Failed to update plugin %s, got error (%v)", name, err)) } else { fmt.Fprintf(out, "Updated plugin: %s\n", name) @@ -86,7 +99,7 @@ func (o *pluginUpdateOptions) run(out io.Writer) error { return nil } -func updatePlugin(p *plugin.Plugin) error { +func updatePlugin(p *plugin.Plugin, version string) error { exactLocation, err := filepath.EvalSymlinks(p.Dir) if err != nil { return err @@ -96,7 +109,7 @@ func updatePlugin(p *plugin.Plugin) error { return err } - i, err := installer.FindSource(absExactLocation) + i, err := installer.FindSource(absExactLocation, version) if err != nil { return err } diff --git a/pkg/plugin/installer/installer.go b/pkg/plugin/installer/installer.go index 6f01494e5..05deb87b5 100644 --- a/pkg/plugin/installer/installer.go +++ b/pkg/plugin/installer/installer.go @@ -75,8 +75,8 @@ func NewForSource(source, version string) (Installer, error) { } // FindSource determines the correct Installer for the given source. -func FindSource(location string) (Installer, error) { - installer, err := existingVCSRepo(location) +func FindSource(location, version string) (Installer, error) { + installer, err := existingVCSRepo(location, version) if err != nil && err.Error() == "Cannot detect VCS" { return installer, errors.New("cannot get information about plugin source") } diff --git a/pkg/plugin/installer/vcs_installer.go b/pkg/plugin/installer/vcs_installer.go index f7df5b322..49c93c21b 100644 --- a/pkg/plugin/installer/vcs_installer.go +++ b/pkg/plugin/installer/vcs_installer.go @@ -16,11 +16,11 @@ limitations under the License. package installer // import "helm.sh/helm/v3/pkg/plugin/installer" import ( + "github.com/Masterminds/vcs" "os" "sort" "github.com/Masterminds/semver/v3" - "github.com/Masterminds/vcs" "github.com/pkg/errors" "helm.sh/helm/v3/internal/third_party/dep/fs" @@ -35,14 +35,15 @@ type VCSInstaller struct { base } -func existingVCSRepo(location string) (Installer, error) { +func existingVCSRepo(location, version string) (Installer, error) { repo, err := vcs.NewRepo("", location) if err != nil { return nil, err } i := &VCSInstaller{ - Repo: repo, - base: newBase(repo.Remote()), + Repo: repo, + Version: version, + base: newBase(repo.Remote()), } return i, nil } @@ -82,6 +83,8 @@ func (i *VCSInstaller) Install() error { if err := i.setVersion(i.Repo, ref); err != nil { return err } + } else if err := updateToLatest(i.Repo); err != nil { + return err } if !isPlugin(i.Repo.LocalPath()) { @@ -98,7 +101,15 @@ func (i *VCSInstaller) Update() error { if i.Repo.IsDirty() { return errors.New("plugin repo was modified") } - if err := i.Repo.Update(); err != nil { + ref, err := i.solveVersion(i.Repo) + if err != nil { + return err + } + if ref != "" { + if err := i.setVersion(i.Repo, ref); err != nil { + debug(err.Error()) + } + } else if err := updateToLatest(i.Repo); err != nil { return err } if !isPlugin(i.Repo.LocalPath()) { @@ -139,7 +150,6 @@ func (i *VCSInstaller) solveVersion(repo vcs.Repo) (string, error) { if constraint.Check(v) { // If the constraint passes get the original reference ver := v.Original() - debug("setting to %s", ver) return ver, nil } } @@ -174,3 +184,19 @@ func getSemVers(refs []string) []*semver.Version { } return sv } + +func updateToLatest(repo vcs.Repo) error { + refs, err := repo.Tags() + if err != nil { + return err + } + debug("found refs: %s", refs) + + // Convert and filter the list to semver.Version instances + semvers := getSemVers(refs) + + // Sort semver list + sort.Sort(sort.Reverse(semver.Collection(semvers))) + latest := semvers[0].Original() + return repo.UpdateVersion(latest) +}