From 89c25e27ca15347cff47ed3df81e4d88d5166a0f Mon Sep 17 00:00:00 2001 From: Curtis Schlak <156-curtis@users.noreply.gitlab.galvanize.com> Date: Sun, 24 Mar 2024 13:36:03 -0500 Subject: [PATCH] Add .gitignore behavior in autoconfig.yaml generation and preview This commit uses the go-gitignore library to parse a .gitignore file in the target directory should it exist. It then prevents files from being added to the autoconfig.yaml and, in the case of preview, the ZIP file that contains the contents of the repo. --- app/cmd/config.go | 66 +++++++++++++++++++++- app/cmd/preview.go | 19 ++++++- app/cmd/preview_test.go | 35 +++++++++++- fixtures/test-block-auto-config/.gitignore | 2 + go.mod | 2 + go.sum | 4 ++ 6 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 fixtures/test-block-auto-config/.gitignore diff --git a/app/cmd/config.go b/app/cmd/config.go index bc1a437..e529d67 100644 --- a/app/cmd/config.go +++ b/app/cmd/config.go @@ -14,6 +14,8 @@ import ( "sort" "strings" + gitignore "github.com/denormal/go-gitignore" + yaml "gopkg.in/yaml.v2" ) @@ -66,6 +68,60 @@ type ContentFileAttrs struct { fromHeader bool // fromHeader is set true when the attrs were parsed from the header } +type emptyGitIgnore struct{} +type alwaysMatch struct { + path string +} + +func (am *alwaysMatch) Ignore() bool { + return false +} + +func (am *alwaysMatch) Include() bool { + return true +} + +func (am *alwaysMatch) String() string { + return am.path +} + +func (am *alwaysMatch) Position() gitignore.Position { + return gitignore.Position{am.path, 0, 0, 0} +} + +func (gi emptyGitIgnore) Base() string { + return "" +} + +func (gi emptyGitIgnore) Match(path string) gitignore.Match { + return &alwaysMatch{path} +} + +func (gi emptyGitIgnore) Absolute(path string, something bool) gitignore.Match { + return &alwaysMatch{path} +} + +func (gi emptyGitIgnore) Relative(path string, something bool) gitignore.Match { + return &alwaysMatch{path} +} + +func (gi emptyGitIgnore) Ignore(path string) bool { + return false +} + +func (gi emptyGitIgnore) Include(path string) bool { + return true +} + +func NewGitIgnore(repoPath string) gitignore.GitIgnore { + ignore, err := gitignore.NewRepository(repoPath) + if err != nil { + fmt.Fprintf(os.Stdout, "Did not find gitignore in %s\n", repoPath) + ignore = emptyGitIgnore{} + } + return ignore +} + var gitTopLevelCmd = "git rev-parse --show-toplevel" // only used from publish, just going to send @@ -237,6 +293,8 @@ func (cb *ConfigBuilder) newConfigYaml() (ConfigYaml, error) { } sort.Strings(unitKeys) + ignore := NewGitIgnore(cb.target) + formattedTargetName := formattedName(cb.target) for _, unit := range unitKeys { parts := strings.Split(unit, "/") @@ -271,6 +329,10 @@ func (cb *ConfigBuilder) newConfigYaml() (ConfigYaml, error) { } for _, contentFile := range unitToContentFileMap[unit] { + match := ignore.Relative(contentFile.Path, false) + if match != nil && match.Ignore() { + continue + } if anyMatchingPrefix("/"+contentFile.Path, cb.excludePaths) { continue } @@ -316,7 +378,9 @@ func (cb *ConfigBuilder) newConfigYaml() (ConfigYaml, error) { } } } - config.Standards = append(config.Standards, standard) + if len(standard.ContentFiles) > 0 { + config.Standards = append(config.Standards, standard) + } } return config, nil diff --git a/app/cmd/preview.go b/app/cmd/preview.go index 9a613c8..9d5f4a9 100644 --- a/app/cmd/preview.go +++ b/app/cmd/preview.go @@ -165,6 +165,8 @@ func (p *previewBuilder) compressDirectory(zipTarget string) error { baseDir = filepath.Base(p.target) } + ignore := NewGitIgnore(p.target) + // Walk the whole filepath filepath.Walk(p.target, func(path string, info os.FileInfo, err error) error { path = filepath.ToSlash(path) @@ -189,8 +191,21 @@ func (p *previewBuilder) compressDirectory(zipTarget string) error { var isConfigFile = strings.Contains(path, "config.yml") || strings.Contains(path, "config.yaml") || strings.Contains(path, "autoconfig.yaml") ext := filepath.Ext(path) + + isGitIgnored := false + if !info.IsDir() { + relPath, relPathErr := filepath.Rel(p.target, path) + if relPathErr == nil { + match := ignore.Relative(relPath, false) + if match != nil && match.Ignore() { + isGitIgnored = true + } + fmt.Printf("%v %s\n", isGitIgnored, relPath) + } + } + // Ignoring all files over 1mb for preivew and warning users if the file is over 20mb that it will be ignored in publish action as well. - if !info.IsDir() && info.Size() > 1000000 && !strings.Contains(path, ".git/") { + if !isGitIgnored && !info.IsDir() && info.Size() > 1000000 && !strings.Contains(path, ".git/") { if path == "preview-curriculum.zip" { // don't warn on preview-curriculum, it gets read here but still cleaned up return nil } @@ -202,7 +217,7 @@ func (p *previewBuilder) compressDirectory(zipTarget string) error { return nil } - if isConfigFile || fileIsIncluded || (info.IsDir() && !strings.Contains(path, ".git/") && (ext != ".git" && path != "node_modules")) { + if !isGitIgnored && isConfigFile || fileIsIncluded || (info.IsDir() && !strings.Contains(path, ".git/") && (ext != ".git" && path != "node_modules")) { if err != nil { return err } diff --git a/app/cmd/preview_test.go b/app/cmd/preview_test.go index 01075bf..78e4cc6 100644 --- a/app/cmd/preview_test.go +++ b/app/cmd/preview_test.go @@ -11,6 +11,10 @@ import ( "testing" ) +const ignoredMDContent = `## Ignored + +This file should be ignored.` + const testMDContent = `## Test links ![alt](./image/nested-small.png) @@ -59,6 +63,21 @@ func Test_compressDirectory(t *testing.T) { t.Errorf("There should be paths parsed from the target") } + err = createTestFile("../../fixtures/test-block-auto-config/ignored.md", ignoredMDContent) + if err != nil { + t.Error("Could not make ignored.md") + } + + err = os.MkdirAll("../../fixtures/test-block-auto-config/ignored/", os.FileMode(0777)) + if err != nil { + t.Error("Could not make ignored/") + } + + err = createTestFile("../../fixtures/test-block-auto-config/ignored/ignored.md", ignoredMDContent) + if err != nil { + t.Error("Could not make ignored/ignored.md") + } + tmpZipFile := "../../fixtures/test-block-auto-config/preview-curriculum.zip" var challengePaths []string @@ -107,6 +126,16 @@ func Test_compressDirectory(t *testing.T) { } } + fmt.Printf("%+v", paths) + + if _, ok := paths["ignored.md"]; ok { + t.Error("ZIP should not contain ignored.md") + } + + if _, ok := paths["ignored/ignored.md"]; ok { + t.Error("ZIP should not contain ignored/ignored.md") + } + os.Remove(tmpZipFile) } @@ -551,7 +580,11 @@ func testFilesExist(t *testing.T, paths []string) { } func createTestMD(content string) error { - f, err := os.OpenFile("test.md", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + return createTestFile("test.md", content) +} + +func createTestFile(fileName string, content string) error { + f, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return err } diff --git a/fixtures/test-block-auto-config/.gitignore b/fixtures/test-block-auto-config/.gitignore new file mode 100644 index 0000000..f91d0dd --- /dev/null +++ b/fixtures/test-block-auto-config/.gitignore @@ -0,0 +1,2 @@ +ignored.md +ignored/ \ No newline at end of file diff --git a/go.mod b/go.mod index f57fe10..577840e 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,8 @@ require ( require ( github.com/VividCortex/ewma v1.1.1 // indirect + github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect + github.com/denormal/go-gitignore v0.0.0-20180930084346-ae8ad1d07817 // indirect github.com/fatih/color v1.7.0 // indirect github.com/fsnotify/fsnotify v1.4.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect diff --git a/go.sum b/go.sum index 6dd475f..7e21949 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,12 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +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.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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=