diff --git a/README.md b/README.md index 3cedd97..677ebbb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Linter for k6 extensions** -k6lint is a command line tool and a library for static analysis of the source of k6 extensions. The analysis is done without building a k6 executable with the extension. +k6lint is a command line tool and a library for static analysis of the source of k6 extensions. The contents of the source directory are used for analysis. If the directory is a git workdir, it also analyzes the git metadata. The analysis is completely local and does not use external APIs (e.g. repository manager API) or services. @@ -20,7 +20,8 @@ The detailed result of the checks are described in a [JSON schema](https://grafa - `git` - checks if the directory is git workdir - `versions` - checks for semantic versioning git tags - `build` - checks if k6 can be built with the extension - - `smoke` - checks if the smoke test script exists and runs successfully + - `smoke` - checks if the smoke test script exists and runs successfully (`smoke.js`, `smoke.ts`, `smoke.test.js` or `smoke.test.ts` in the `test`,`tests`, `examples` or the base directory) + - `codeowners` - checks if there is a CODEOWNERS file (for official extensions) ## Install diff --git a/checker_codeowners.go b/checker_codeowners.go new file mode 100644 index 0000000..968223b --- /dev/null +++ b/checker_codeowners.go @@ -0,0 +1,26 @@ +package k6lint + +import ( + "context" + "path/filepath" + "regexp" +) + +var reCODEOWNERS = regexp.MustCompile("^CODEOWNERS$") + +func checkerCodeowners(_ context.Context, dir string) *checkResult { + _, shortname, err := findFile(reCODEOWNERS, + dir, + filepath.Join(dir, ".github"), + filepath.Join(dir, "docs"), + ) + if err != nil { + return checkError(err) + } + + if len(shortname) > 0 { + return checkPassed("found `CODEOWNERS` file") + } + + return checkFailed("no CODEOWNERS file found") +} diff --git a/checks.go b/checks.go index ce30e82..970d207 100644 --- a/checks.go +++ b/checks.go @@ -31,7 +31,7 @@ type checkDefinition struct { score int } -func checkDefinitions() []checkDefinition { +func checkDefinitions(official bool) []checkDefinition { modCheck := newModuleChecker() gitCheck := newGitChecker() @@ -47,11 +47,21 @@ func checkDefinitions() []checkDefinition { {id: CheckerSmoke, score: 2, fn: modCheck.smoke}, } + if !official { + return defs + } + + extra := []checkDefinition{ + {id: CheckerCodeowners, score: 2, fn: checkerCodeowners}, + } + + defs = append(defs, extra...) + return defs } func runChecks(ctx context.Context, dir string, opts *Options) ([]Check, int) { - checkDefs := checkDefinitions() + checkDefs := checkDefinitions(opts.Official) results := make([]Check, 0, len(checkDefs)) passed := passedChecks(opts.Passed) @@ -94,7 +104,10 @@ func ParseChecker(val string) (Checker, error) { CheckerExamples, CheckerLicense, CheckerGit, - CheckerVersions: + CheckerVersions, + CheckerBuild, + CheckerSmoke, + CheckerCodeowners: return v, nil default: diff --git a/cmd/cmd.go b/cmd/cmd.go index 06b5785..b6ec40e 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -27,6 +27,7 @@ type options struct { passing k6lint.Grade passedStr []string passed []k6lint.Checker + official bool } // New creates new cobra command for exec command. @@ -69,6 +70,7 @@ func New() (*cobra.Command, error) { flags.SortFlags = false flags.Var(&opts.passing, "passing", "set lowest passing grade") + flags.BoolVar(&opts.official, "official", false, "enable extra checks for official extensions") flags.BoolVarP(&opts.quiet, "quiet", "q", false, "no output, only validation") flags.StringVarP(&opts.out, "out", "o", "", "write output to file instead of stdout") flags.BoolVar(&opts.json, "json", false, "generate JSON output") @@ -125,7 +127,7 @@ func run(ctx context.Context, args []string, opts *options) (result error) { output = file } - compliance, err := k6lint.Lint(ctx, dir, &k6lint.Options{Passed: opts.passed}) + compliance, err := k6lint.Lint(ctx, dir, &k6lint.Options{Passed: opts.passed, Official: opts.official}) if err != nil { return err } diff --git a/compliance_gen.go b/compliance_gen.go index 59376eb..0ffcdab 100644 --- a/compliance_gen.go +++ b/compliance_gen.go @@ -25,6 +25,7 @@ type Check struct { type Checker string const CheckerBuild Checker = "build" +const CheckerCodeowners Checker = "codeowners" const CheckerExamples Checker = "examples" const CheckerGit Checker = "git" const CheckerLicense Checker = "license" diff --git a/docs/compliance.schema.json b/docs/compliance.schema.json index 5b58029..6d03e65 100644 --- a/docs/compliance.schema.json +++ b/docs/compliance.schema.json @@ -83,7 +83,8 @@ "git", "versions", "build", - "smoke" + "smoke", + "codeowners" ] } } diff --git a/docs/compliance.schema.yaml b/docs/compliance.schema.yaml index 1c63adc..5e98be3 100644 --- a/docs/compliance.schema.yaml +++ b/docs/compliance.schema.yaml @@ -79,3 +79,4 @@ $defs: - versions - build - smoke + - codeowners diff --git a/options.go b/options.go index f019f03..f087387 100644 --- a/options.go +++ b/options.go @@ -4,6 +4,9 @@ package k6lint type Options struct { // Passed contains a list of checkers that have already been marked as successful. Passed []Checker + + // Official can be set true to enable extra checkers (like codeowners) for official extensions. + Official bool } func passedChecks(checkers []Checker) map[Checker]Check {