Skip to content

Commit 43058bc

Browse files
committed
feat(create): skip secret and generated files during scaffold copy
1 parent 32d58a7 commit 43058bc

2 files changed

Lines changed: 68 additions & 70 deletions

File tree

‎cmd/create.go‎

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ import (
1515
"github.com/spf13/cobra"
1616
)
1717

18+
var skippedTemplateDirs = map[string]struct{}{
19+
".git": {},
20+
".hackctl": {},
21+
"node_modules": {},
22+
}
23+
1824
var (
1925
createTemplate string
2026
)
@@ -56,12 +62,6 @@ var createCmd = &cobra.Command{
5662
}
5763
completeStep(stepID)
5864

59-
stepID = addStep("Updating ignore rules")
60-
if err := ensureGitignoreEntry(targetPath, ".hackctl/"); err != nil {
61-
return errors.New("could not update .gitignore")
62-
}
63-
completeStep(stepID)
64-
6565
installTargets, err := dependencyInstallTargets(targetPath)
6666
if err != nil {
6767
return err
@@ -282,39 +282,6 @@ func installDependencies(target dependencyTarget) error {
282282
return nil
283283
}
284284

285-
func ensureGitignoreEntry(projectPath string, entry string) error {
286-
gitignorePath := filepath.Join(projectPath, ".gitignore")
287-
body, err := os.ReadFile(gitignorePath)
288-
if err != nil {
289-
if errors.Is(err, os.ErrNotExist) {
290-
return os.WriteFile(gitignorePath, []byte(entry+"\n"), 0o644)
291-
}
292-
return err
293-
}
294-
295-
content := string(body)
296-
if hasGitignoreEntry(content, entry) {
297-
return nil
298-
}
299-
300-
if !strings.HasSuffix(content, "\n") {
301-
content += "\n"
302-
}
303-
content += entry + "\n"
304-
305-
return os.WriteFile(gitignorePath, []byte(content), 0o644)
306-
}
307-
308-
func hasGitignoreEntry(content string, entry string) bool {
309-
for _, line := range strings.Split(content, "\n") {
310-
if strings.TrimSpace(line) == entry {
311-
return true
312-
}
313-
}
314-
315-
return false
316-
}
317-
318285
func copyDirectory(src string, dst string) error {
319286
if err := os.MkdirAll(dst, 0o755); err != nil {
320287
return err
@@ -334,8 +301,11 @@ func copyDirectory(src string, dst string) error {
334301
return nil
335302
}
336303

337-
if d.IsDir() && d.Name() == ".git" {
338-
return filepath.SkipDir
304+
if shouldSkipTemplateEntry(d) {
305+
if d.IsDir() {
306+
return filepath.SkipDir
307+
}
308+
return nil
339309
}
340310

341311
targetPath := filepath.Join(dst, relPath)
@@ -368,3 +338,29 @@ func copyDirectory(src string, dst string) error {
368338
return nil
369339
})
370340
}
341+
342+
func shouldSkipTemplateEntry(entry os.DirEntry) bool {
343+
name := strings.ToLower(strings.TrimSpace(entry.Name()))
344+
if name == "" {
345+
return false
346+
}
347+
348+
if entry.IsDir() {
349+
_, shouldSkip := skippedTemplateDirs[name]
350+
return shouldSkip
351+
}
352+
353+
if name == ".ds_store" || name == "thumbs.db" {
354+
return true
355+
}
356+
357+
if strings.HasPrefix(name, ".env") {
358+
return !isExampleEnvFile(name)
359+
}
360+
361+
return false
362+
}
363+
364+
func isExampleEnvFile(name string) bool {
365+
return strings.HasSuffix(name, ".env.example") || strings.HasSuffix(name, ".env.sample")
366+
}

‎cmd/create_test.go‎

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,48 @@ import (
99
"github.com/hackctl/hackctl/cli/internal/config"
1010
)
1111

12-
func TestEnsureGitignoreEntryCreatesFile(t *testing.T) {
13-
dir := t.TempDir()
12+
func TestCopyDirectorySkipsSecretsAndGeneratedFiles(t *testing.T) {
13+
sourceDir := t.TempDir()
14+
destinationDir := t.TempDir()
1415

15-
if err := ensureGitignoreEntry(dir, ".hackctl/"); err != nil {
16-
t.Fatalf("unexpected error: %v", err)
16+
if err := os.WriteFile(filepath.Join(sourceDir, ".env"), []byte("SECRET=1\n"), 0o644); err != nil {
17+
t.Fatalf("could not write .env: %v", err)
1718
}
18-
19-
body, err := os.ReadFile(filepath.Join(dir, ".gitignore"))
20-
if err != nil {
21-
t.Fatalf("could not read .gitignore: %v", err)
19+
if err := os.WriteFile(filepath.Join(sourceDir, ".env.example"), []byte("SECRET=\n"), 0o644); err != nil {
20+
t.Fatalf("could not write .env.example: %v", err)
2221
}
23-
24-
if string(body) != ".hackctl/\n" {
25-
t.Fatalf("unexpected .gitignore content: %q", string(body))
22+
if err := os.WriteFile(filepath.Join(sourceDir, ".DS_Store"), []byte("junk"), 0o644); err != nil {
23+
t.Fatalf("could not write .DS_Store: %v", err)
24+
}
25+
if err := os.MkdirAll(filepath.Join(sourceDir, "frontend", "node_modules"), 0o755); err != nil {
26+
t.Fatalf("could not create node_modules: %v", err)
27+
}
28+
if err := os.WriteFile(filepath.Join(sourceDir, "frontend", "node_modules", "pkg.txt"), []byte("x"), 0o644); err != nil {
29+
t.Fatalf("could not write node_modules file: %v", err)
30+
}
31+
if err := os.WriteFile(filepath.Join(sourceDir, "frontend", "app.js"), []byte("console.log('ok')\n"), 0o644); err != nil {
32+
t.Fatalf("could not write app file: %v", err)
2633
}
27-
}
28-
29-
func TestEnsureGitignoreEntryAppendsWithoutDuplicates(t *testing.T) {
30-
dir := t.TempDir()
31-
gitignorePath := filepath.Join(dir, ".gitignore")
3234

33-
if err := os.WriteFile(gitignorePath, []byte("backend/.env\n"), 0o644); err != nil {
34-
t.Fatalf("could not write seed .gitignore: %v", err)
35+
if err := copyDirectory(sourceDir, destinationDir); err != nil {
36+
t.Fatalf("copyDirectory failed: %v", err)
3537
}
3638

37-
if err := ensureGitignoreEntry(dir, ".hackctl/"); err != nil {
38-
t.Fatalf("unexpected error on first write: %v", err)
39+
if _, err := os.Stat(filepath.Join(destinationDir, ".env")); err == nil {
40+
t.Fatalf("expected .env to be excluded")
3941
}
40-
if err := ensureGitignoreEntry(dir, ".hackctl/"); err != nil {
41-
t.Fatalf("unexpected error on second write: %v", err)
42+
if _, err := os.Stat(filepath.Join(destinationDir, ".DS_Store")); err == nil {
43+
t.Fatalf("expected .DS_Store to be excluded")
4244
}
43-
44-
body, err := os.ReadFile(gitignorePath)
45-
if err != nil {
46-
t.Fatalf("could not read .gitignore: %v", err)
45+
if _, err := os.Stat(filepath.Join(destinationDir, "frontend", "node_modules")); err == nil {
46+
t.Fatalf("expected node_modules to be excluded")
4747
}
4848

49-
expected := "backend/.env\n.hackctl/\n"
50-
if string(body) != expected {
51-
t.Fatalf("unexpected .gitignore content: %q", string(body))
49+
if _, err := os.Stat(filepath.Join(destinationDir, ".env.example")); err != nil {
50+
t.Fatalf("expected .env.example to be copied: %v", err)
51+
}
52+
if _, err := os.Stat(filepath.Join(destinationDir, "frontend", "app.js")); err != nil {
53+
t.Fatalf("expected app file to be copied: %v", err)
5254
}
5355
}
5456

0 commit comments

Comments
 (0)