fix: resolve symlinked plugin directories in GetPluginVersion (#2661)

In nix/devbox environments, helm plugin directories are typically
symlinks into the Nix store. GetPluginVersion used entry.IsDir()
which does not follow symlinks, causing the plugin to be reported
as not installed. Follow symlinks with os.Stat before skipping
non-directory entries.

Signed-off-by: Shane Starcher <shane.starcher@gmail.com>
Co-authored-by: Shane Starcher <shane.starcher@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Shane Starcher
2026-06-23 06:59:18 +08:00
committed by GitHub
co-authored by Shane Starcher Claude Opus 4.6
parent 9b943adc9e
commit 9e66f55d23
2 changed files with 29 additions and 1 deletions
+8 -1
View File
@@ -141,7 +141,14 @@ func GetPluginVersion(name, pluginsDir string) (*semver.Version, error) {
}
for _, entry := range entries {
if !entry.IsDir() {
isDir := entry.IsDir()
if !isDir && entry.Type()&os.ModeSymlink != 0 {
info, err := os.Stat(filepath.Join(dir, entry.Name()))
if err == nil {
isDir = info.IsDir()
}
}
if !isDir {
continue
}
+21
View File
@@ -1402,6 +1402,27 @@ func Test_GetPluginVersion_XDGPaths(t *testing.T) {
assert.Contains(t, err.Error(), "plugin nonexistent-plugin not installed")
}
func Test_GetPluginVersion_Symlink(t *testing.T) {
// Simulate a nix/devbox environment where the plugin directory is a symlink
tmpDir := t.TempDir()
// Create a real plugin directory with plugin.yaml
realPluginDir := filepath.Join(tmpDir, "real", "helm-diff")
require.NoError(t, os.MkdirAll(realPluginDir, 0o755))
require.NoError(t, os.WriteFile(filepath.Join(realPluginDir, "plugin.yaml"), []byte(`name: "diff"
version: "3.12.0"
`), 0o644))
// Create a plugins directory where helm-diff is a symlink (like nix/devbox)
symlinkPluginsDir := filepath.Join(tmpDir, "plugins")
require.NoError(t, os.MkdirAll(symlinkPluginsDir, 0o755))
require.NoError(t, os.Symlink(realPluginDir, filepath.Join(symlinkPluginsDir, "helm-diff")))
version, err := GetPluginVersion("diff", symlinkPluginsDir)
require.NoError(t, err)
assert.Equal(t, "3.12.0", version.String())
}
func Test_GetVersion(t *testing.T) {
helm2Runner := mockRunner{output: []byte("Client: v2.16.1+ge13bc94\n")}
helm, err := New("helm", HelmExecOptions{}, NewLogger(os.Stdout, "info"), "", "dev", &helm2Runner)