diff --git a/pkg/helmexec/exec.go b/pkg/helmexec/exec.go index 59e18c6c..dd6edea7 100644 --- a/pkg/helmexec/exec.go +++ b/pkg/helmexec/exec.go @@ -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 } diff --git a/pkg/helmexec/exec_test.go b/pkg/helmexec/exec_test.go index 2be59612..27e609c4 100644 --- a/pkg/helmexec/exec_test.go +++ b/pkg/helmexec/exec_test.go @@ -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)