Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,27 @@ commitlint-scope init
### Overview

```yaml
#$schema: https://github.com/thumbrise/commitlint-scope/blob/main/docs/schema/config.json
#$schema: https://github.com/thumbrise/commitlint-scope/blob/main/docs/schema/config.v3.json

# Scope parsing customization. Not required, if you follow common conventional header. In example: 'type!(scope): subject'
#scopeRegex: ^[a-z]+(?:\((?P<scope>[^)]+)\))?!?:\s

# Patterns map: each key is a scope name, value is a list of glob patterns that match files belonging to that scope.
# Patterns list: each item specifies a list of scopes and the corresponding file glob patterns.
patterns:
"auth": [ "services/auth/**" ]
"migrations": [ "database/migrations/*.sql" ]
"frontend": [ "**/assets/**", "**/frontend/**" ]
"docs": [ "**/*.md" ]
- scopes: ["auth"]
files: ["services/auth/**"]

- scopes: ["migrations", "sql"]
files: ["database/migrations/*.sql"]

- scopes: ["frontend", "assets"]
files: ["**/assets/**", "**/frontend/**"]

- scopes: ["docs", "md"]
files: ["**/*.md"]

- scopes: ["some.dot.scope", "any-anotherscope"]
files: ["**/rail.v1.json"]
```

## Zero Configuration
Expand Down Expand Up @@ -191,7 +201,7 @@ pipelines:

## JSON schema

https://github.com/thumbrise/commitlint-scope/blob/main/docs/schema/config.json
https://github.com/thumbrise/commitlint-scope/blob/main/docs/schema/config.v3.json

## License

Expand Down
24 changes: 17 additions & 7 deletions cmd/commands/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"fmt"
"os"

"github.com/thumbrise/commitlint-scope/v2/pkg/validator"
"github.com/thumbrise/commitlint-scope/v3/pkg/validator"
"github.com/urfave/cli/v3"
)

Expand All @@ -16,17 +16,27 @@ var (
ErrWrite = errors.New("cannot write content")
)

const InitConfigData = `#$schema: https://github.com/thumbrise/commitlint-scope/blob/main/docs/schema/config.json
const InitConfigData = `#$schema: https://github.com/thumbrise/commitlint-scope/blob/main/docs/schema/config.v3.json

# Scope parsing customization. Not required, if you follow common conventional header. In example: 'type!(scope): subject'
#scopeRegex: ^[a-z]+(?:\((?P<scope>[^)]+)\))?!?:\s

# Patterns map: each key is a scope name, value is a list of glob patterns that match files belonging to that scope.
# Patterns list: each item specifies a list of scopes and the corresponding file glob patterns.
patterns:
"auth": [ "services/auth/**" ]
"migrations": [ "database/migrations/*.sql" ]
"frontend": [ "**/assets/**", "**/frontend/**" ]
"docs": [ "**/*.md" ]
- scopes: ["auth"]
files: ["services/auth/**"]

- scopes: ["migrations", "sql"]
files: ["database/migrations/*.sql"]

- scopes: ["frontend", "assets"]
files: ["**/assets/**", "**/frontend/**"]

- scopes: ["docs", "md"]
files: ["**/*.md"]

