Skip to content

Commit 9223a07

Browse files
mcknclaude
andauthored
Skip node_modules directory in manifest generation (#1504)
* Skip node_modules directory in manifest generation Exclude Go files located in the node_modules directory from the plugin manifest file generated during the build process. This prevents frontend dependencies from being included in the backend plugin manifest. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Only skip root-level node_modules in manifest generation Restrict the node_modules exclusion to the root directory only so that Go files in nested node_modules directories are still included. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix errcheck lint errors in manifest tests Add writeFile and mkdirAll test helpers that check error return values, and handle the os.Chdir error in the cleanup function. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Fix gosec lint errors in manifest tests Use 0600 for file permissions and 0750 for directory permissions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent f4bfcf0 commit 9223a07

File tree

2 files changed

+199
-0
lines changed

2 files changed

+199
-0
lines changed

build/utils/manifest.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ func GenerateManifest() (string, error) {
1818
if err != nil {
1919
return err
2020
}
21+
if d.IsDir() && path == "node_modules" {
22+
return fs.SkipDir
23+
}
2124
if !d.IsDir() && strings.HasSuffix(path, ".go") {
2225
hash, err := hashFileContent(path)
2326
if err != nil {

build/utils/manifest_test.go

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package utils
2+
3+
import (
4+
"crypto/sha256"
5+
"encoding/hex"
6+
"fmt"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
"testing"
11+
)
12+
13+
// chdir changes to the given directory and registers a cleanup to restore the original.
14+
func chdir(t *testing.T, dir string) {
15+
t.Helper()
16+
prev, err := os.Getwd()
17+
if err != nil {
18+
t.Fatal(err)
19+
}
20+
t.Cleanup(func() {
21+
if err := os.Chdir(prev); err != nil {
22+
t.Logf("failed to restore working directory: %v", err)
23+
}
24+
})
25+
if err := os.Chdir(dir); err != nil {
26+
t.Fatal(err)
27+
}
28+
}
29+
30+
func writeFile(t *testing.T, path string, data []byte) {
31+
t.Helper()
32+
if err := os.WriteFile(path, data, 0600); err != nil {
33+
t.Fatal(err)
34+
}
35+
}
36+
37+
func mkdirAll(t *testing.T, path string) {
38+
t.Helper()
39+
if err := os.MkdirAll(path, 0750); err != nil {
40+
t.Fatal(err)
41+
}
42+
}
43+
44+
func sha256Hex(data []byte) string {
45+
h := sha256.Sum256(data)
46+
return hex.EncodeToString(h[:])
47+
}
48+
49+
func TestGenerateManifest_SkipsNodeModules(t *testing.T) {
50+
dir := t.TempDir()
51+
chdir(t, dir)
52+
53+
writeFile(t, "main.go", []byte("package main"))
54+
mkdirAll(t, filepath.Join("node_modules", "somepackage"))
55+
writeFile(t, filepath.Join("node_modules", "somepackage", "file.go"), []byte("package somepackage"))
56+
57+
manifest, err := GenerateManifest()
58+
if err != nil {
59+
t.Fatal(err)
60+
}
61+
62+
if !strings.Contains(manifest, "main.go") {
63+
t.Error("manifest should contain main.go")
64+
}
65+
if strings.Contains(manifest, "node_modules") {
66+
t.Error("manifest should not contain files from node_modules")
67+
}
68+
}
69+
70+
func TestGenerateManifest_OnlySkipsRootNodeModules(t *testing.T) {
71+
dir := t.TempDir()
72+
chdir(t, dir)
73+
74+
writeFile(t, "main.go", []byte("package main"))
75+
76+
// Root node_modules — should be excluded.
77+
mkdirAll(t, filepath.Join("node_modules", "pkg"))
78+
writeFile(t, filepath.Join("node_modules", "pkg", "root.go"), []byte("package pkg"))
79+
80+
// Nested node_modules inside a subdirectory — should be included.
81+
nestedNM := filepath.Join("vendor", "lib", "node_modules", "dep")
82+
mkdirAll(t, nestedNM)
83+
writeFile(t, filepath.Join(nestedNM, "nested.go"), []byte("package dep"))
84+
85+
manifest, err := GenerateManifest()
86+
if err != nil {
87+
t.Fatal(err)
88+
}
89+
90+
if strings.Contains(manifest, "root.go") {
91+
t.Error("manifest should not contain Go files from root node_modules")
92+
}
93+
if !strings.Contains(manifest, "nested.go") {
94+
t.Error("manifest should contain Go files from nested node_modules")
95+
}
96+
}
97+
98+
func TestGenerateManifest_OnlyIncludesGoFiles(t *testing.T) {
99+
dir := t.TempDir()
100+
chdir(t, dir)
101+
102+
writeFile(t, "main.go", []byte("package main"))
103+
writeFile(t, "readme.md", []byte("# readme"))
104+
writeFile(t, "config.json", []byte("{}"))
105+
writeFile(t, "script.sh", []byte("#!/bin/bash"))
106+
107+
manifest, err := GenerateManifest()
108+
if err != nil {
109+
t.Fatal(err)
110+
}
111+
112+
if !strings.Contains(manifest, "main.go") {
113+
t.Error("manifest should contain main.go")
114+
}
115+
for _, name := range []string{"readme.md", "config.json", "script.sh"} {
116+
if strings.Contains(manifest, name) {
117+
t.Errorf("manifest should not contain non-Go file %s", name)
118+
}
119+
}
120+
}
121+
122+
func TestGenerateManifest_IncludesNestedGoFiles(t *testing.T) {
123+
dir := t.TempDir()
124+
chdir(t, dir)
125+
126+
writeFile(t, "main.go", []byte("package main"))
127+
mkdirAll(t, filepath.Join("pkg", "sub"))
128+
writeFile(t, filepath.Join("pkg", "sub", "helper.go"), []byte("package sub"))
129+
130+
manifest, err := GenerateManifest()
131+
if err != nil {
132+
t.Fatal(err)
133+
}
134+
135+
if !strings.Contains(manifest, "main.go") {
136+
t.Error("manifest should contain main.go")
137+
}
138+
if !strings.Contains(manifest, "pkg/sub/helper.go") {
139+
t.Error("manifest should contain nested Go file pkg/sub/helper.go")
140+
}
141+
}
142+
143+
func TestGenerateManifest_EntryFormat(t *testing.T) {
144+
dir := t.TempDir()
145+
chdir(t, dir)
146+
147+
content := []byte("package main")
148+
writeFile(t, "main.go", content)
149+
150+
manifest, err := GenerateManifest()
151+
if err != nil {
152+
t.Fatal(err)
153+
}
154+
155+
expectedHash := sha256Hex(content)
156+
expectedLine := fmt.Sprintf("%s:main.go", expectedHash)
157+
158+
lines := strings.Split(strings.TrimSpace(manifest), "\n")
159+
if len(lines) != 1 {
160+
t.Fatalf("expected 1 manifest line, got %d", len(lines))
161+
}
162+
if lines[0] != expectedLine {
163+
t.Errorf("manifest line = %q, want %q", lines[0], expectedLine)
164+
}
165+
}
166+
167+
func TestGenerateManifest_UsesForwardSlashes(t *testing.T) {
168+
dir := t.TempDir()
169+
chdir(t, dir)
170+
171+
mkdirAll(t, filepath.Join("a", "b"))
172+
writeFile(t, filepath.Join("a", "b", "c.go"), []byte("package b"))
173+
174+
manifest, err := GenerateManifest()
175+
if err != nil {
176+
t.Fatal(err)
177+
}
178+
179+
if !strings.Contains(manifest, "a/b/c.go") {
180+
t.Errorf("manifest should use forward slashes, got: %s", manifest)
181+
}
182+
}
183+
184+
func TestGenerateManifest_EmptyDirectory(t *testing.T) {
185+
dir := t.TempDir()
186+
chdir(t, dir)
187+
188+
manifest, err := GenerateManifest()
189+
if err != nil {
190+
t.Fatal(err)
191+
}
192+
193+
if manifest != "" {
194+
t.Errorf("expected empty manifest for directory with no .go files, got: %q", manifest)
195+
}
196+
}

0 commit comments

Comments
 (0)