Skip to content

Commit

Permalink
feat: allow providing a list of globs (#937)
Browse files Browse the repository at this point in the history
mrexox authored Jan 21, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 8cc927f commit f692bb5
Showing 14 changed files with 112 additions and 51 deletions.
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{}:
@@ -131,7 +131,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"
9 changes: 6 additions & 3 deletions testdata/remotes.txt
Original file line number Diff line number Diff line change
@@ -23,13 +23,15 @@ pre-commit:
commands:
js-lint:
run: npx eslint --fix {staged_files} && git add {staged_files}
glob: '*.{js,ts}'
glob:
- '*.{js,ts}'
ping:
run: echo pong
ruby-lint:
run: bundle exec rubocop --force-exclusion --parallel '{files}'
files: git diff-tree -r --name-only --diff-filter=CDMR HEAD origin/master
glob: '*.rb'
glob:
- '*.rb'
ruby-test:
run: bundle exec rspec
skip:
@@ -44,7 +46,8 @@ pre-push:
spelling:
run: npx yaspeller {files}
files: git diff --name-only HEAD @{push}
glob: '*.md'
glob:
- '*.md'
remotes:
- git_url: https://github.com/evilmartians/lefthook
ref: v1.4.0

0 comments on commit f692bb5

Please sign in to comment.