diff --git a/README.md b/README.md index d9fce72..6d5f28f 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,7 @@ Use the following environment variables to configure the application: | OWNER_CHECKER_OWNERS_MUST_BE_TEAMS | `false` | Specifies whether only teams are allowed as owners of files. | | NOT_OWNED_CHECKER_SKIP_PATTERNS | | The comma-separated list of patterns that should be ignored by `not-owned-checker`. For example, you can specify `*` and as a result, the `*` pattern from the **CODEOWNERS** file will be ignored and files owned by this pattern will be reported as unowned unless a later specific pattern will match that path. It's useful because often we have default owners entry at the begging of the CODOEWNERS file, e.g. `* @global-owner1 @global-owner2` | | NOT_OWNED_CHECKER_SKIP_PATH_PATTERNS | | The comma-separated list of path patterns that should be ignored by not-owned-checker. For example `lib/tasks,db/migrations` | +| NOT_OWNED_CHECKER_ONLY_PATH_PATTERNS | | The comma-separated list of path patterns that should be checked by not-owned-checker. For example `app` | | NOT_OWNED_CHECKER_GIT_DIFF_ARGUMENTS | | The comma-separated list of git diff options that should be used by `not-owned-checker`. | | NOT_OWNED_CHECKER_SUBDIRECTORIES | | The comma-separated list of subdirectories to check in `not-owned-checker`. When specified, only files in the listed subdirectories will be checked if they do not have specified owners in CODEOWNERS. | | NOT_OWNED_CHECKER_TRUST_WORKSPACE | `false` | Specifies whether the repository path should be marked as safe. See: https://github.com/actions/checkout/issues/766. | diff --git a/action.yml b/action.yml index 4d589c0..76ff039 100644 --- a/action.yml +++ b/action.yml @@ -54,6 +54,10 @@ inputs: description: "The comma-separated list of path patterns that should be ignored by not-owned-checker. For example `lib/tasks,db/migrations`" required: false + not_owned_checker_only_path_patterns: + description: "The comma-separated list of path patterns that should be checked by not-owned-checker. For example `app`" + required: false + owner_checker_repository: description: "The owner and repository name. For example, gh-codeowners/codeowners-samples. Used to check if GitHub team is in the given organization and has permission to the given repository." required: false @@ -88,7 +92,7 @@ inputs: runs: using: 'docker' - image: 'docker://ghcr.io/uchiru/codeowners-validator:v0.8.8' + image: 'docker://ghcr.io/uchiru/codeowners-validator:v0.8.9' env: ENVS_PREFIX: "INPUT" diff --git a/internal/check/not_owned_file.go b/internal/check/not_owned_file.go index 8ac1d47..a700263 100644 --- a/internal/check/not_owned_file.go +++ b/internal/check/not_owned_file.go @@ -22,6 +22,7 @@ type NotOwnedFileConfig struct { TrustWorkspace bool `envconfig:"default=false"` SkipPatterns []string `envconfig:"optional"` SkipPathPatterns []string `envconfig:"optional"` + OnlyPathPatterns []string `envconfig:"optional"` Subdirectories []string `envconfig:"optional"` GitDiffArguments []string `envconfig:"optional"` } @@ -29,6 +30,7 @@ type NotOwnedFileConfig struct { type NotOwnedFile struct { skipPatterns map[string]struct{} skipPathPatterns []string + onlyPathPatterns []string subDirectories []string gitDiffArguments []string trustWorkspace bool @@ -43,6 +45,7 @@ func NewNotOwnedFile(cfg *NotOwnedFileConfig) *NotOwnedFile { return &NotOwnedFile{ skipPatterns: skip, skipPathPatterns: cfg.SkipPathPatterns, + onlyPathPatterns: cfg.OnlyPathPatterns, subDirectories: cfg.Subdirectories, trustWorkspace: cfg.TrustWorkspace, gitDiffArguments: cfg.GitDiffArguments, @@ -109,9 +112,10 @@ func (c *NotOwnedFile) Check(ctx context.Context, in Input) (output Output, err if lsOut != "" { lines := strings.Split(lsOut, "\n") filteredOwnerLines := c.filterByOwners(patterns, lines) - filteredLines := c.filterByPaths(filteredOwnerLines) + filteredPathLines := c.skipByPaths(filteredOwnerLines) + filteredLines := c.selectByPaths(filteredPathLines) if len(filteredLines) > 0 { - msg := fmt.Sprintf("Found %d not owned files (skipped patterns: %q, skipped paths: %q):\n%s", len(filteredLines), c.skipPatternsList(), c.skipPathPatterns, c.ListFormatFunc(filteredLines)) + msg := fmt.Sprintf("Found %d not owned files (skipped patterns: %q, skipped paths: %q, only paths: %q):\n%s", len(filteredLines), c.skipPatternsList(), c.skipPathPatterns, c.onlyPathPatterns, c.ListFormatFunc(filteredLines)) bldr.ReportIssue(msg) } } @@ -273,7 +277,7 @@ func (c *NotOwnedFile) filterByOwners(patterns, files []string) []string { return result } -func (c *NotOwnedFile) filterByPaths(files []string) []string { +func (c *NotOwnedFile) skipByPaths(files []string) []string { f := func(search string, patterns []string) bool { for _, pattern := range patterns { if pathFound := strings.HasPrefix(search, pattern); pathFound { @@ -294,6 +298,31 @@ func (c *NotOwnedFile) filterByPaths(files []string) []string { return result } +func (c *NotOwnedFile) selectByPaths(files []string) []string { + if len(c.onlyPathPatterns) == 0 { + return files + } + + f := func(search string, patterns []string) bool { + for _, pattern := range patterns { + if pathFound := strings.HasPrefix(search, pattern); pathFound { + return false + } + } + return true + } + + var result []string + for _, file := range files { + if filePathfound := f(file, c.onlyPathPatterns); filePathfound { + result = append(result, file) + } + continue + } + + return result +} + // ListFormatFunc is a basic formatter that outputs // a bullet point list of the pattern. func (c *NotOwnedFile) ListFormatFunc(es []string) string {