From 467fd5df9e8697249a470afe809456fd8933d09d Mon Sep 17 00:00:00 2001 From: bhanu0710 Date: Sun, 26 Apr 2026 15:30:40 +0530 Subject: [PATCH] fix(plugin): install into first path when HELM_PLUGINS has multiple entries When HELM_PLUGINS contains a colon-separated list of directories, FindPlugins() correctly reads from all of them using filepath.SplitList(). However, plugin install was ignoring the split and falling back to the raw HELM_PLUGINS string as the destination directory instead of using the first entry. This change adds pluginInstallDir() which returns the first entry from HELM_PLUGINS when multiple paths are present, consistent with how git handles multiple path variables and matching user expectations. Fixes #11310 --- internal/plugin/installer/base.go | 17 +++++++++++- internal/plugin/installer/base_test.go | 37 ++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/internal/plugin/installer/base.go b/internal/plugin/installer/base.go index c21a245a8..acb4441e4 100644 --- a/internal/plugin/installer/base.go +++ b/internal/plugin/installer/base.go @@ -32,10 +32,25 @@ func newBase(source string) base { settings := cli.New() return base{ Source: source, - PluginsDirectory: settings.PluginsDirectory, + PluginsDirectory: pluginInstallDir(settings.PluginsDirectory), } } +// pluginInstallDir returns the directory to install a new plugin into. +// When HELM_PLUGINS contains multiple colon-separated paths, the first +// path is used as the install destination — consistent with how +// FindPlugins() loads from all paths and matching git conventions. +func pluginInstallDir(helmPlugins string) string { + if helmPlugins == "" { + return helmPlugins + } + dirs := filepath.SplitList(helmPlugins) + if len(dirs) == 0 { + return helmPlugins + } + return dirs[0] +} + // Path is where the plugin will be installed. func (b *base) Path() string { if b.Source == "" { diff --git a/internal/plugin/installer/base_test.go b/internal/plugin/installer/base_test.go index 62b77bde5..5f9851e4a 100644 --- a/internal/plugin/installer/base_test.go +++ b/internal/plugin/installer/base_test.go @@ -44,3 +44,40 @@ func TestPath(t *testing.T) { } } } + +func TestPluginInstallDir(t *testing.T) { + tests := []struct { + name string + helmPlugins string + want string + }{ + { + name: "empty string returns empty string", + helmPlugins: "", + want: "", + }, + { + name: "single path returned as-is", + helmPlugins: "/tmp/plugins", + want: "/tmp/plugins", + }, + { + name: "two paths returns first", + helmPlugins: "/tmp/abc:/tmp/xyz", + want: "/tmp/abc", + }, + { + name: "three paths returns first", + helmPlugins: "/tmp/a:/tmp/b:/tmp/c", + want: "/tmp/a", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := pluginInstallDir(tt.helmPlugins) + if got != tt.want { + t.Errorf("pluginInstallDir(%q) = %q, want %q", tt.helmPlugins, got, tt.want) + } + }) + } +}