Skip to content

Commit

Permalink
feat: add recursive 'actions' option
Browse files Browse the repository at this point in the history
  • Loading branch information
mrexox committed Dec 4, 2024
1 parent df484d9 commit 51f32aa
Show file tree
Hide file tree
Showing 25 changed files with 766 additions and 375 deletions.
7 changes: 7 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ linters-settings:
rules:
- name: unused-parameter
disabled: true
unused:
field-writes-are-uses: false
post-statements-are-reads: true
exported-fields-are-used: false
parameters-are-used: true
local-variables-are-used: false
generated-is-used: false

issues:
exclude:
Expand Down
59 changes: 59 additions & 0 deletions internal/config/actions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package config

type Action 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:",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" 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" mapstructure:"file_types" toml:"file_types,omitempty" yaml:"file_types,omitempty"`

Env map[string]string `json:"env,omitempty" mapstructure:"env" toml:"env,omitempty" yaml:",omitempty"`

Interactive bool `json:"interactive,omitempty" mapstructure:"interactive" toml:"interactive,omitempty" yaml:",omitempty"`
UseStdin bool `json:"use_stdin,omitempty" mapstructure:"use_stdin" toml:"use_stdin,omitempty" yaml:",omitempty"`
StageFixed bool `json:"stage_fixed,omitempty" mapstructure:"stage_fixed" toml:"stage_fixed,omitempty" yaml:"stage_fixed,omitempty"`

Exclude interface{} `json:"exclude,omitempty" mapstructure:"exclude" toml:"exclude,omitempty" yaml:",omitempty"`
Skip interface{} `json:"skip,omitempty" mapstructure:"skip" toml:"skip,omitempty,inline" yaml:",omitempty"`
Only interface{} `json:"only,omitempty" mapstructure:"only" toml:"only,omitempty,inline" yaml:",omitempty"`

Group *Group `json:"group,omitempty" mapstructure:"group" toml:"group,omitempty" yaml:",omitempty"`
}

type Group struct {
Name string `json:"name,omitempty" mapstructure:"name" toml:"name,omitempty" yaml:",omitempty"`
Root string `json:"root,omitempty" mapstructure:"root" toml:"root,omitempty" yaml:",omitempty"`
Parallel bool `json:"parallel,omitempty" mapstructure:"parallel" toml:"parallel,omitempty" yaml:",omitempty"`
Piped bool `json:"piped,omitempty" mapstructure:"piped" toml:"piped,omitempty" yaml:",omitempty"`
Glob string `json:"glob,omitempty" mapstructure:"glob" toml:"glob,omitempty" yaml:",omitempty"`
Actions []*Action `json:"actions,omitempty" mapstructure:"actions" toml:"actions,omitempty" yaml:",omitempty"`
}

func (action *Action) PrintableName(id string) string {
if len(action.Name) != 0 {
return action.Name
}
if len(action.Run) != 0 {
return action.Run
}
if len(action.Script) != 0 {
return action.Script
}

return "[" + id + "]"
}

func (g *Group) PrintableName(id string) string {
if len(g.Name) != 0 {
return g.Name
}

return "[" + id + "]"
}
18 changes: 1 addition & 17 deletions internal/config/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ package config

import (
"errors"

"github.com/evilmartians/lefthook/internal/git"
"github.com/evilmartians/lefthook/internal/system"
)

var errFilesIncompatible = errors.New("One of your runners contains incompatible file types")
var ErrFilesIncompatible = errors.New("One of your runners contains incompatible file types")

