diff --git a/.crev-config.yaml b/.crev-config.yaml index 0a48f07..f3deebc 100644 --- a/.crev-config.yaml +++ b/.crev-config.yaml @@ -1,7 +1,9 @@ # Configuration for the crev tool # specify your Code AI Review API key (necessary for review command) -api-key: "dcds" -# specify the prefixes of files and directories to ignore (paths starting with . are always ignored) -ignore: [tests, build, readme.md, LICENSE, dist] -# specify the extensions of files to include (by default all files are included) -extensions: # ex. [.go, .py, .js] +api-key: # Fill in your CREV API key here +# specify the prefixes of files and directories to ignore (by default common configuration files are ignored) +ignore-pre: # ex. [tests, readme.md, scripts] +# specify the extensions of files to ignore +ignore-ext: [.go, .py, .js, .txt] +# specify the extensions of files to include +include-ext: # ex. [.go, .py, .js] diff --git a/cmd/generate.go b/cmd/generate.go index 559f098..886af85 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -77,11 +77,16 @@ crev generate --ignore=tests,readme.md --extensions=go,py,js // get all file paths from the root directory rootDir := "." - prefixesToFilter := viper.GetStringSlice("ignore") - // always ignore directories starting with "." + + prefixesToFilter := viper.GetStringSlice("ignore-pre") prefixesToFilter = append(prefixesToFilter, standardPrefixesToFilter...) - extensionsToKeep := viper.GetStringSlice("extensions") - filePaths, err := files.GetAllFilePaths(rootDir, prefixesToFilter, extensionsToKeep) + + extensionsToIgnore := viper.GetStringSlice("ignore-ext") + + extensionsToKeep := viper.GetStringSlice("include-ext") + + filePaths, err := files.GetAllFilePaths(rootDir, prefixesToFilter, + extensionsToKeep, extensionsToIgnore) if err != nil { log.Fatal(err) return @@ -122,13 +127,19 @@ crev generate --ignore=tests,readme.md --extensions=go,py,js func init() { rootCmd.AddCommand(generateCmd) - generateCmd.Flags().StringSlice("ignore", []string{}, "Comma-separated prefixes of paths to ignore") - generateCmd.Flags().StringSlice("extensions", []string{}, "Comma-separated file extensions to include. (default: all files)") - err := viper.BindPFlag("ignore", generateCmd.Flags().Lookup("ignore")) + // TODO Fix description with defaults + generateCmd.Flags().StringSlice("ignore-pre", []string{}, "Comma-separated prefixes of paths to ignore") + generateCmd.Flags().StringSlice("ignore-ext", []string{}, "Comma-separated file extensions to ignore") + generateCmd.Flags().StringSlice("include-ext", []string{}, "Comma-separated file extensions to include.") + err := viper.BindPFlag("ignore-pre", generateCmd.Flags().Lookup("ignore-pre")) + if err != nil { + log.Fatal(err) + } + err = viper.BindPFlag("ignore-ext", generateCmd.Flags().Lookup("ignore-ext")) if err != nil { log.Fatal(err) } - err = viper.BindPFlag("extensions", generateCmd.Flags().Lookup("extensions")) + err = viper.BindPFlag("include-ext", generateCmd.Flags().Lookup("include-ext")) if err != nil { log.Fatal(err) } diff --git a/cmd/init.go b/cmd/init.go index e2b9fbe..4ba4d18 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -14,9 +14,11 @@ var defaultConfig = []byte(`# Configuration for the crev tool # specify your Code AI Review API key (necessary for review command) api-key: # Fill in your CREV API key here # specify the prefixes of files and directories to ignore (by default common configuration files are ignored) -ignore: # ex. [tests, readme.md, scripts] -# specify the extensions of files to include (by default all files are included) -extensions: # ex. [.go, .py, .js] +ignore-pre: # ex. [tests, readme.md, scripts] +# specify the extensions of files to ignore +ignore-ext: # ex. [.go, .py, .js] +# specify the extensions of files to include +include-ext: # ex. [.go, .py, .js] `) var initCmd = &cobra.Command{ diff --git a/internal/files/reading.go b/internal/files/reading.go index ea71c87..46bf57e 100644 --- a/internal/files/reading.go +++ b/internal/files/reading.go @@ -11,7 +11,8 @@ import ( // Given a root path returns all the file paths in the root directory // and its subdirectories. -func GetAllFilePaths(root string, prefixesToFilter []string, extensionsToKeep []string) ([]string, error) { +func GetAllFilePaths(root string, prefixesToFilter []string, extensionsToKeep []string, + extensionsToIgnore []string) ([]string, error) { var filePaths []string err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { if err != nil { @@ -30,6 +31,12 @@ func GetAllFilePaths(root string, prefixesToFilter []string, extensionsToKeep [] return nil } } + // Filter out the files that have the extensions in extensionsToFilter. + for _, ext := range extensionsToIgnore { + if filepath.Ext(path) == ext { + return nil + } + } // Process file based on extension filters. if d.IsDir() || len(extensionsToKeep) == 0 { filePaths = append(filePaths, path) diff --git a/tests/files/reading_test.go b/tests/files/reading_test.go index 7094c06..04d3556 100644 --- a/tests/files/reading_test.go +++ b/tests/files/reading_test.go @@ -32,7 +32,7 @@ func TestGetAllFilePaths(t *testing.T) { filepath.Join(subDir, "file2.txt"), } - filePaths, err := files.GetAllFilePaths(rootDir, nil, nil) + filePaths, err := files.GetAllFilePaths(rootDir, nil, nil, nil) if err != nil { t.Fatalf("expected no error, got %v", err) } @@ -88,7 +88,7 @@ func TestGetAllFilePathsWithPrefixFilter(t *testing.T) { filepath.Join(subDir2, "file3.go"), } // filter out full path prefix subDir1 - filePaths, err := files.GetAllFilePaths(rootDir, []string{"subdir_1"}, nil) + filePaths, err := files.GetAllFilePaths(rootDir, []string{"subdir_1"}, nil, nil) if err != nil { t.Fatalf("expected no error, got %v", err) @@ -146,7 +146,7 @@ func TestGetAllFilePathsWithPrefixFilterNestedDir(t *testing.T) { filepath.Join(subDir3, "file2.go"), } - filePaths, err := files.GetAllFilePaths(rootDir, []string{"."}, nil) + filePaths, err := files.GetAllFilePaths(rootDir, []string{"."}, nil, nil) if err != nil { t.Fatalf("expected no error, got %v", err) @@ -170,7 +170,7 @@ func TestGetAllFilePathsWithPrefixFilterNestedDir(t *testing.T) { } } -// Tests the functionality to filter out text extensions. +// Tests the functionality to include only files with specific extensions. func TestGetAllFilePathsWithExtensionFilter(t *testing.T) { rootDir := t.TempDir() @@ -204,7 +204,7 @@ func TestGetAllFilePathsWithExtensionFilter(t *testing.T) { subDir2, } - filePaths, err := files.GetAllFilePaths(rootDir, nil, []string{".go"}) + filePaths, err := files.GetAllFilePaths(rootDir, nil, []string{".go"}, nil) if err != nil { t.Fatalf("expected no error, got %v", err) } @@ -227,6 +227,99 @@ func TestGetAllFilePathsWithExtensionFilter(t *testing.T) { } } +// Tests the functionality to exclude files with specific extensions. + +func TestGetAllFilePathsWithExtensionFilterExclude(t *testing.T) { + rootDir := t.TempDir() + + // Create subdirectories and nested subdirectories + subDir1 := filepath.Join(rootDir, "subdir_1") + err := os.Mkdir(subDir1, 0755) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + nestedSubDir1 := filepath.Join(subDir1, "nested_subdir_1") + err = os.Mkdir(nestedSubDir1, 0755) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + subDir2 := filepath.Join(rootDir, "subdir_2") + err = os.Mkdir(subDir2, 0755) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + nestedSubDir2 := filepath.Join(subDir2, "nested_subdir_2") + err = os.Mkdir(nestedSubDir2, 0755) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + // Create files in various directories + err = os.WriteFile(filepath.Join(rootDir, "file1.go"), []byte("content1"), 0644) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + err = os.WriteFile(filepath.Join(subDir1, "file2.go"), []byte("content2"), 0644) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + err = os.WriteFile(filepath.Join(nestedSubDir1, "file3.go"), []byte("content3"), 0644) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + err = os.WriteFile(filepath.Join(subDir2, "file4.txt"), []byte("content4"), 0644) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + err = os.WriteFile(filepath.Join(nestedSubDir2, "file5.md"), []byte("content5"), 0644) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + err = os.WriteFile(filepath.Join(nestedSubDir2, "file6.txt"), []byte("content6"), 0644) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + // Expected result: exclude .txt files, keep the rest + expected := []string{ + filepath.Join(rootDir, "file1.go"), + filepath.Join(subDir1, "file2.go"), + filepath.Join(nestedSubDir1, "file3.go"), + subDir1, + subDir2, + nestedSubDir1, + nestedSubDir2, + } + + // Get all file paths excluding .txt files + filePaths, err := files.GetAllFilePaths(rootDir, nil, nil, []string{".txt", ".md"}) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + // Check the number of files found + if len(filePaths) != len(expected) { + t.Fatalf("expected %d files, got %d", len(expected), len(filePaths)) + } + + // Verify that each expected file is in the result + for _, exp := range expected { + found := false + for _, fp := range filePaths { + if fp == exp { + found = true + break + } + } + if !found { + t.Errorf("expected path %s not found in result", exp) + } + } +} + // Tests the functionality to read all the content of files and directories and create a // file content map. func TestGetContentMapOfFiles(t *testing.T) {