diff --git a/pkg/analysis/passes/gomanifest/gomanifest.go b/pkg/analysis/passes/gomanifest/gomanifest.go index 99cf1cea..3364fe22 100644 --- a/pkg/analysis/passes/gomanifest/gomanifest.go +++ b/pkg/analysis/passes/gomanifest/gomanifest.go @@ -73,6 +73,11 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } + goFiles, err = filterPluginGoFiles(sourceCodeDir, goFiles) + if err != nil { + return nil, err + } + if len(goFiles) == 0 { // no go files found so we can't check the manifest return nil, nil @@ -187,6 +192,32 @@ func normalizeFileName(fileName string) string { return strings.Replace(fileName, "\\", "/", -1) } +func isNodeModulesPath(fileName string) bool { + normalized := normalizeFileName(fileName) + return normalized == "node_modules" || + strings.HasPrefix(normalized, "node_modules/") || + strings.Contains(normalized, "/node_modules/") +} + +func filterPluginGoFiles(sourceCodeDir string, goFiles []string) ([]string, error) { + filteredGoFiles := make([]string, 0, len(goFiles)) + + for _, goFilePath := range goFiles { + goFileRelativePath, err := filepath.Rel(sourceCodeDir, goFilePath) + if err != nil { + return nil, err + } + + if isNodeModulesPath(goFileRelativePath) { + continue + } + + filteredGoFiles = append(filteredGoFiles, goFilePath) + } + + return filteredGoFiles, nil +} + func verifyManifest( manifest map[string]string, goFiles []string, diff --git a/pkg/analysis/passes/gomanifest/gomanifest_test.go b/pkg/analysis/passes/gomanifest/gomanifest_test.go index 93d9f967..e13849bd 100644 --- a/pkg/analysis/passes/gomanifest/gomanifest_test.go +++ b/pkg/analysis/passes/gomanifest/gomanifest_test.go @@ -1,6 +1,7 @@ package gomanifest import ( + "os" "path/filepath" "testing" @@ -218,3 +219,75 @@ func TestWindowsLineEndingsManifest(t *testing.T) { prettyprint.Print(interceptor.Diagnostics) require.Len(t, interceptor.Diagnostics, 0) } + +func TestIsNodeModulesPath(t *testing.T) { + testCases := []struct { + name string + path string + expected bool + }{ + {name: "exact node_modules", path: "node_modules", expected: true}, + {name: "root node_modules child", path: "node_modules/flatted/main.go", expected: true}, + {name: "nested node_modules child", path: "src/node_modules/flatted/main.go", expected: true}, + {name: "windows separators", path: `src\\node_modules\\flatted\\main.go`, expected: true}, + {name: "similar but different directory name", path: "node_modules2/flatted/main.go", expected: false}, + {name: "regular source path", path: "pkg/main.go", expected: false}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + require.Equal(t, tc.expected, isNodeModulesPath(tc.path)) + }) + } +} + +func TestFilterPluginGoFiles(t *testing.T) { + sourceCodeDir := filepath.Join("repo", "plugin") + goFiles := []string{ + filepath.Join(sourceCodeDir, "pkg", "main.go"), + filepath.Join(sourceCodeDir, "pkg", "subdir", "worker.go"), + filepath.Join(sourceCodeDir, "node_modules", "flatted", "main.go"), + filepath.Join(sourceCodeDir, "src", "node_modules", "dep", "dep.go"), + } + + filtered, err := filterPluginGoFiles(sourceCodeDir, goFiles) + require.NoError(t, err) + require.Equal(t, []string{ + filepath.Join(sourceCodeDir, "pkg", "main.go"), + filepath.Join(sourceCodeDir, "pkg", "subdir", "worker.go"), + }, filtered) +} + +func TestParseManifestFile_IgnoreListIsExplicit(t *testing.T) { + tempDir := t.TempDir() + manifestPath := filepath.Join(tempDir, "go_plugin_build_manifest") + manifestContent := "hash-main:pkg/main.go\n" + + "hash-ignored:node_modules/flatted/golang/pkg/flatted/flatted.go\n" + + "hash-nested:pkg/node_modules/unsafe.go\n" + + require.NoError(t, os.WriteFile(manifestPath, []byte(manifestContent), 0o600)) + + manifest, err := parseManifestFile(manifestPath) + require.NoError(t, err) + + _, hasIgnored := manifest["node_modules/flatted/golang/pkg/flatted/flatted.go"] + require.False(t, hasIgnored) + require.Equal(t, "hash-main", manifest["pkg/main.go"]) + require.Equal(t, "hash-nested", manifest["pkg/node_modules/unsafe.go"]) +} + +func TestParseManifestFile_IgnoreListWorksWithWindowsSeparators(t *testing.T) { + tempDir := t.TempDir() + manifestPath := filepath.Join(tempDir, "go_plugin_build_manifest") + manifestContent := "hash-main:pkg\\main.go\n" + + "hash-ignored:node_modules\\flatted\\golang\\pkg\\flatted\\flatted.go\n" + + require.NoError(t, os.WriteFile(manifestPath, []byte(manifestContent), 0o600)) + + manifest, err := parseManifestFile(manifestPath) + require.NoError(t, err) + + _, hasIgnored := manifest["node_modules/flatted/golang/pkg/flatted/flatted.go"] + require.False(t, hasIgnored) + require.Equal(t, "hash-main", manifest["pkg/main.go"]) +}