diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1176519 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,17 @@ +.gitignore +.dockerignore +Dockerfile +.github/ +.git/ +*.log +.goac/ +.goacproject.yaml +.semver.yaml +coverage.out +goac +*_test.go +README.md +LICENSE +Makefile +.DS_Store +.idea \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0a271a6..9f57f20 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ go.work .goac goac -.idea \ No newline at end of file +.idea +.DS_Store \ No newline at end of file diff --git a/.goacproject.yaml b/.goacproject.yaml index 15f1737..33fe2d3 100644 --- a/.goacproject.yaml +++ b/.goacproject.yaml @@ -8,10 +8,11 @@ target: - build - -ldflags=-s -w - -o + - "{{project-path}}/{{project-name}}" + - "{{project-path}}" build-image: + envs: + - key: PROJECT_PATH + value: "{{project-path}}" exec: - cmd: go - params: - - build - - -ldflags=-s -w - - -o \ No newline at end of file + cmd: ./_scripts/build-image.sh \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..30333a3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +FROM golang:1.22-bookworm AS builder + +# Set Go env +ENV GOOS=linux CGO_ENABLED=0 + +WORKDIR /workspace + +# Build Go binary +COPY . . +RUN --mount=type=cache,mode=0755,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + go mod download +RUN --mount=type=cache,mode=0755,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + CGO_ENABLED=0 go build -ldflags="-s -w" -o /workspace/goac + +# Deployment container +FROM gcr.io/distroless/static-debian12 + +COPY --from=builder /workspace/goac /goac +ENTRYPOINT ["/goac"] diff --git a/_scripts/build-image.sh b/_scripts/build-image.sh new file mode 100755 index 0000000..18f44ef --- /dev/null +++ b/_scripts/build-image.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -e + +: "${PUSH_IMAGE="false"}" + +: "${REPOSITORY="kperreau/goac"}" + +: "${PROJECT_PATH="."}" # project path (must be where the Dockerfile is) + +DOCKERFILE="${PROJECT_PATH}/Dockerfile" + +GIT_VERSION=$(git rev-parse --short=7 HEAD) + +dockerCmd=(docker buildx build --platform="linux/amd64,linux/arm64" --network host) + +if [[ "${PUSH_IMAGE}" == "true" ]]; then + dockerCmd+=(--push); +fi + +# print cmd +echo "${dockerCmd[@]}" \ + -t "${REPOSITORY}:latest" \ + -t "${REPOSITORY}:${GIT_VERSION}" \ + -f "${DOCKERFILE}" \ + . + +# run docker build +"${dockerCmd[@]}" \ + -t "${REPOSITORY}:latest" \ + -t "${REPOSITORY}:${GIT_VERSION}" \ + -f "${DOCKERFILE}" \ + . \ No newline at end of file diff --git a/cmd/affected.go b/cmd/affected.go index 501ced9..b6ed567 100644 --- a/cmd/affected.go +++ b/cmd/affected.go @@ -22,7 +22,6 @@ var affectedCmd = &cobra.Command{ t := project.StringToTarget(target) if project.StringToTarget(target) != project.TargetNone { projectsList, err := project.NewProjectsList(&project.Options{ - Path: ".", Target: t, DryRun: dryrun, MaxConcurrency: concurrency, diff --git a/cmd/list.go b/cmd/list.go index c05d3a0..e0a7995 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -25,7 +25,6 @@ var listCmd = &cobra.Command{ } listProject, err := project.NewProjectsList(&project.Options{ - Path: ".", Target: project.TargetNone, MaxConcurrency: concurrency, BinaryCheck: binaryCheck, diff --git a/pkg/project/affected.go b/pkg/project/affected.go index b482ed9..640af16 100644 --- a/pkg/project/affected.go +++ b/pkg/project/affected.go @@ -55,7 +55,7 @@ func processAffected(p *Project, opts *processAffectedOptions) { isAffected := p.isAffected() if isAffected && p.CMDOptions.DryRun { - printer.Printf("%s %s %s\n", color.BlueString(p.Name), color.YellowString("=>"), p.Path) + printer.Printf("%s %s %s\n", color.BlueString(p.Name), color.YellowString("=>"), p.CleanPath) } if p.CMDOptions.DryRun || !isAffected { @@ -91,7 +91,7 @@ func (p *Project) isAffected() bool { return true } - if p.CMDOptions.BinaryCheck && !utils.FileExist(path.Join(p.Path, p.Name)) { + if p.CMDOptions.BinaryCheck && !utils.FileExist(path.Join(p.CleanPath, p.Name)) { return true } diff --git a/pkg/project/affected_test.go b/pkg/project/affected_test.go index 938a4db..225585d 100644 --- a/pkg/project/affected_test.go +++ b/pkg/project/affected_test.go @@ -52,8 +52,8 @@ func TestIsAffected_BinaryCheckFalse_ReturnFalse(t *testing.T) { DirHash: "hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -81,8 +81,8 @@ func TestIsAffected_BinaryCheckTrue_ReturnTrue(t *testing.T) { DirHash: "hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -110,8 +110,8 @@ func TestIsAffected_DiffHash_ReturnTrue(t *testing.T) { DirHash: "new-hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -176,8 +176,8 @@ func TestCountAffected_OneProject(t *testing.T) { DirHash: "hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -213,8 +213,8 @@ func TestCountAffected_OneProjectOfTwo(t *testing.T) { DirHash: "hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -234,8 +234,8 @@ func TestCountAffected_OneProjectOfTwo(t *testing.T) { DirHash: "hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -270,8 +270,8 @@ func TestCountAffected_TwoProjects(t *testing.T) { DirHash: "new-hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -291,8 +291,8 @@ func TestCountAffected_TwoProjects(t *testing.T) { DirHash: "new-hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -346,8 +346,8 @@ func TestAffected_Prints1AffectedProjects(t *testing.T) { DirHash: "hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -369,8 +369,8 @@ func TestAffected_Prints1AffectedProjects(t *testing.T) { DirHash: "hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -413,8 +413,8 @@ func TestAffected_MaxConcurrencyZero(t *testing.T) { DirHash: "hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { @@ -450,8 +450,8 @@ func TestProcessAffected_BuildAffectedProject(t *testing.T) { DirHash: "hash", Date: "date", }, - Path: ".", - Name: "goac", + CleanPath: ".", + Name: "goac", Cache: &Cache{ Target: map[Target]*Metadata{ TargetBuild: { diff --git a/pkg/project/build.go b/pkg/project/build.go index 7c2e1d1..e2a6f99 100644 --- a/pkg/project/build.go +++ b/pkg/project/build.go @@ -3,20 +3,21 @@ package project import ( "bytes" "fmt" - "os" - "os/exec" - "path" - "github.com/fatih/color" "github.com/kperreau/goac/pkg/printer" + "os" + "os/exec" + "strings" ) func (p *Project) build() error { printer.Printf("Building %s...\n", color.HiBlueString(p.Name)) - params := append(p.Target[p.CMDOptions.Target].Exec.Params, path.Join(p.GoPath, p.Name), p.GoPath) + + // replace variables env and params to proper values + replaceAllVariables(p) var stderr bytes.Buffer - cmd := exec.Command(p.Target[p.CMDOptions.Target].Exec.CMD, params...) + cmd := exec.Command(p.Target[p.CMDOptions.Target].Exec.CMD, p.Target[p.CMDOptions.Target].Exec.Params...) setEnv(p, cmd) cmd.Stderr = &stderr output, err := cmd.Output() @@ -32,6 +33,28 @@ func (p *Project) build() error { } func setEnv(p *Project, cmd *exec.Cmd) { - cmd.Env = append(os.Environ(), fmt.Sprintf("BUILD_NAME=%s", p.Name)) - cmd.Env = append(cmd.Env, fmt.Sprintf("PROJECT_PATH=%s", p.GoPath)) + cmd.Env = os.Environ() + for _, env := range p.Target[p.CMDOptions.Target].Envs { + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", env.Key, env.Value)) + } +} + +func replaceAllVariables(p *Project) { + // init variables + variables := map[string]string{ + "{{project-name}}": p.Name, + "{{project-path}}": p.Path, + } + + for i := range p.Target[p.CMDOptions.Target].Envs { + for search, replace := range variables { + p.Target[p.CMDOptions.Target].Envs[i].Value = strings.ReplaceAll(p.Target[p.CMDOptions.Target].Envs[i].Value, search, replace) + } + } + + for i := range p.Target[p.CMDOptions.Target].Exec.Params { + for search, replace := range variables { + p.Target[p.CMDOptions.Target].Exec.Params[i] = strings.ReplaceAll(p.Target[p.CMDOptions.Target].Exec.Params[i], search, replace) + } + } } diff --git a/pkg/project/build_test.go b/pkg/project/build_test.go index f13c0b4..93435b1 100644 --- a/pkg/project/build_test.go +++ b/pkg/project/build_test.go @@ -2,7 +2,6 @@ package project import ( "bytes" - "fmt" "io" "log" "os" @@ -15,8 +14,8 @@ import ( func TestBuild_WithDefaultParameters(t *testing.T) { tmp, _ := os.MkdirTemp("", "test-build") p := &Project{ - Name: "test-project", - GoPath: tmp, + Name: "test-project", + Path: tmp, Target: map[Target]*TargetConfig{ TargetBuild: { Exec: &Exec{ @@ -129,14 +128,65 @@ func redirectBuildStdout(f func() error) (*bytes.Buffer, error) { return &buf, err } -func TestSetEnv_BuildName(t *testing.T) { - p := &Project{Name: "test-project", GoPath: "."} +func TestSetEnv_SetEnvironmentVariables(t *testing.T) { + p := &Project{ + Name: "goac", + Path: ".", + Target: map[Target]*TargetConfig{ + TargetBuild: { + Envs: []Env{ + {Key: "ENV_TEST", Value: "hello"}, + {Key: "BUILD_NAME", Value: "goac"}, + {Key: "PROJECT_PATH", Value: "."}, + }, + }, + }, + CMDOptions: &Options{ + Target: TargetBuild, + }, + } cmd := &exec.Cmd{} setEnv(p, cmd) + expectedEnv := append( os.Environ(), - fmt.Sprintf("BUILD_NAME=%s", p.Name), - fmt.Sprintf("PROJECT_PATH=%s", p.GoPath), + "ENV_TEST=hello", + "BUILD_NAME=goac", + "PROJECT_PATH=.", ) assert.Equal(t, expectedEnv, cmd.Env) } + +func TestReplaceAllVariables_ReplaceVariables(t *testing.T) { + p := &Project{ + Name: "goac", + Path: ".", + Target: map[Target]*TargetConfig{ + TargetBuild: { + Envs: []Env{ + {Key: "PROJECT_NAME", Value: "{{project-name}}"}, + {Key: "PROJECT_PATH", Value: "{{project-path}}"}, + }, + Exec: &Exec{ + CMD: "echo", + Params: []string{"{{project-name}}", "{{project-path}}"}, + }, + }, + }, + CMDOptions: &Options{ + Target: TargetBuild, + }, + } + + replaceAllVariables(p) + + expectedEnvName := p.Name + expectedEnvPath := p.Path + assert.Equal(t, expectedEnvName, p.Target[TargetBuild].Envs[0].Value) + assert.Equal(t, expectedEnvPath, p.Target[TargetBuild].Envs[1].Value) + + expectedParamName := p.Name + expectedParamPath := p.Path + assert.Equal(t, expectedParamName, p.Target[TargetBuild].Exec.Params[0]) + assert.Equal(t, expectedParamPath, p.Target[TargetBuild].Exec.Params[1]) +} diff --git a/pkg/project/cache.go b/pkg/project/cache.go index c8cd445..661af23 100644 --- a/pkg/project/cache.go +++ b/pkg/project/cache.go @@ -20,7 +20,7 @@ func (p *Project) LoadCache() error { cacheFilePath := fmt.Sprintf("%s%s.yaml", DefaultCachePath, p.HashPath) // init a default basic cache - cacheData := Cache{Path: p.Path, Target: map[Target]*Metadata{}} + cacheData := Cache{Path: p.CleanPath, Target: map[Target]*Metadata{}} if _, err := os.Stat(cacheFilePath); os.IsNotExist(err) { p.Cache = &cacheData diff --git a/pkg/project/cache_test.go b/pkg/project/cache_test.go index 8f67a02..8be0091 100644 --- a/pkg/project/cache_test.go +++ b/pkg/project/cache_test.go @@ -13,9 +13,9 @@ import ( func TestLoadCache_LoadsCacheDataFromFileIfExists(t *testing.T) { // Initialize the class object p := &Project{ - Cache: &Cache{}, - HashPath: "hash", - Path: "path", + Cache: &Cache{}, + HashPath: "hash", + CleanPath: "path", } // Create a temporary directory @@ -29,7 +29,7 @@ func TestLoadCache_LoadsCacheDataFromFileIfExists(t *testing.T) { // Create a temporary cache file cacheFilePath := fmt.Sprintf("%s%s.yaml", DefaultCachePath, p.HashPath) cacheData := Cache{ - Path: p.Path, + Path: p.CleanPath, Target: map[Target]*Metadata{ TargetBuild: { DependenciesHash: "hash", @@ -53,9 +53,9 @@ func TestLoadCache_LoadsCacheDataFromFileIfExists(t *testing.T) { func TestLoadCache_InitializesDefaultCacheIfFileDoesNotExist(t *testing.T) { // Initialize the class object p := &Project{ - Cache: &Cache{}, - HashPath: "hash", - Path: "path", + Cache: &Cache{}, + HashPath: "hash", + CleanPath: "path", } DefaultCachePath = "not-exist" // override DefaultCachePath @@ -67,16 +67,16 @@ func TestLoadCache_InitializesDefaultCacheIfFileDoesNotExist(t *testing.T) { // Assert that a default cache is initialized assert.NoError(t, err) - assert.Equal(t, p.Path, p.Cache.Path) + assert.Equal(t, p.CleanPath, p.Cache.Path) assert.Empty(t, p.Cache.Target) } func TestLoadCache_ReturnsErrorIfCacheFileCannotBeRead(t *testing.T) { // Initialize the class object p := &Project{ - Cache: &Cache{}, - HashPath: "hash", - Path: "path", + Cache: &Cache{}, + HashPath: "hash", + CleanPath: "path", } // Create a temporary directory @@ -102,9 +102,9 @@ func TestLoadCache_ReturnsErrorIfCacheFileCannotBeRead(t *testing.T) { func TestLoadCache_ReturnsErrorIfCacheFileCannotBeUnmarshaled(t *testing.T) { // Initialize the class object p := &Project{ - Cache: &Cache{}, - HashPath: "hash", - Path: "path", + Cache: &Cache{}, + HashPath: "hash", + CleanPath: "path", } // Create a temporary directory diff --git a/pkg/project/hash_test.go b/pkg/project/hash_test.go index 79c56fe..780b1e8 100644 --- a/pkg/project/hash_test.go +++ b/pkg/project/hash_test.go @@ -15,12 +15,12 @@ import ( func TestLoadHashs_Success(t *testing.T) { p := &Project{ - Version: "1.0", - Name: "TestProject", - Path: ".", - Target: make(map[Target]*TargetConfig), - GoPath: ".", - HashPath: ".", + Version: "1.0", + Name: "TestProject", + CleanPath: ".", + Target: make(map[Target]*TargetConfig), + Path: ".", + HashPath: ".", Module: &Module{ LocalDirs: []string{"."}, ExternalDeps: []string{"dep1", "dep2"}, diff --git a/pkg/project/list.go b/pkg/project/list.go index 03d732a..48c91d5 100644 --- a/pkg/project/list.go +++ b/pkg/project/list.go @@ -10,6 +10,6 @@ const configFileName = ".goacproject.yaml" func (l *List) List() { printer.Printf("Found %s projects\n", color.YellowString("%d", len(l.Projects))) for _, project := range l.Projects { - printer.Printf("%s %s %s\n", color.BlueString(project.Name), color.YellowString("=>"), project.Path) + printer.Printf("%s %s %s\n", color.BlueString(project.Name), color.YellowString("=>"), project.CleanPath) } } diff --git a/pkg/project/list_test.go b/pkg/project/list_test.go index cc3cd29..b28f6b0 100644 --- a/pkg/project/list_test.go +++ b/pkg/project/list_test.go @@ -14,8 +14,8 @@ func TestList_PrintsNumberOfProjects(t *testing.T) { // Initialize the List object l := &List{ Projects: []*Project{ - {Name: "Project1", Path: "/path/to/project1"}, - {Name: "Project2", Path: "/path/to/project2"}, + {Name: "Project1", CleanPath: "/path/to/project1"}, + {Name: "Project2", CleanPath: "/path/to/project2"}, }, Options: &Options{}, } @@ -48,7 +48,7 @@ func TestList_HandlesProjectsWithEmptyName(t *testing.T) { // Initialize the List object with a project with empty name l := &List{ Projects: []*Project{ - {Name: "", Path: "."}, + {Name: "", CleanPath: "."}, }, Options: &Options{}, } diff --git a/pkg/project/message_test.go b/pkg/project/message_test.go index 9bc2f7a..01f6861 100644 --- a/pkg/project/message_test.go +++ b/pkg/project/message_test.go @@ -14,7 +14,7 @@ func TestPrintAffected_1AffectedAnd1Project(t *testing.T) { // Initialize the List object l := &List{ Projects: []*Project{ - {Name: "Project1", Path: "/path/to/project1", CMDOptions: &Options{DryRun: true, Force: true}}, + {Name: "Project1", CleanPath: "/path/to/project1", CMDOptions: &Options{DryRun: true, Force: true}}, }, Options: &Options{ DryRun: true, @@ -41,7 +41,7 @@ func TestPrintAffected_0AffectedAnd1Project(t *testing.T) { l := &List{ Projects: []*Project{ { - Name: "Project1", Path: "/path/to/project1", + Name: "Project1", CleanPath: "/path/to/project1", CMDOptions: opts, Metadata: &Metadata{ DependenciesHash: "a", diff --git a/pkg/project/modules.go b/pkg/project/modules.go index c2f9cc0..7347f71 100644 --- a/pkg/project/modules.go +++ b/pkg/project/modules.go @@ -31,7 +31,7 @@ type toolData struct { } func (p *Project) LoadGOModules(gomod *modfile.File) error { - cmd := exec.Command("go", "list", "-json", p.GoPath) + cmd := exec.Command("go", "list", "-json", p.Path) output, err := cmd.Output() if err != nil { return err @@ -42,7 +42,7 @@ func (p *Project) LoadGOModules(gomod *modfile.File) error { return err } - localDir, extDeps := cleanDeps(&rawData, p.GoPath) + localDir, extDeps := cleanDeps(&rawData, p.Path) p.Module = &Module{ LocalDirs: localDir, diff --git a/pkg/project/modules_test.go b/pkg/project/modules_test.go index 94bab7a..b4e5aa6 100644 --- a/pkg/project/modules_test.go +++ b/pkg/project/modules_test.go @@ -14,8 +14,8 @@ import ( func TestLoadGOModules_LoadsModuleData(t *testing.T) { // Initialize the class object p := &Project{ - Name: "test-project", - GoPath: "./../..", + Name: "test-project", + Path: "./../..", } mfile, _ := loadGOModFile("../..") diff --git a/pkg/project/project.go b/pkg/project/project.go index 8848550..5d26240 100644 --- a/pkg/project/project.go +++ b/pkg/project/project.go @@ -18,12 +18,18 @@ import ( "github.com/kperreau/goac/pkg/printer" ) +type Env struct { + Key string + Value string +} + type Exec struct { CMD string Params []string } type TargetConfig struct { + Envs []Env Exec *Exec } @@ -31,8 +37,8 @@ type Project struct { Version string Name string Path string + CleanPath string Target map[Target]*TargetConfig - GoPath string HashPath string Module *Module HashPool *sync.Pool @@ -53,7 +59,6 @@ type List struct { } type Options struct { - Path string Target Target DryRun bool MaxConcurrency int @@ -106,12 +111,12 @@ func loadConfig(file string, opts *processProjectOptions) (*Project, error) { printer.Errorf("failed to unmarshal project config: %s", err.Error()) return nil, err } - project.Path = utils.CleanPath(file, configFileName) - project.GoPath = utils.AddCurrentDirPrefix(project.Path) + project.CleanPath = utils.CleanPath(file, configFileName) + project.Path = utils.AddCurrentDirPrefix(project.CleanPath) project.HashPool = opts.hashPool project.CMDOptions = opts.Options - hashPath, err := hasher.WithPool(opts.hashPool, project.Path) + hashPath, err := hasher.WithPool(opts.hashPool, project.CleanPath) if err != nil { return nil, fmt.Errorf("error hashing files: %w", err) } @@ -131,7 +136,7 @@ type processProjectOptions struct { } func getProjects(opt *Options) (projects []*Project, err error) { - projectsFiles, err := find(opt.Path, configFileName) + projectsFiles, err := find(".", configFileName) if err != nil { return nil, err } diff --git a/pkg/project/rule.go b/pkg/project/rule.go index 1e34471..a0e5a66 100644 --- a/pkg/project/rule.go +++ b/pkg/project/rule.go @@ -26,7 +26,7 @@ func (p *Project) LoadRule(target Target) { } // add .dockerignore entries to the exclude files rules - dockerIgnoreFiles, err := dockerignore.ReadIgnoreFile(filepath.Clean(fmt.Sprintf("%s/.dockerignore", p.Path))) + dockerIgnoreFiles, err := dockerignore.ReadIgnoreFile(filepath.Clean(fmt.Sprintf("%s/.dockerignore", p.CleanPath))) if err == nil { p.Rule.Excludes = utils.AppendIfNotExist(p.Rule.Excludes, dockerIgnoreFiles...) } diff --git a/pkg/scan/scan.go b/pkg/scan/scan.go index b30ab56..7127dbc 100644 --- a/pkg/scan/scan.go +++ b/pkg/scan/scan.go @@ -29,6 +29,15 @@ func subDir(dir string, rule *Rule) (files []string, err error) { return err } + // Skip if we match excludes patterns + if fileMatch(info.Name(), rule.Excludes) { + //fmt.Println("dir1", info.IsDir(), info.Name()) + if info.IsDir() { + return filepath.SkipDir + } + return nil + } + if info.IsDir() { return nil } else if file == dir { @@ -36,10 +45,11 @@ func subDir(dir string, rule *Rule) (files []string, err error) { return filepath.SkipDir } - // Skip if - // we have includes patterns, and we don't match it - // we match excludes patterns - if (len(rule.Includes) > 0 && !fileMatch(info.Name(), rule.Includes)) || fileMatch(info.Name(), rule.Excludes) { + // Skip if we have includes patterns, and we don't match it + if len(rule.Includes) > 0 && !fileMatch(info.Name(), rule.Includes) { + if info.IsDir() { + return filepath.SkipDir + } return nil } diff --git a/pkg/scan/scan_test.go b/pkg/scan/scan_test.go index 3bef1f2..abce4fb 100644 --- a/pkg/scan/scan_test.go +++ b/pkg/scan/scan_test.go @@ -1,6 +1,7 @@ package scan import ( + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -48,12 +49,13 @@ func TestDirs_ReturnsErrorWhenDirectoryDoesNotExist(t *testing.T) { func TestSubDir_ValidDirectoryAndRule_ReturnsListOfFiles(t *testing.T) { // Create a mock rule rule := &Rule{ - Excludes: []string{".*"}, + Excludes: []string{".DS_Store"}, Includes: []string{"*.go"}, } // Call the subDir function files, err := subDir(".", rule) + fmt.Println("files", files) // Assert that the function returns the expected result assert.NoError(t, err) @@ -63,7 +65,7 @@ func TestSubDir_ValidDirectoryAndRule_ReturnsListOfFiles(t *testing.T) { func TestSubDir_ValidDirectoryAndRuleExcludeTestFiles_ReturnsListOfFiles(t *testing.T) { // Create a mock rule rule := &Rule{ - Excludes: []string{".*", "*_test.go"}, + Excludes: []string{".DS_Store", "*_test.go"}, Includes: []string{"*.go"}, } @@ -78,7 +80,7 @@ func TestSubDir_ValidDirectoryAndRuleExcludeTestFiles_ReturnsListOfFiles(t *test func TestSubDir_ValidDirectoryAndRuleOnlyGO_ReturnsListOfFiles(t *testing.T) { // Create a mock rule rule := &Rule{ - Excludes: []string{".*", "*_test.go"}, + Excludes: []string{".DS_Store", "*_test.go"}, Includes: []string{"*.go"}, } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index bfbed85..786c99b 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -12,7 +12,7 @@ func CleanPath(path string, filename string) string { } func AddCurrentDirPrefix(path string) string { - if !strings.HasPrefix(path, "./") && !strings.HasPrefix(path, "/") { + if path != "." && !strings.HasPrefix(path, "./") && !strings.HasPrefix(path, "/") { return "./" + path } return path