type Command struct {
Run string `json:"run" mapstructure:"run" toml:"run" yaml:"run"`
Expand All @@ -31,19 +28,6 @@ type Command struct {
StageFixed bool `json:"stage_fixed,omitempty" koanf:"stage_fixed" mapstructure:"stage_fixed" toml:"stage_fixed,omitempty" yaml:"stage_fixed,omitempty"`
}

func (c Command) Validate() error {
if !isRunnerFilesCompatible(c.Run) {
return errFilesIncompatible
}

return nil
}

func (c Command) DoSkip(state func() git.State) bool {
skipChecker := NewSkipChecker(system.Cmd)
return skipChecker.check(state, c.Skip, c.Only)
}

func (c Command) ExecutionPriority() int {
return c.Priority
}
6 changes: 0 additions & 6 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import (
"github.com/mitchellh/mapstructure"
toml "github.com/pelletier/go-toml/v2"
"gopkg.in/yaml.v3"

"github.com/evilmartians/lefthook/internal/version"
)

type DumpFormat int
Expand Down Expand Up @@ -46,10 +44,6 @@ type Config struct {
Hooks map[string]*Hook `mapstructure:"-"`
}

func (c *Config) Validate() error {
return version.CheckCovered(c.MinVersion)
}

func (c *Config) Md5() (checksum string, err error) {
configBytes := new(bytes.Buffer)

Expand Down
7 changes: 2 additions & 5 deletions internal/config/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ const (
SubPushFiles string = "{push_files}"
)

func isRunnerFilesCompatible(runner string) bool {
if strings.Contains(runner, SubStagedFiles) && strings.Contains(runner, SubPushFiles) {
return false
}
return true
func IsRunFilesCompatible(run string) bool {
return !(strings.Contains(run, SubStagedFiles) && strings.Contains(run, SubPushFiles))
}
20 changes: 5 additions & 15 deletions internal/config/hook.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,28 @@
package config

import (
"errors"

"github.com/evilmartians/lefthook/internal/git"
"github.com/evilmartians/lefthook/internal/system"
)

const CMD = "{cmd}"

var errPipedAndParallelSet = errors.New("conflicting options 'piped' and 'parallel' are set to 'true', remove one of this option from hook group")

type Hook struct {
Commands map[string]*Command `json:"commands,omitempty" mapstructure:"-" toml:"commands,omitempty" yaml:",omitempty"`
Scripts map[string]*Script `json:"scripts,omitempty" mapstructure:"-" toml:"scripts,omitempty" yaml:",omitempty"`

Files string `json:"files,omitempty" mapstructure:"files" toml:"files,omitempty" yaml:",omitempty"`
Parallel bool `json:"parallel,omitempty" mapstructure:"parallel" toml:"parallel,omitempty" yaml:",omitempty"`
Piped bool `json:"piped,omitempty" mapstructure:"piped" toml:"piped,omitempty" yaml:",omitempty"`
Follow bool `json:"follow,omitempty" mapstructure:"follow" toml:"follow,omitempty" yaml:",omitempty"`
Files string `json:"files,omitempty" mapstructure:"files" toml:"files,omitempty" yaml:",omitempty"`
ExcludeTags []string `json:"exclude_tags,omitempty" koanf:"exclude_tags" mapstructure:"exclude_tags" toml:"exclude_tags,omitempty" yaml:"exclude_tags,omitempty"`
Skip interface{} `json:"skip,omitempty" mapstructure:"skip" toml:"skip,omitempty,inline" yaml:",omitempty"`
Only interface{} `json:"only,omitempty" mapstructure:"only" toml:"only,omitempty,inline" yaml:",omitempty"`
}

func (h *Hook) Validate() error {
if h.Parallel && h.Piped {
return errPipedAndParallelSet
}
Actions []*Action `json:"actions,omitempty" mapstructure:"actions" toml:"actions,omitempty" yaml:",omitempty"`

return nil
Commands map[string]*Command `json:"commands,omitempty" mapstructure:"-" toml:"commands,omitempty" yaml:",omitempty"`
Scripts map[string]*Script `json:"scripts,omitempty" mapstructure:"-" toml:"scripts,omitempty" yaml:",omitempty"`
}

func (h *Hook) DoSkip(state func() git.State) bool {
skipChecker := NewSkipChecker(system.Cmd)
return skipChecker.check(state, h.Skip, h.Only)
return skipChecker.Check(state, h.Skip, h.Only)
}
2 changes: 1 addition & 1 deletion internal/config/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Script struct {

func (s Script) DoSkip(state func() git.State) bool {
skipChecker := NewSkipChecker(system.Cmd)
return skipChecker.check(state, s.Skip, s.Only)
return skipChecker.Check(state, s.Skip, s.Only)
}

func (s Script) ExecutionPriority() int {
Expand Down
2 changes: 1 addition & 1 deletion internal/config/skip_checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func NewSkipChecker(cmd system.Command) *skipChecker {
}

// check returns the result of applying a skip/only setting which can be a branch, git state, shell command, etc.
func (sc *skipChecker) check(state func() git.State, skip interface{}, only interface{}) bool {
func (sc *skipChecker) Check(state func() git.State, skip interface{}, only interface{}) bool {
if skip == nil && only == nil {
return false
}
Expand Down
4 changes: 2 additions & 2 deletions internal/config/skip_checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (mc mockCmd) Run(cmd []string, _root string, _in io.Reader, _out io.Writer,
}
}

func TestDoSkip(t *testing.T) {
func TestSkipChecker_Check(t *testing.T) {
skipChecker := NewSkipChecker(mockCmd{})

for _, tt := range [...]struct {
Expand Down Expand Up @@ -151,7 +151,7 @@ func TestDoSkip(t *testing.T) {
},
} {
t.Run(tt.name, func(t *testing.T) {
if skipChecker.check(tt.state, tt.skip, tt.only) != tt.skipped {
if skipChecker.Check(tt.state, tt.skip, tt.only) != tt.skipped {
t.Errorf("Expected: %v, Was %v", tt.skipped, !tt.skipped)
}
})
Expand Down
31 changes: 19 additions & 12 deletions internal/lefthook/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/evilmartians/lefthook/internal/config"
"github.com/evilmartians/lefthook/internal/lefthook/runner"
"github.com/evilmartians/lefthook/internal/log"
"github.com/evilmartians/lefthook/internal/version"
)

const (
Expand All @@ -21,6 +22,8 @@ const (
envOutput = "LEFTHOOK_OUTPUT" // "meta,success,failure,summary,skips,execution,execution_out,execution_info"
)

var errPipedAndParallelSet = errors.New("conflicting options 'piped' and 'parallel' are set to 'true', remove one of this option from hook group")

type RunArgs struct {
NoTTY bool
AllFiles bool
Expand Down Expand Up @@ -64,7 +67,7 @@ func (l *Lefthook) Run(hookName string, args RunArgs, gitArgs []string) error {
return err
}

if err = cfg.Validate(); err != nil {
if err = version.CheckCovered(cfg.MinVersion); err != nil {
return err
}

Expand Down Expand Up @@ -115,8 +118,9 @@ func (l *Lefthook) Run(hookName string, args RunArgs, gitArgs []string) error {

return fmt.Errorf("Hook %s doesn't exist in the config", hookName)
}
if err := hook.Validate(); err != nil {
return err

if hook.Parallel && hook.Piped {
return errPipedAndParallelSet
}

if args.FilesFromStdin {
Expand Down Expand Up @@ -167,11 +171,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 Expand Up @@ -222,13 +227,17 @@ func printSummary(
)
}

logResults(0, results, logSettings)
}

func logResults(indent int, results []runner.Result, logSettings log.Settings) {
if logSettings.LogSuccess() {
for _, result := range results {
if !result.Success() {
continue
}

log.Success(result.Name)
log.Success(indent, result.Name)
}
}

Expand All @@ -238,7 +247,11 @@ func printSummary(
continue
}

log.Failure(result.Name, result.Text())
log.Failure(indent, result.Name, result.Text())

if len(result.Sub) > 0 {
logResults(indent+1, result.Sub, logSettings)
}
}
}
}
Expand All @@ -256,9 +269,6 @@ func (l *Lefthook) configHookCompletions() []string {
if err != nil {
return nil
}
if err = cfg.Validate(); err != nil {
return nil
}
hooks := make([]string, 0, len(cfg.Hooks))
for hook := range cfg.Hooks {
hooks = append(hooks, hook)
Expand All @@ -279,9 +289,6 @@ func (l *Lefthook) configHookCommandCompletions(hookName string) []string {
if err != nil {
return nil
}
if err = cfg.Validate(); err != nil {
return nil
}
if hook, found := cfg.Hooks[hookName]; !found {
return nil
} else {
Expand Down
Loading

0 comments on commit 51f32aa

Please sign in to comment.