From 9966671372c27a342b38e3727c33132c5d54b43a Mon Sep 17 00:00:00 2001 From: Ashish Bhatia Date: Sun, 8 Dec 2024 14:37:52 -0800 Subject: [PATCH] feat: add `GitHub Actions Linter` (#109) --- src/gabo/go.mod | 1 + src/gabo/go.sum | 2 + src/gabo/internal/generator/all_options.go | 82 ++++++++++--------- .../goreleaser_config_checker_generator.go | 2 +- .../openapi_schema_validator_generator.go | 2 +- 5 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/gabo/go.mod b/src/gabo/go.mod index a599868..2da3542 100644 --- a/src/gabo/go.mod +++ b/src/gabo/go.mod @@ -8,6 +8,7 @@ require ( ) require ( + github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect diff --git a/src/gabo/go.sum b/src/gabo/go.sum index e535b89..c94e032 100644 --- a/src/gabo/go.sum +++ b/src/gabo/go.sum @@ -1,3 +1,5 @@ +github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q= +github.com/bmatcuk/doublestar/v4 v4.7.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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= diff --git a/src/gabo/internal/generator/all_options.go b/src/gabo/internal/generator/all_options.go index 08be1f5..3794173 100644 --- a/src/gabo/internal/generator/all_options.go +++ b/src/gabo/internal/generator/all_options.go @@ -1,6 +1,8 @@ package generator import ( + "github.com/bmatcuk/doublestar/v4" + "io/fs" "os" "path/filepath" "strings" @@ -8,6 +10,14 @@ import ( "github.com/rs/zerolog/log" ) +const ( + _AndroidManifestFile = "**/AndroidManifest.xml" + _dockerFile = "**/Dockerfile" + _goFile = "**/*.go" + _markdownFile = "**/*.md" + _pythonFile = "**/*.py" +) + type Option interface { // E.g. "Markdown Linter" Name() string @@ -27,58 +37,58 @@ func GetOptions() []Option { return []Option{ _Option{ "Android Builder", "build-android", - newFileMatcher("AndroidManifest.xml"), + newFileMatcher(_AndroidManifestFile), newPatternMatcher("gradlew build"), newGenerator2(generateBuildAndroidYaml), "build-android.yaml", }, _Option{ "Android Linter", "lint-android", - newFileMatcher("AndroidManifest.xml"), + newFileMatcher(_AndroidManifestFile), newPatternMatcher("gradlew lint"), newGenerator(_lintAndroidYaml), "lint-android.yaml", }, _Option{ "Android Auto Translator", "translate-android", - newFileMatcher("AndroidManifest.xml"), + newFileMatcher(_AndroidManifestFile), newPatternMatcher("ashishb/android-auto-translate"), newGenerator(_translateAndroidYaml), "translate-android.yaml", }, _Option{ "Compress Images", "compress-images", - newFileMatcher("*.jpg", "*.jpeg", "*.png", "*.webp"), + newFileMatcher("**/*.jpg", "**/*.jpeg", "**/*.png", "**/*.webp"), newPatternMatcher("calibreapp/image-actions"), newGenerator(_comressImageYaml), "compress-images.yaml", }, _Option{ "Docker Builder", "build-docker", - newFileMatcher("Dockerfile"), + newFileMatcher(_dockerFile), newPatternMatcher("docker build ", "docker buildx"), newGenerator2(generateBuildDockerYaml), "build-docker.yaml", }, _Option{ - "NPM Builder", "build-npm", newFileMatcher("package-lock.json"), + "NPM Builder", "build-npm", newFileMatcher("**/package-lock.json"), newPatternMatcher("npm install "), newGenerator2(generateBuildNpmYaml), "build-npm.yaml", }, _Option{ - "Yarn Builder", "build-yarn", newFileMatcher("yarn.lock"), + "Yarn Builder", "build-yarn", newFileMatcher("**/yarn.lock"), newPatternMatcher("yarn build"), newGenerator2(generateBuildYarnYaml), "build-yarn.yaml", }, _Option{ - "Docker Linter", "lint-docker", newFileMatcher("Dockerfile"), + "Docker Linter", "lint-docker", newFileMatcher(_dockerFile), newPatternMatcher("hadolint "), newGenerator(_lintDockerYaml), "lint-docker.yaml", }, _Option{ - "Go Formatter", "format-go", newFileMatcher("*.go"), + "Go Formatter", "format-go", newFileMatcher(_goFile), newPatternMatcher("gofmt -l", "go fmt", "gofumpt "), newGenerator(_formatGoYaml), "format-go.yaml", }, _Option{ - "Go Linter", "lint-go", newFileMatcher("*.go"), + "Go Linter", "lint-go", newFileMatcher(_goFile), newPatternMatcher("golangci-lint"), newGenerator2(generateGoLintYaml), "lint-go.yaml", }, @@ -90,13 +100,13 @@ func GetOptions() []Option { }, _Option{ - "HTML Linter", "lint-html", newFileMatcher("*.html", "*.htm"), + "HTML Linter", "lint-html", newFileMatcher("**/*.html", "**/*.htm"), newPatternMatcher("htmlhint "), newGenerator(_lintHtmlYaml), "lint-html.yaml", }, _Option{ - "Markdown Linter", "lint-markdown", newFileMatcher("*.md"), + "Markdown Linter", "lint-markdown", newFileMatcher(_markdownFile), newPatternMatcher("mdl "), newGenerator(_lintMarkdownYaml), "lint-markdown.yaml", }, @@ -108,30 +118,36 @@ func GetOptions() []Option { "validate-openapi-schema.yaml", }, _Option{ - "Python Formatter", "format-python", newFileMatcher("*.py"), + "Python Formatter", "format-python", newFileMatcher(_pythonFile), newPatternMatcher("black "), newGenerator(_formatPythonYaml), "format-python.yaml", }, _Option{ - "Python Linter", "lint-python", newFileMatcher("*.py"), + "Python Linter", "lint-python", newFileMatcher(_pythonFile), newPatternMatcher("pylint ", "ruff "), newGenerator(_lintPythonYaml), "lint-python.yaml", }, _Option{ - "Shell Script Linter", "lint-shell-script", newFileMatcher("*.sh", "*.bash"), + "Shell Script Linter", "lint-shell-script", newFileMatcher("**/*.sh", "**/*.bash"), newPatternMatcher("shellcheck "), newGenerator(_lintShellScriptYaml), "lint-shell-script.yaml", }, _Option{ - "Solidity Linter", "lint-solidity", newFileMatcher("*.sol"), + "Solidity Linter", "lint-solidity", newFileMatcher("**/*.sol"), newPatternMatcher("solhint "), newGenerator(_lintSolidityYaml), "lint-solidity.yaml", }, _Option{ - "YAML Linter", "lint-yaml", newFileMatcher("*.yml", "*.yaml"), + "YAML Linter", "lint-yaml", newFileMatcher("**/*.yml", "**/*.yaml"), newPatternMatcher("ibiqlik/action-yamllint@"), newGenerator(_lintYamlYaml), "lint-yaml.yaml", }, + _Option{ + "GitHub Actions Linter", "lint-github-actions", + newFileMatcher(".github/workflows/*.yml", ".github/workflows/*.yaml"), + newPatternMatcher( /*"actionlint",*/ "zizmor"), + newGenerator(_lintYamlYaml), "lint-github-actions.yaml", + }, _Option{ "Render.com blueprint Validator", "validate-render-blueprint", newFileMatcher("render.yml", "render.yaml"), newPatternMatcher("GrantBirki/json-yaml-validate"), @@ -266,32 +282,20 @@ func getPath(rootDir string, fileName string) string { // Note: Go does not support "**" glob pattern func hasFile(rootDir string, globPattern string) bool { + log.Debug(). + Str("rootDir", rootDir). + Str("globPattern", globPattern). + Msg("Glob pattern") found := false - err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - // TODO(ashishb): In the long-term, add code to parse .gitignore - if info.Name() == ".git" || info.Name() == "node_modules" { - return filepath.SkipDir - } - return nil - } - matched, err := filepath.Match(globPattern, info.Name()) - if err != nil { - return err - } - if matched { - found = true - return filepath.SkipAll - } - return nil + err := doublestar.GlobWalk(os.DirFS(rootDir), globPattern, func(path string, d fs.DirEntry) error { + found = true + log.Trace().Msgf("hasFile(%s, %s) = %s", globPattern, rootDir, path) + return doublestar.SkipDir }) if err != nil { - log.Panic().Err(err).Msgf("glob failed: '%s'", globPattern) + log.Error(). + Err(err).Msgf("glob failed: '%s'", globPattern) } - log.Trace().Msgf("hasFile(%s, %s) = %v", globPattern, rootDir, found) return found } diff --git a/src/gabo/internal/generator/goreleaser_config_checker_generator.go b/src/gabo/internal/generator/goreleaser_config_checker_generator.go index ce9a30c..1870bbb 100644 --- a/src/gabo/internal/generator/goreleaser_config_checker_generator.go +++ b/src/gabo/internal/generator/goreleaser_config_checker_generator.go @@ -15,7 +15,7 @@ const _goReleaserCheckerTask = ` ` var _goReleaserConfigFiles = []string{ - "goreleaser.yaml", "goreleaser.yml", ".goreleaser.yaml", ".goreleaser.yml", + "**/goreleaser.yaml", "**/goreleaser.yml", "**/.goreleaser.yaml", "**/.goreleaser.yml", } func generateGoReleaserConfigCheckerYaml(repoDir string) (*string, error) { diff --git a/src/gabo/internal/generator/openapi_schema_validator_generator.go b/src/gabo/internal/generator/openapi_schema_validator_generator.go index e6984e2..8cd50fb 100644 --- a/src/gabo/internal/generator/openapi_schema_validator_generator.go +++ b/src/gabo/internal/generator/openapi_schema_validator_generator.go @@ -13,7 +13,7 @@ const _validateSchemaTask = ` command: 'validate %s/%s' ` -var _openAPIFileList = []string{"openapi.yaml", "openapi.yml", "openapi.json"} +var _openAPIFileList = []string{"**/openapi.yaml", "**/openapi.yml", "**/openapi.json"} func generateOpenAPISchemaValidator(repoDir string) (*string, error) { found := false