Skip to content

Commit

Permalink
feat: add recursive do option, basic implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mrexox committed Oct 31, 2024
1 parent 04a79f6 commit 3b478c7
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 11 deletions.
11 changes: 9 additions & 2 deletions internal/config/do.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import "errors"
var (
errAmbiguousDo = errors.New("Ambiguous command")
errEmptyDo = errors.New("Empty command")
errEmptyGroup = errors.New("Empty group")
)

type Do struct {
Name string `json:"name,omitempty" mapstructure:"name" toml:"name,omitempty" yaml:",omitempty"`
Run string `json:"run,omitempty" mapstructure:"run" toml:"run,omitempty" yaml:",omitempty"`
Script string `json:"script,omitempty" mapstructure:"script" toml:"script,omitempty" yaml:",omitempty"`
Runner string `json:"runner,omitempty" mapstructure:"runner" toml:"runner,omitempty" yaml:",runner"`
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"`
Expand Down Expand Up @@ -53,4 +54,10 @@ func (do *Do) Validate() error {
return nil
}

// TODO: properly merge `do` options by index/name
func (g *Group) Validate() error {
if len(g.Do) == 0 {
return errEmptyGroup
}

return nil
}
3 changes: 2 additions & 1 deletion internal/lefthook/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,12 @@ func (l *Lefthook) Run(hookName string, args RunArgs, gitArgs []string) error {
Files: args.Files,
Force: args.Force,
RunOnlyCommands: args.RunOnlyCommands,
SourceDirs: sourceDirs,
},
)

startTime := time.Now()
results, runErr := r.RunAll(ctx, sourceDirs)
results, runErr := r.RunAll(ctx)
if runErr != nil {
return fmt.Errorf("failed to run the hook: %w", runErr)
}
Expand Down
109 changes: 109 additions & 0 deletions internal/lefthook/runner/do.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package runner

import (
"context"
"fmt"
"path/filepath"
"strconv"
"sync"

"github.com/evilmartians/lefthook/internal/config"
"github.com/evilmartians/lefthook/internal/lefthook/runner/exec"
)

func (r *Runner) do(ctx context.Context) []Result {
var wg sync.WaitGroup

results := make([]Result, 0, len(r.Hook.Do))
resultsChan := make(chan Result, len(r.Hook.Do))
for i, do := range r.Hook.Do {
id := strconv.Itoa(i)
if r.Hook.Parallel {
wg.Add(1)
go func(id string, do *config.Do) {
defer wg.Done()
resultsChan <- r.runDo(ctx, id, do)
}(id, do)
} else {
results = append(results, r.runDo(ctx, id, do))
}
}

wg.Wait()
close(resultsChan)
for result := range resultsChan {
results = append(results, result)
}

return results
}

func (r *Runner) runDo(ctx context.Context, id string, do *config.Do) Result {
name := do.Name
if len(name) == 0 {
name = do.Run
}
if len(name) == 0 {
name = do.Script
}

err := do.Validate()
if err != nil {
return failed(name, "validation error")
}

if len(do.Run) != 0 {
ok := r.run(ctx, exec.Options{
Name: name,
Root: filepath.Join(r.Repo.RootPath, do.Root),
Commands: []string{do.Run},
Interactive: do.Interactive && !r.DisableTTY,
UseStdin: do.UseStdin,
Env: do.Env,
}, r.Hook.Follow)

if !ok {
r.failed.Store(true)
return failed(name, do.FailText)
}
}

// if len(do.Script) != 0 {
// // run a script
// }

if do.Group == nil {
return succeeded(name)
}

if len(name) == 0 {
name = do.Group.Name
}
if len(name) == 0 {
name = fmt.Sprintf("group #%s", id)
}

err = do.Group.Validate()
if err != nil {
return failed(name, "group validation error")
}

var wg sync.WaitGroup

for idx, subdo := range do.Group.Do {
subid := fmt.Sprintf("%s.%d", id, idx)
if do.Group.Parallel {
wg.Add(1)
go func(id string, do *config.Do) {
defer wg.Done()
r.runDo(ctx, id, do)
}(subid, subdo)
} else {
r.runDo(ctx, subid, subdo)
}
}

wg.Wait()

return succeeded(name)
}
9 changes: 6 additions & 3 deletions internal/lefthook/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type Options struct {
Force bool
Files []string
RunOnlyCommands []string
SourceDirs []string
}

// Runner responds for actual execution and handling the results.
Expand Down Expand Up @@ -87,7 +88,7 @@ type executable interface {

// RunAll runs scripts and commands.
// LFS hook is executed at first if needed.
func (r *Runner) RunAll(ctx context.Context, sourceDirs []string) ([]Result, error) {
func (r *Runner) RunAll(ctx context.Context) ([]Result, error) {
results := make([]Result, 0, len(r.Hook.Commands)+len(r.Hook.Scripts))

if r.Hook.DoSkip(r.Repo.State) {
Expand All @@ -104,8 +105,10 @@ func (r *Runner) RunAll(ctx context.Context, sourceDirs []string) ([]Result, err
defer log.StopSpinner()
}

scriptDirs := make([]string, 0, len(sourceDirs))
for _, sourceDir := range sourceDirs {
results = append(results, r.do(ctx)...)

scriptDirs := make([]string, 0, len(r.SourceDirs))
for _, sourceDir := range r.SourceDirs {
scriptDirs = append(scriptDirs, filepath.Join(
sourceDir, r.HookName,
))
Expand Down
3 changes: 2 additions & 1 deletion internal/lefthook/runner/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,7 @@ func TestRunAll(t *testing.T) {
LogSettings: log.NewSettings(),
GitArgs: tt.args,
Force: tt.force,
SourceDirs: tt.sourceDirs,
},
executor: executor{},
cmd: cmd{},
Expand All @@ -745,7 +746,7 @@ func TestRunAll(t *testing.T) {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
git.ResetState()
results, err := runner.RunAll(context.Background(), tt.sourceDirs)
results, err := runner.RunAll(context.Background())
assert.NoError(err)

var success, fail []Result
Expand Down
6 changes: 3 additions & 3 deletions testdata/dump.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ colors:
red: '#FF1493'
yellow: '#F0E68C'
pre-commit:
follow: true
commands:
lint:
run: yarn lint {staged_files}
Expand All @@ -54,7 +55,6 @@ pre-commit:
run: yarn test
skip: merge
glob: '*.js'
follow: true
-- lefthook-dumped.json --
{
"colors": {
Expand All @@ -65,6 +65,7 @@ pre-commit:
"yellow": "#F0E68C"
},
"pre-commit": {
"follow": true,
"commands": {
"lint": {
"run": "yarn lint {staged_files}",
Expand All @@ -82,8 +83,7 @@ pre-commit:
"skip": "merge",
"glob": "*.js"
}
},
"follow": true
}
}
}
-- lefthook-dumped.toml --
Expand Down
2 changes: 1 addition & 1 deletion testdata/remotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ remotes:
-- lefthook-dump.yml --
DEPRECATED: "remotes"."config" option is deprecated and will be omitted in the next major release, use "configs" option instead
pre-commit:
parallel: true
commands:
js-lint:
run: npx eslint --fix {staged_files} && git add {staged_files}
Expand All @@ -38,7 +39,6 @@ pre-commit:
scripts:
good_job.js:
runner: node
parallel: true
pre-push:
commands:
spelling:
Expand Down

0 comments on commit 3b478c7

Please sign in to comment.