- scopes: ["some.dot.scope", "any-anotherscope"]
files: ["**/rail.v1.json"]
`

const (
Expand Down
4 changes: 2 additions & 2 deletions cmd/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"os"

"github.com/fatih/color"
"github.com/thumbrise/commitlint-scope/v2/cmd/errs"
"github.com/thumbrise/commitlint-scope/v2/pkg/validator"
"github.com/thumbrise/commitlint-scope/v3/cmd/errs"
"github.com/thumbrise/commitlint-scope/v3/pkg/validator"
"github.com/urfave/cli/v3"
)

Expand Down
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"os"

"github.com/fatih/color"
"github.com/thumbrise/commitlint-scope/v2/cmd/commands"
"github.com/thumbrise/commitlint-scope/v3/cmd/commands"
"github.com/urfave/cli/v3"
)

Expand Down
44 changes: 44 additions & 0 deletions docs/schema/config.v3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "commitlint-scope configuration",
"description": "Configuration for commitlint-scope - a linter that checks if declared commit scopes match the changed files.",
"type": "object",
"properties": {
"scopeRegex": {
"description": "Regular expression used to extract the scope from a conventional commit header. It must contain a named group 'scope'. If omitted, a sensible default is used. https://github.com/google/re2/wiki/Syntax",
"type": "string",
"format": "regex",
"pattern": "\\(\\?P<scope>"
},
"patterns": {
"description": "List of pattern rules. Each rule maps a list of scope names to a list of glob patterns.",
"type": "array",
"items": {
"type": "object",
"properties": {
"scopes": {
"description": "List of scope names that share these glob patterns.",
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"files": {
"description": "List of glob patterns that match files belonging to the listed scopes. Patterns support globstars (**) and standard wildcards.",
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
"required": ["scopes", "files"],
"additionalProperties": false
}
}
},
"additionalProperties": false
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/thumbrise/commitlint-scope/v2
module github.com/thumbrise/commitlint-scope/v3

go 1.26.1

Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"fmt"
"os"

"github.com/thumbrise/commitlint-scope/v2/cmd"
"github.com/thumbrise/commitlint-scope/v3/cmd"
)

var (
Expand Down
9 changes: 7 additions & 2 deletions pkg/validator/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ import (

const ConfigName = ".commitlint-scope"

type PatternItem struct {
Scopes []string `mapstructure:"scopes"`
Files []string `mapstructure:"files"`
}

type Config struct {
ScopeRegex *regexp.Regexp `mapstructure:"scopeRegex"`
Patterns map[string][]string `mapstructure:"patterns"`
ScopeRegex *regexp.Regexp `mapstructure:"scopeRegex"`
Patterns []PatternItem `mapstructure:"patterns"`
}

var ErrConfigRead = errors.New("error reading config")
Expand Down
37 changes: 24 additions & 13 deletions pkg/validator/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thumbrise/commitlint-scope/v2/pkg/validator"
"github.com/thumbrise/commitlint-scope/v3/pkg/validator"
)

func TestLoadConfig(t *testing.T) {
Expand All @@ -18,7 +18,7 @@ func TestLoadConfig(t *testing.T) {
yaml string
wantRegexNil bool
wantRegex string
wantPatterns map[string][]string
wantPatterns []validator.PatternItem
wantErr error
}{
{
Expand All @@ -28,15 +28,15 @@ func TestLoadConfig(t *testing.T) {
{
name: "patterns with default regex",
yaml: `patterns:
api:
- api/*
core:
- core/**
- scopes: ["api"]
files: ["api/*"]
- scopes: ["core"]
files: ["core/**"]
`,
wantRegex: defaultRegexStr,
wantPatterns: map[string][]string{
"api": {"api/*"},
"core": {"core/**"},
wantPatterns: []validator.PatternItem{
{Scopes: []string{"api"}, Files: []string{"api/*"}},
{Scopes: []string{"core"}, Files: []string{"core/**"}},
},
},
{
Expand All @@ -49,12 +49,23 @@ func TestLoadConfig(t *testing.T) {
name: "both patterns and custom scopeRegex",
yaml: `scopeRegex: '^(feat|fix):'
patterns:
api:
- api/*
- scopes: ["api"]
files: ["api/*"]
`,
wantRegex: `^(feat|fix):`,
wantPatterns: map[string][]string{
"api": {"api/*"},
wantPatterns: []validator.PatternItem{
{Scopes: []string{"api"}, Files: []string{"api/*"}},
},
},
{
name: "patterns with dots inside scopes",
yaml: `patterns:
- scopes: ["rail.v1.json"]
files: ["**/rail.v1.json"]
`,
wantRegex: defaultRegexStr,
wantPatterns: []validator.PatternItem{
{Scopes: []string{"rail.v1.json"}, Files: []string{"**/rail.v1.json"}},
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"strings"
"testing"

"github.com/thumbrise/commitlint-scope/v2/pkg/validator"
"github.com/thumbrise/commitlint-scope/v3/pkg/validator"
)

func gitCall(t *testing.T, dir string, args ...string) string {
Expand Down
29 changes: 20 additions & 9 deletions pkg/validator/outsider_finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,21 @@ type DefaultOutsiderFinder struct {
scopesToPatternsGlob map[string][]glob.Glob
}

// OutsiderFinderPattern matches the new configuration structure.
type OutsiderFinderPattern struct {
Scopes []string
Files []string
}

// NewDefaultOutsiderFinder creates a new DefaultOutsiderFinder.
// scopesToPatterns is a map from scope name to a list of glob pattern strings.
func NewDefaultOutsiderFinder(scopesToPatterns map[string][]string) (*DefaultOutsiderFinder, error) {
scopesToPatternsGlob := make(map[string][]glob.Glob, len(scopesToPatterns))
for scope, patterns := range scopesToPatterns {
globs := make([]glob.Glob, 0, len(patterns))
for _, pattern := range patterns {
// It accepts a slice of OutsiderFinderPattern and flattens it into efficient lookup maps.
func NewDefaultOutsiderFinder(patterns []OutsiderFinderPattern) (*DefaultOutsiderFinder, error) {
scopesToPatternsHuman := make(map[string][]string)
scopesToPatternsGlob := make(map[string][]glob.Glob)

for _, item := range patterns {
globs := make([]glob.Glob, 0, len(item.Files))
for _, pattern := range item.Files {
g, err := glob.Compile(pattern, '/')
if err != nil {
return nil, fmt.Errorf("%w: %q: %w", ErrInvalidGlobPattern, pattern, err)
Expand All @@ -30,11 +38,14 @@ func NewDefaultOutsiderFinder(scopesToPatterns map[string][]string) (*DefaultOut
globs = append(globs, g)
}

scopesToPatternsGlob[scope] = globs
for _, scope := range item.Scopes {
scopesToPatternsHuman[scope] = append(scopesToPatternsHuman[scope], item.Files...)
scopesToPatternsGlob[scope] = append(scopesToPatternsGlob[scope], globs...)
}
}

return &DefaultOutsiderFinder{
scopesToPatternsHuman: scopesToPatterns,
scopesToPatternsHuman: scopesToPatternsHuman,
scopesToPatternsGlob: scopesToPatternsGlob,
}, nil
}
Expand All @@ -47,7 +58,7 @@ func (f *DefaultOutsiderFinder) Find(scope string, files []string) []Outsider {

// zero config
if len(globFilePatterns) == 0 {
defaultPattern := scope + "/**"
defaultPattern := glob.QuoteMeta(scope) + "/**"

g, err := glob.Compile(defaultPattern, '/')
if err != nil {
Expand Down
Loading
Loading