From b75a7569987ee74e510cb01f09390405da9df4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E8=B5=B5=E5=98=89=E7=A8=8B521432910016?= Date: Fri, 18 Oct 2024 14:41:09 +0800 Subject: [PATCH] feat(healthcheck): forbidden check guided by `.gitignore` file (#58) (#60) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Hydraallen Co-authored-by: zzjc1234 <2359047351@qq.com> Reviewed-on: https://focs.ji.sjtu.edu.cn/git/JOJ/JOJ3/pulls/60 Reviewed-by: 张泊明518370910136 Co-authored-by: 周赵嘉程521432910016 Co-committed-by: 周赵嘉程521432910016 --- cmd/repo-health-checker/main.go | 5 +-- go.mod | 2 + go.sum | 4 ++ pkg/healthcheck/forbidden.go | 67 ++++++++++++++------------------- 4 files changed, 36 insertions(+), 42 deletions(-) diff --git a/cmd/repo-health-checker/main.go b/cmd/repo-health-checker/main.go index be152f8..91c1aae 100644 --- a/cmd/repo-health-checker/main.go +++ b/cmd/repo-health-checker/main.go @@ -39,14 +39,13 @@ var Version string // Generally, err is used for runtime errors, and checkRes is used for the result of the checks. func main() { - var gitWhitelist, metaFile []string + var metaFile []string showVersion := flag.Bool("version", false, "print current version") rootDir := flag.String("root", "", "") size := flag.Float64("repoSize", 2, "maximum size of the repo in MiB") localList := flag.String("localList", "", "") checkFileNameList := flag.String("checkFileNameList", "", "Comma-separated list of files to check.") checkFileSumList := flag.String("checkFileSumList", "", "Comma-separated list of expected checksums.") - parseMultiValueFlag(&gitWhitelist, "whitelist", "") parseMultiValueFlag(&metaFile, "meta", "") flag.Parse() if *showVersion { @@ -59,7 +58,7 @@ func main() { if err != nil { fmt.Printf("### Repo Size Check Failed:\n%s\n", err.Error()) } - err = healthcheck.ForbiddenCheck(*rootDir, gitWhitelist, *localList) + err = healthcheck.ForbiddenCheck(*rootDir) if err != nil { fmt.Printf("### Forbidden File Check Failed:\n%s\n", err.Error()) } diff --git a/go.mod b/go.mod index fdeae04..6c81d72 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.23.1 require ( github.com/criyle/go-judge v1.8.5 + github.com/denormal/go-gitignore v0.0.0-20180930084346-ae8ad1d07817 github.com/go-git/go-git/v5 v5.12.0 github.com/jinzhu/copier v0.4.0 github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7 @@ -21,6 +22,7 @@ require ( github.com/creack/pty v1.1.21 // indirect github.com/criyle/go-sandbox v0.10.4 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/camelcase v1.0.0 // indirect github.com/fatih/structs v1.1.0 // indirect diff --git a/go.sum b/go.sum index 6f4d886..614bbf5 100644 --- a/go.sum +++ b/go.sum @@ -23,9 +23,13 @@ github.com/criyle/go-sandbox v0.10.4 h1:EHJrJj5V/VSrjm1Y0ZJAea5zPASoOtn1CPZRzhTU github.com/criyle/go-sandbox v0.10.4/go.mod h1:sYJUuTmJ72Jilkc1/PO7eDdpJq3rOZ55o8MxzP80vw0= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= +github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denormal/go-gitignore v0.0.0-20180930084346-ae8ad1d07817 h1:0nsrg//Dc7xC74H/TZ5sYR8uk4UQRNjsw8zejqH5a4Q= +github.com/denormal/go-gitignore v0.0.0-20180930084346-ae8ad1d07817/go.mod h1:C/+sI4IFnEpCn6VQ3GIPEp+FrQnQw+YQP3+n+GdGq7o= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= diff --git a/pkg/healthcheck/forbidden.go b/pkg/healthcheck/forbidden.go index 2c58ab9..f7ce458 100644 --- a/pkg/healthcheck/forbidden.go +++ b/pkg/healthcheck/forbidden.go @@ -1,65 +1,54 @@ package healthcheck import ( - "bufio" "fmt" "log/slog" "os" "path/filepath" - "regexp" "strings" + + "github.com/denormal/go-gitignore" ) // getForbiddens retrieves a list of forbidden files in the specified root directory. -// It searches for files that do not match the specified regex patterns in the given file list. -func getForbiddens(root string, fileList []string, localList string) ([]string, error) { +// It searches for files that match the specified ignore patterns in the .gitignore file. +func getForbiddens(root string) ([]string, error) { var matches []string - var regexList []*regexp.Regexp - regexList, err := getRegex(fileList) + // Create a gitignore instance from the .gitignore file + ignore := gitignore.NewRepositoryWithCache(root, ".gitignore", gitignore.NewCache(), func(e gitignore.Error) bool { + return false + }) + + var err error + if err != nil { return nil, err } - var dirs []string - - if localList != "" { - file, err := os.Open(localList) - if err != nil { - return nil, fmt.Errorf("Failed to open file %s: %v\n", localList, err) - } - defer file.Close() - - scanner := bufio.NewScanner(file) - for scanner.Scan() { - dirs = append(dirs, scanner.Text()) - } - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("Error reading file %s: %v\n", localList, err) - } - } - err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { - if info.Name() == ".git" || info.Name() == ".gitea" || info.Name() == "ci" || (localList != "" && inString(info.Name(), dirs)) { + if info.Name() == ".git" { return filepath.SkipDir + } else if info.Name() == root { + return nil } - } else { - match := false - for _, regex := range regexList { - if regex.MatchString(info.Name()) { - match = true - break - } - } + } - if !match { - matches = append(matches, path) - } + // Get the relative path to the git repo root + relPath, err := filepath.Rel(root, path) + if err != nil { + return err + } + match := ignore.Relative(relPath, true) + + // Check if the relative file path should be ignored based on the .gitignore rules + if match != nil && match.Ignore() { + matches = append(matches, path) } return nil @@ -68,10 +57,10 @@ func getForbiddens(root string, fileList []string, localList string) ([]string, return matches, err } -// forbiddenCheck checks for forbidden files in the specified root directory. +// ForbiddenCheck checks for forbidden files in the specified root directory. // It prints the list of forbidden files found, along with instructions on how to fix them. -func ForbiddenCheck(rootDir string, regexList []string, localList string) error { - forbids, err := getForbiddens(rootDir, regexList, localList) +func ForbiddenCheck(rootDir string) error { + forbids, err := getForbiddens(rootDir) if err != nil { slog.Error("getting forbiddens", "error", err) return fmt.Errorf("error getting forbiddens: %w", err)