Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow providing a list of globs #937

Merged
Merged
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
25 changes: 19 additions & 6 deletions docs/mdbook/configuration/glob.md
Original file line number Diff line number Diff line change
@@ -8,12 +8,25 @@ You can set a glob to filter files for your command. This is only used if you us
# lefthook.yml

pre-commit:
commands:
lint:
glob: "*.{js,ts,jsx,tsx}"
jobs:
- name: lint
run: yarn eslint {staged_files}
glob: "*.{js,ts,jsx,tsx}"
```

> **Note:** from lefthook version `1.10.10` you can also provide a list of globs:
>
> ```yml
> # lefthook.yml
>
> pre-commit:
> jobs:
> - run: yarn lint {staged_files}
> glob:
> - "*.ts"
> - "*.js"
> ```

**Notes**

For patterns that you can use see [this](https://tldp.org/LDP/GNU-Linux-Tools-Summary/html/x11655.htm) reference. We use [glob](https://github.com/gobwas/glob) library.
@@ -24,8 +37,8 @@ If you've specified `glob` but don't have a files template in [`run`](./run.md)
# lefthook.yml

pre-commit:
commands:
lint:
glob: "*.js"
jobs:
- name: lint
run: npm run lint # skipped if no .js files staged
glob: "*.js"
```
2 changes: 1 addition & 1 deletion internal/config/command.go
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ type Command struct {

FileTypes []string `json:"file_types,omitempty" koanf:"file_types" mapstructure:"file_types" toml:"file_types,omitempty" yaml:"file_types,omitempty"`

Glob string `json:"glob,omitempty" mapstructure:"glob" toml:"glob,omitempty" yaml:",omitempty"`
Glob []string `json:"glob,omitempty" jsonschema:"oneof_type=string;array" mapstructure:"glob" toml:"glob,omitempty" yaml:",omitempty"`
Root string `json:"root,omitempty" mapstructure:"root" toml:"root,omitempty" yaml:",omitempty"`
Exclude interface{} `json:"exclude,omitempty" jsonschema:"oneof_type=string;array" mapstructure:"exclude" toml:"exclude,omitempty" yaml:",omitempty"`

8 changes: 4 additions & 4 deletions internal/config/job.go
Original file line number Diff line number Diff line change
@@ -6,10 +6,10 @@ type Job struct {
Script string `json:"script,omitempty" jsonschema:"oneof_required=Run a script" mapstructure:"script" toml:"script,omitempty" yaml:",omitempty"`
Runner string `json:"runner,omitempty" mapstructure:"runner" toml:"runner,omitempty" yaml:",omitempty"`

Glob string `json:"glob,omitempty" mapstructure:"glob" toml:"glob,omitempty" yaml:",omitempty"`
Root string `json:"root,omitempty" mapstructure:"root" toml:"root,omitempty" yaml:",omitempty"`
Files string `json:"files,omitempty" mapstructure:"files" toml:"files,omitempty" yaml:",omitempty"`
FailText string `json:"fail_text,omitempty" koanf:"fail_text" mapstructure:"fail_text" toml:"fail_text,omitempty" yaml:"fail_text,omitempty"`
Glob []string `json:"glob,omitempty" jsonschema:"oneof_type=string;array" mapstructure:"glob" toml:"glob,omitempty" yaml:",omitempty"`
Root string `json:"root,omitempty" mapstructure:"root" toml:"root,omitempty" yaml:",omitempty"`
Files string `json:"files,omitempty" mapstructure:"files" toml:"files,omitempty" yaml:",omitempty"`
FailText string `json:"fail_text,omitempty" koanf:"fail_text" mapstructure:"fail_text" toml:"fail_text,omitempty" yaml:"fail_text,omitempty"`

Tags []string `json:"tags,omitempty" mapstructure:"tags" toml:"tags,omitempty" yaml:",omitempty"`
FileTypes []string `json:"file_types,omitempty" koanf:"file_types" mapstructure:"file_types" toml:"file_types,omitempty" yaml:"file_types,omitempty"`
6 changes: 3 additions & 3 deletions internal/config/load_test.go
Original file line number Diff line number Diff line change
@@ -201,7 +201,7 @@ pre-push:
Tags: []string{"backend", "test"},
},
"lint": {
Glob: "*.rb",
Glob: []string{"*.rb"},
Run: "docker exec -it ruby:2.7 bundle exec rubocop",
Tags: []string{"backend", "linter"},
},
@@ -649,7 +649,7 @@ pre-commit:
"global-lint": {
Run: "bundle exec rubocop",
Tags: []string{"backend", "linter"},
Glob: "*.rb",
Glob: []string{"*.rb"},
},
"global-other": {
Run: "bundle exec rubocop",
@@ -783,7 +783,7 @@ pre-commit:
Jobs: []*Job{
{
Name: "group 1",
Glob: "*.rb",
Glob: []string{"*.rb"},
Group: &Group{
Parallel: true,
Jobs: []*Job{
30 changes: 22 additions & 8 deletions internal/lefthook/runner/filters/filters.go
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ const (
)

type Params struct {
Glob string
Glob []string
Root string
FileTypes []string
Exclude interface{}
@@ -52,19 +52,33 @@ func Apply(fs afero.Fs, files []string, params Params) []string {
return files
}

func byGlob(vs []string, matcher string) []string {
if matcher == "" {
func byGlob(vs []string, matchers []string) []string {
if len(matchers) == 0 {
return vs
}

g := glob.MustCompile(strings.ToLower(matcher))

var hasNonEmpty bool
vsf := make([]string, 0)
for _, v := range vs {
if res := g.Match(strings.ToLower(v)); res {
vsf = append(vsf, v)
for _, matcher := range matchers {
if len(matcher) == 0 {
continue
}

hasNonEmpty = true

g := glob.MustCompile(strings.ToLower(matcher))

for _, v := range vs {
if res := g.Match(strings.ToLower(v)); res {
vsf = append(vsf, v)
}
}
}

if !hasNonEmpty {
return vs
}

return vsf
}

19 changes: 12 additions & 7 deletions internal/lefthook/runner/filters/filters_test.go
Original file line number Diff line number Diff line change
@@ -28,31 +28,31 @@ func slicesEqual(a, b []string) bool {
func TestByGlob(t *testing.T) {
for i, tt := range [...]struct {
source, result []string
glob string
glob []string
}{
{
source: []string{"folder/subfolder/0.rb", "1.txt", "2.RB", "3.rbs"},
glob: "",
glob: []string{},
result: []string{"folder/subfolder/0.rb", "1.txt", "2.RB", "3.rbs"},
},
{
source: []string{"folder/subfolder/0.rb", "1.txt", "2.RB", "3.rbs"},
glob: "*.rb",
glob: []string{"*.rb"},
result: []string{"folder/subfolder/0.rb", "2.RB"},
},
{
source: []string{"folder/subfolder/0.rb", "1.rbs"},
glob: "**/*.rb",
glob: []string{"**/*.rb"},
result: []string{"folder/subfolder/0.rb"},
},
{
source: []string{"folder/0.rb", "1.rBs", "2.rbv"},
glob: "*.rb?",
glob: []string{"*.rb?"},
result: []string{"1.rBs", "2.rbv"},
},
{
source: []string{"f.a", "f.b", "f.c", "f.cn"},
glob: "*.{a,b,cn}",
glob: []string{"*.{a,b,cn}"},
result: []string{"f.a", "f.b", "f.cn"},
},
} {
@@ -68,7 +68,7 @@ func TestByGlob(t *testing.T) {
func TestByExclude(t *testing.T) {
for i, tt := range [...]struct {
source, result []string
exclude string
exclude interface{}
}{
{
source: []string{"folder/subfolder/0.rb", "1.txt", "2.RB", "3.rb"},
@@ -95,6 +95,11 @@ func TestByExclude(t *testing.T) {
exclude: ".*\\.(a|b|cn)$",
result: []string{"f.c"},
},
{
source: []string{"f.a", "f.b", "f.c", "f.cn"},
exclude: []interface{}{"*.a", "*.b", "*.cn"},
result: []string{"f.c"},
},
} {
t.Run(fmt.Sprintf("%d:", i), func(t *testing.T) {
res := byExclude(tt.source, tt.exclude)
2 changes: 1 addition & 1 deletion internal/lefthook/runner/jobs/jobs.go
Original file line number Diff line number Diff line change
@@ -19,10 +19,10 @@ type Params struct {
Root string
Runner string
Script string
Glob string
Files string
FileTypes []string
Tags []string
Glob []string
Templates map[string]string
Exclude interface{}
Only interface{}
6 changes: 3 additions & 3 deletions internal/lefthook/runner/run_jobs.go
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ var (
type domain struct {
failed *atomic.Bool

glob string
glob []string
root string
exclude interface{}
onlyJobs []string
@@ -95,7 +95,7 @@ func (r *Runner) runJob(ctx context.Context, domain *domain, id string, job *con

if job.Group != nil {
inheritedDomain := *domain
inheritedDomain.glob = first(job.Glob, domain.glob)
inheritedDomain.glob = slices.Concat(inheritedDomain.glob, job.Glob)
inheritedDomain.root = first(job.Root, domain.root)
switch list := job.Exclude.(type) {
case []interface{}:
@@ -126,7 +126,7 @@ func (r *Runner) runSingleJob(ctx context.Context, domain *domain, id string, jo
name := job.PrintableName(id)

root := first(job.Root, domain.root)
glob := first(job.Glob, domain.glob)
glob := slices.Concat(domain.glob, job.Glob)
exclude := join(job.Exclude, domain.exclude)
executionJob, err := jobs.New(name, &jobs.Params{
Repo: r.Repo,
12 changes: 6 additions & 6 deletions internal/lefthook/runner/runner_test.go
Original file line number Diff line number Diff line change
@@ -618,12 +618,12 @@ func TestRunAll(t *testing.T) {
"ok": {
Run: "success",
StageFixed: true,
Glob: "*.md",
Glob: []string{"*.md"},
},
"fail": {
Run: "fail",
StageFixed: true,
Glob: "*.txt",
Glob: []string{"*.txt"},
},
},
},
@@ -648,12 +648,12 @@ func TestRunAll(t *testing.T) {
"ok": {
Run: "success",
StageFixed: true,
Glob: "*.md",
Glob: []string{"*.md"},
},
"fail": {
Run: "fail",
StageFixed: true,
Glob: "*.sh",
Glob: []string{"*.sh"},
},
},
},
@@ -703,12 +703,12 @@ func TestRunAll(t *testing.T) {
"ok": {
Run: "success",
StageFixed: true,
Glob: "*.md",
Glob: []string{"*.md"},
},
"fail": {
Run: "fail",
StageFixed: true,
Glob: "*.sh",
Glob: []string{"*.sh"},
},
},
},
26 changes: 23 additions & 3 deletions schema.json
Original file line number Diff line number Diff line change
@@ -56,7 +56,17 @@
"type": "array"
},
"glob": {
"type": "string"
"oneOf": [
{
"type": "string"
},
{
"type": "array"
}
],
"items": {
"type": "string"
}
},
"root": {
"type": "string"
@@ -214,7 +224,17 @@
"type": "string"
},
"glob": {
"type": "string"
"oneOf": [
{
"type": "string"
},
{
"type": "array"
}
],
"items": {
"type": "string"
}
},
"root": {
"type": "string"
@@ -392,7 +412,7 @@
"type": "object"
}
},
"$comment": "Last updated on 2025.01.16.",
"$comment": "Last updated on 2025.01.21.",
"properties": {
"min_version": {
"type": "string",
9 changes: 6 additions & 3 deletions testdata/dump.txt
Original file line number Diff line number Diff line change
@@ -61,7 +61,8 @@ pre-commit:
test:
run: yarn test
skip: merge
glob: '*.js'
glob:
- '*.js'
scripts:
my-script.sh:
runner: bash
@@ -95,7 +96,9 @@ pre-commit:
"test": {
"run": "yarn test",
"skip": "merge",
"glob": "*.js"
"glob": [
"*.js"
]
}
},
"scripts": {
@@ -130,7 +133,7 @@ interactive = true
[pre-commit.commands.test]
run = 'yarn test'
skip = 'merge'
glob = '*.js'
glob = ['*.js']

[pre-commit.scripts]
[pre-commit.scripts.'my-script.sh']
6 changes: 4 additions & 2 deletions testdata/job_merging.txt
Original file line number Diff line number Diff line change
@@ -103,7 +103,8 @@ extends:
pre-commit:
jobs:
- name: group
glob: '*.rb'
glob:
- '*.rb'
group:
jobs:
- name: child
@@ -115,7 +116,8 @@ pre-commit:
- run: 3 no-name
- name: echo
run: echo 2
glob: "3"
glob:
- "3"
tags:
- backend
skip: true
3 changes: 2 additions & 1 deletion testdata/many_extends_levels.txt
Original file line number Diff line number Diff line change
@@ -77,4 +77,5 @@ pre-commit:
skip: true
tags:
- backend
glob: "3"
glob:
- "3"
Loading