diff --git a/go.mod b/go.mod index 16c0837c..1ac0de14 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.17 require ( github.com/MakeNowJust/heredoc v1.0.0 github.com/briandowns/spinner v1.18.1 + github.com/creack/pty v1.1.17 github.com/gobwas/glob v0.2.3 github.com/google/go-cmp v0.5.6 - github.com/kr/pty v1.1.1 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/mitchellh/mapstructure v1.4.2 github.com/spf13/afero v1.6.0 diff --git a/go.sum b/go.sum index a635a2da..fb30815f 100644 --- a/go.sum +++ b/go.sum @@ -72,6 +72,8 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -212,7 +214,6 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= diff --git a/internal/config/command.go b/internal/config/command.go index 6db0a7da..3a618ea3 100644 --- a/internal/config/command.go +++ b/internal/config/command.go @@ -1,6 +1,7 @@ package config import ( + "errors" "strings" "github.com/spf13/viper" @@ -8,6 +9,8 @@ import ( "github.com/evilmartians/lefthook/internal/git" ) +var errFilesIncompatible = errors.New("One of your runners contains incompatible file types") + type Command struct { Run string `mapstructure:"run"` @@ -23,6 +26,14 @@ type Command struct { Runner string `mapstructure:"runner"` } +func (c Command) Validate() error { + if !isRunnerFilesCompatible(c.Run) { + return errFilesIncompatible + } + + return nil +} + func (c Command) DoSkip(gitState git.State) bool { if value := c.Skip; value != nil { return isSkip(gitState, value) @@ -30,14 +41,6 @@ func (c Command) DoSkip(gitState git.State) bool { return false } -func (c Command) GetRunner() string { - runner := c.Run - if runner == "" { - runner = c.Runner - } - return runner -} - type commandRunReplace struct { Run string `mapstructure:"run"` Runner string `mapstructure:"runner"` // DEPRECATED diff --git a/internal/config/files.go b/internal/config/files.go new file mode 100644 index 00000000..ba9f1da5 --- /dev/null +++ b/internal/config/files.go @@ -0,0 +1,17 @@ +package config + +import "strings" + +const ( + SubFiles string = "{files}" + SubAllFiles string = "{all_files}" + SubStagedFiles string = "{staged_files}" + PushFiles string = "{push_files}" +) + +func isRunnerFilesCompatible(runner string) bool { + if strings.Contains(runner, SubStagedFiles) && strings.Contains(runner, PushFiles) { + return false + } + return true +} diff --git a/internal/config/hook.go b/internal/config/hook.go index ff09501b..c3f3d92e 100644 --- a/internal/config/hook.go +++ b/internal/config/hook.go @@ -2,7 +2,9 @@ package config import ( "errors" + "os" "sort" + "strings" "github.com/spf13/viper" @@ -78,6 +80,10 @@ func unmarshalHooks(base, extra *viper.Viper) (*Hook, error) { return nil, err } + if tags := os.Getenv("LEFTHOOK_EXCLUDE"); tags != "" { + hook.ExcludeTags = append(hook.ExcludeTags, strings.Split(tags, ",")...) + } + return &hook, nil } diff --git a/internal/config/load.go b/internal/config/load.go index 9c0cd558..6b251e6a 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -1,6 +1,7 @@ package config import ( + "os" "path/filepath" "strings" @@ -127,5 +128,9 @@ func unmarshalConfigs(base, extra *viper.Viper, c *Config) error { return err } + if tags := os.Getenv("LEFTHOOK_QUIET"); tags != "" { + c.SkipOutput = append(c.SkipOutput, strings.Split(tags, ",")...) + } + return nil } diff --git a/internal/config/script.go b/internal/config/script.go index 96e36319..23639380 100644 --- a/internal/config/script.go +++ b/internal/config/script.go @@ -26,14 +26,6 @@ func (s Script) DoSkip(gitState git.State) bool { return false } -func (s Script) GetRunner() string { - runner := s.Runner - if runner == "" { - runner = s.Run - } - return runner -} - type scriptRunnerReplace struct { Runner string `mapstructure:"runner"` Run string `mapstructure:"run"` // DEPRECATED diff --git a/internal/lefthook/output.go b/internal/lefthook/output.go index ed47ec94..a534a79c 100644 --- a/internal/lefthook/output.go +++ b/internal/lefthook/output.go @@ -12,8 +12,8 @@ const ( type outputDisablerFn func(out ...interface{}) string -func outputDisabler(output string, disabledOutputs []string, envDisabledOutputs []string) outputDisablerFn { - if isOutputDisabled(output, disabledOutputs, envDisabledOutputs) { +func outputDisabler(output string, disabledOutputs []string) outputDisablerFn { + if isOutputDisabled(output, disabledOutputs) { return func(...interface{}) string { return "" } @@ -23,16 +23,11 @@ func outputDisabler(output string, disabledOutputs []string, envDisabledOutputs } } -func isOutputDisabled(output string, disabledOutputs []string, envDisabledOutputs []string) bool { +func isOutputDisabled(output string, disabledOutputs []string) bool { for _, disabledOutput := range disabledOutputs { if output == disabledOutput { return true } } - for _, disabledOutput := range envDisabledOutputs { - if output == disabledOutput { - return true - } - } return false } diff --git a/internal/lefthook/run.go b/internal/lefthook/run.go index 53647157..fd0147da 100644 --- a/internal/lefthook/run.go +++ b/internal/lefthook/run.go @@ -27,17 +27,10 @@ var ( failList []string isPipeBroken bool - envExcludedTags []string - successSprint outputDisablerFn ) const ( - subFiles string = "{files}" - subAllFiles string = "{all_files}" - subStagedFiles string = "{staged_files}" - pushFiles string = "{push_files}" - execMode os.FileMode = 0751 execMask os.FileMode = 0111 ) @@ -61,33 +54,25 @@ func (l *Lefthook) Run(hookName string, gitArgs []string) error { return err } if err := cfg.Validate(); err != nil { - log.Info(log.Brown(fmt.Sprintf("Config error! %s", err))) + log.Info(log.Red(fmt.Sprintf("Config error! %s", err))) return err } - if tags := os.Getenv("LEFTHOOK_EXCLUDE"); tags != "" { - envExcludedTags = strings.Split(tags, ",") - } - - var envDisabledOutputs []string - if tags := os.Getenv("LEFTHOOK_QUIET"); tags != "" { - envDisabledOutputs = strings.Split(tags, ",") - } - successSprint = outputDisabler(outputSuccess, cfg.SkipOutput, envDisabledOutputs) + successSprint = outputDisabler(outputSuccess, cfg.SkipOutput) hook, ok := cfg.Hooks[hookName] if !ok { - log.Info(log.Brown(fmt.Sprintf("Can't find hook by name '%s'.", hookName))) + log.Info(log.Red(fmt.Sprintf("Can't find hook by name '%s'.", hookName))) return errors.New("hook is not found") } if err := hook.Validate(); err != nil { - log.Info(log.Brown(fmt.Sprintf("Config error! %s", err))) + log.Info(log.Red(fmt.Sprintf("Config error! %s", err))) return err } startTime := time.Now() - if !isOutputDisabled(outputMeta, cfg.SkipOutput, envDisabledOutputs) { + if !isOutputDisabled(outputMeta, cfg.SkipOutput) { log.Info(log.Cyan("Lefthook v" + version.Version())) log.Info(log.Cyan("RUNNING HOOK:"), log.Bold(hookName)) } @@ -95,8 +80,9 @@ func (l *Lefthook) Run(hookName string, gitArgs []string) error { spinner.Start() var wg sync.WaitGroup - l.executeScripts(hookName, gitArgs, cfg.SourceDir, hook, &wg) - l.executeScripts(hookName, gitArgs, cfg.SourceDirLocal, hook, &wg) + + l.executeScripts(filepath.Join(cfg.SourceDir, hookName), gitArgs, hook, &wg) + l.executeScripts(filepath.Join(cfg.SourceDirLocal, hookName), gitArgs, hook, &wg) for _, name := range hook.CommandsSorted { wg.Add(1) @@ -111,7 +97,7 @@ func (l *Lefthook) Run(hookName string, gitArgs []string) error { wg.Wait() spinner.Stop() - if !isOutputDisabled(outputSummary, cfg.SkipOutput, envDisabledOutputs) { + if !isOutputDisabled(outputSummary, cfg.SkipOutput) { printSummary(time.Since(startTime)) } @@ -125,39 +111,90 @@ func (l *Lefthook) executeCommand(commandName string, gitArgs []string, hook *co defer wg.Done() if hook.Piped && isPipeBroken { - spinner.RestartWithMsg("\n", log.Bold(commandName), log.Brown("(SKIP BY BROKEN PIPE)")) + spinner.RestartWithMsg("\n", log.Bold(commandName), log.Red("(SKIP BY BROKEN PIPE)")) return } command := hook.Commands[commandName] + if err := command.Validate(); err != nil { + appendFailList(commandName) + setPipeBroken() + spinner.RestartWithMsg(commandName, log.Red(fmt.Sprintf("(SKIP BY CONFIG ERROR: %s)", err))) + return + } if command.DoSkip(l.repo.State()) { - spinner.RestartWithMsg(successSprint(log.Bold(commandName), log.Brown("(SKIP BY SETTINGS)"))) + spinner.RestartWithMsg(successSprint(log.Bold(commandName), log.Red("(SKIP BY SETTINGS)"))) return } if isContainsExcludedTags(command.Tags, hook.ExcludeTags) { - spinner.RestartWithMsg(successSprint(log.Bold(commandName), log.Brown("(SKIP BY TAGS)"))) + spinner.RestartWithMsg(successSprint(log.Bold(commandName), log.Red("(SKIP BY TAGS)"))) return } - runner := command.GetRunner() - - var files []string filesCommand := hook.Files if command.Files != "" { filesCommand = command.Files } - if strings.Contains(runner, subStagedFiles) { - files, _ = l.repo.StagedFiles() - } else if strings.Contains(runner, subFiles) || filesCommand != "" { - files, _ = git.FilesByCommand(filesCommand) - } else if strings.Contains(runner, pushFiles) { - files, _ = l.repo.PushFiles() + runner := command.Run + if strings.Contains(runner, config.SubStagedFiles) { + files, err := l.repo.StagedFiles() + files = prepareFiles(command, files) + if err == nil { + runner = strings.ReplaceAll(runner, config.SubStagedFiles, strings.Join(files, " ")) + } + } + if strings.Contains(runner, config.SubFiles) || filesCommand != "" { + files, err := git.FilesByCommand(filesCommand) + files = prepareFiles(command, files) + if err == nil { + runner = strings.ReplaceAll(runner, config.SubFiles, strings.Join(files, " ")) + } + } + if strings.Contains(runner, config.PushFiles) { + files, err := l.repo.PushFiles() + files = prepareFiles(command, files) + if err == nil { + runner = strings.ReplaceAll(runner, config.PushFiles, strings.Join(files, " ")) + } + } + if strings.Contains(runner, config.SubAllFiles) { + files, err := l.repo.AllFiles() + files = prepareFiles(command, files) + if err == nil { + runner = strings.ReplaceAll(runner, config.SubAllFiles, strings.Join(files, " ")) + } + } + + runner = strings.ReplaceAll(runner, "{0}", strings.Join(gitArgs, " ")) + for gitArgIndex, gitArg := range gitArgs { + runner = strings.ReplaceAll(runner, fmt.Sprintf("{%d}", gitArgIndex+1), gitArg) + } + + commandOutput, isRun, err := RunCommand(runner, command.Root) + + stageName := fmt.Sprintln(log.Cyan("\n EXECUTE >"), log.Bold(commandName)) + if !isRun { + appendFailList(commandName) + setPipeBroken() + spinner.RestartWithMsg(stageName, err) + return + } + + if err == nil { + spinner.RestartWithMsg(successSprint(stageName, commandOutput.String())) + + appendOkList(commandName) } else { - files, _ = l.repo.AllFiles() + spinner.RestartWithMsg(stageName, commandOutput.String()) + + appendFailList(commandName) + setPipeBroken() } +} +func prepareFiles(command *config.Command, files []string) []string { log.Debug("\nFiles before filters: \n", files) files = FilterGlob(files, command.Glob) @@ -176,124 +213,93 @@ func (l *Lefthook) executeCommand(commandName string, gitArgs []string, hook *co log.Debug("Files after escaping: \n", files) - runner = strings.Replace(runner, pushFiles, strings.Join(files, " "), -1) - runner = strings.Replace(runner, subStagedFiles, strings.Join(files, " "), -1) - runner = strings.Replace(runner, subAllFiles, strings.Join(files, " "), -1) - runner = strings.Replace(runner, subFiles, strings.Join(files, " "), -1) - runner = strings.Replace(runner, "{0}", strings.Join(gitArgs, " "), -1) - for gitArgIndex, gitArg := range gitArgs { - runner = strings.Replace(runner, fmt.Sprintf("{%d}", gitArgIndex+1), gitArg, -1) - } + return files +} - commandOutput, wait, err := RunCommand(runner, command.Root) +func (l *Lefthook) executeScripts(sourcePath string, gitArgs []string, hook *config.Hook, wg *sync.WaitGroup) { + executables, err := afero.ReadDir(l.Fs, sourcePath) + if err != nil || len(executables) == 0 { + return + } - mutex.Lock() - defer mutex.Unlock() + for _, executable := range executables { + wg.Add(1) - stageName := fmt.Sprintln(log.Cyan("\n EXECUTE >"), log.Bold(commandName)) - if err != nil { - failList = append(failList, commandName) - setPipeBroken() - spinner.RestartWithMsg(stageName, err) - return + if hook.Parallel { + go l.executeScript(executable, gitArgs, sourcePath, hook, wg) + } else { + l.executeScript(executable, gitArgs, sourcePath, hook, wg) + } } +} - if wait() == nil { - spinner.RestartWithMsg(successSprint(stageName, commandOutput.String())) +func (l *Lefthook) executeScript(executable os.FileInfo, gitArgs []string, sourcePath string, hook *config.Hook, wg *sync.WaitGroup) { + defer wg.Done() - okList = append(okList, commandName) - } else { - spinner.RestartWithMsg(stageName, commandOutput.String()) + executableName := executable.Name() - failList = append(failList, commandName) - setPipeBroken() + if hook.Piped && isPipeBroken { + spinner.RestartWithMsg("\n", log.Bold(executableName), log.Red("(SKIP BY BROKEN PIPE)")) + return } -} -func (l *Lefthook) executeScripts(hookName string, gitArgs []string, sourceDir string, hook *config.Hook, wg *sync.WaitGroup) { - sourcePath := filepath.Join(sourceDir, hookName) - executables, err := afero.ReadDir(l.Fs, sourcePath) - if err != nil || len(executables) == 0 { + script, ok := hook.Scripts[executableName] + if !ok { + spinner.RestartWithMsg(successSprint(log.Bold(executableName), log.Red("(SKIP BY NOT EXIST IN CONFIG)"))) + return + } + if script.DoSkip(l.repo.State()) { + spinner.RestartWithMsg(successSprint(log.Bold(executableName), log.Red("(SKIP BY SETTINGS)"))) + return + } + if isContainsExcludedTags(script.Tags, hook.ExcludeTags) { + spinner.RestartWithMsg(successSprint(log.Bold(executableName), log.Red("(SKIP BY TAGS)"))) return } - for _, executable := range executables { - wg.Add(1) + executablePath := filepath.Join(sourcePath, executableName) + if err := isExecutable(executable); err != nil { + if err := l.Fs.Chmod(executablePath, execMode); err != nil { + appendFailList(executableName) - f := func() { - defer wg.Done() - - executableName := executable.Name() - - if hook.Piped && isPipeBroken { - spinner.RestartWithMsg("\n", log.Bold(executableName), log.Brown("(SKIP BY BROKEN PIPE)")) - return - } - - script, ok := hook.Scripts[executableName] - if !ok { - spinner.RestartWithMsg(successSprint(log.Bold(executableName), log.Brown("(SKIP BY NOT EXIST IN CONFIG)"))) - return - } - if script.DoSkip(l.repo.State()) { - spinner.RestartWithMsg(successSprint(log.Bold(executableName), log.Brown("(SKIP BY SETTINGS)"))) - return - } - if isContainsExcludedTags(script.Tags, hook.ExcludeTags) { - spinner.RestartWithMsg(successSprint(log.Bold(executableName), log.Brown("(SKIP BY TAGS)"))) - return - } - - executablePath := filepath.Join(sourcePath, executableName) - if err := isExecutable(executable); err != nil { - if err := l.Fs.Chmod(executablePath, execMode); err != nil { - log.Error(err) - panic(err) - } - } - - command := exec.Command(executablePath, gitArgs...) - if runner := script.GetRunner(); runner != "" { - runnerArg := append(strings.Split(runner, " "), executablePath) - runnerArg = append(runnerArg, gitArgs...) - - command = exec.Command(runnerArg[0], runnerArg[1:]...) - } - - commandOutput, wait, err := RunPlainCommand(command) - - mutex.Lock() - defer mutex.Unlock() - - stageName := fmt.Sprintln(log.Cyan("\n EXECUTE >"), log.Bold(executableName)) - if os.IsPermission(err) { - spinner.RestartWithMsg(successSprint(stageName, log.Brown("(SKIP NOT EXECUTABLE FILE)"))) - return - } - if err != nil { - failList = append(failList, executableName) - spinner.RestartWithMsg(stageName, err, log.Brown("TIP: Command start failed. Checkout `runner:` option for this script")) - setPipeBroken() - return - } - - if wait() == nil { - spinner.RestartWithMsg(successSprint(stageName, commandOutput.String())) - - okList = append(okList, executableName) - } else { - spinner.RestartWithMsg(stageName, commandOutput.String()) - - failList = append(failList, executableName) - setPipeBroken() - } + spinner.RestartWithMsg(log.Bold(executableName), err, log.Red("(SKIP BY CHMOD ERROR)")) + setPipeBroken() + return } + } - if hook.Parallel { - go f() - } else { - f() + command := exec.Command(executablePath, gitArgs...) + if script.Runner != "" { + runnerArg := append(strings.Split(script.Runner, " "), executablePath) + runnerArg = append(runnerArg, gitArgs...) + + command = exec.Command(runnerArg[0], runnerArg[1:]...) + } + + commandOutput, isRun, err := RunPlainCommand(command) + + stageName := fmt.Sprintln(log.Cyan("\n EXECUTE >"), log.Bold(executableName)) + if !isRun { + if os.IsPermission(err) { + spinner.RestartWithMsg(successSprint(stageName, log.Red("(SKIP NOT EXECUTABLE FILE)"))) + return } + + appendFailList(executableName) + spinner.RestartWithMsg(stageName, err, log.Red("TIP: Command start failed. Checkout `runner:` option for this script")) + setPipeBroken() + return + } + + if err == nil { + spinner.RestartWithMsg(successSprint(stageName, commandOutput.String())) + + appendOkList(executableName) + } else { + spinner.RestartWithMsg(stageName, commandOutput.String()) + + appendFailList(executableName) + setPipeBroken() } } @@ -301,14 +307,26 @@ func setPipeBroken() { isPipeBroken = true } +func appendOkList(task string) { + mutex.Lock() + defer mutex.Unlock() + okList = append(okList, task) +} + +func appendFailList(task string) { + mutex.Lock() + defer mutex.Unlock() + failList = append(failList, task) +} + func isExecutable(executable os.FileInfo) error { mode := executable.Mode() if !mode.IsRegular() { - return errors.New("ErrPermission") + return os.ErrPermission } if (mode & execMask) == 0 { - return errors.New("ErrPermission") + return os.ErrPermission } return nil } @@ -323,17 +341,12 @@ func isContainsExcludedTags(entityTagsList []string, excludedTags []string) bool return true } } - for _, tag := range envExcludedTags { - if _, ok := entityTags[tag]; ok { - return true - } - } return false } func printSummary(execTime time.Duration) { if len(okList) == 0 && len(failList) == 0 { - log.Info(log.Cyan("\nSUMMARY:"), log.Brown("(SKIP EMPTY)")) + log.Info(log.Cyan("\nSUMMARY:"), log.Red("(SKIP EMPTY)")) } else { log.Info(log.Cyan(fmt.Sprintf("\nSUMMARY: (done in %.2f seconds)", execTime.Seconds()))) } diff --git a/internal/lefthook/run_command.go b/internal/lefthook/run_command.go index 4a32e6f9..8554b6b0 100644 --- a/internal/lefthook/run_command.go +++ b/internal/lefthook/run_command.go @@ -3,16 +3,17 @@ package lefthook import ( "bytes" "io" - "os" "os/exec" "path/filepath" - "github.com/kr/pty" + "github.com/creack/pty" + + "github.com/evilmartians/lefthook/internal/log" ) type WaitFunc func() error -func RunCommand(runner string, cmdRoot string) (*bytes.Buffer, WaitFunc, error) { +func RunCommand(runner string, cmdRoot string) (*bytes.Buffer, bool, error) { command := exec.Command("sh", "-c", runner) if cmdRoot != "" { fullPath, _ := filepath.Abs(cmdRoot) @@ -22,17 +23,18 @@ func RunCommand(runner string, cmdRoot string) (*bytes.Buffer, WaitFunc, error) return RunPlainCommand(command) } -func RunPlainCommand(command *exec.Cmd) (*bytes.Buffer, WaitFunc, error) { +func RunPlainCommand(command *exec.Cmd) (*bytes.Buffer, bool, error) { ptyOut, err := pty.Start(command) + if err != nil { + return nil, false, err + } + defer ptyOut.Close() - // Copy stdin to the pty and the pty to stdout. - go func() { _, _ = io.Copy(ptyOut, os.Stdin) }() commandOutput := bytes.NewBuffer(make([]byte, 0)) - _, _ = io.Copy(commandOutput, ptyOut) - waitFunc := func() error { - wErr := command.Wait() - _ = ptyOut.Close() - return wErr + _, err = io.Copy(commandOutput, ptyOut) + if err != nil { + log.Debug(err) } - return commandOutput, waitFunc, err + + return commandOutput, true, command.Wait() } diff --git a/internal/lefthook/run_test.go b/internal/lefthook/run_test.go index 0fb397be..120ab829 100644 --- a/internal/lefthook/run_test.go +++ b/internal/lefthook/run_test.go @@ -97,6 +97,8 @@ post-commit: } { fs := afero.Afero{Fs: afero.NewMemMapFs()} t.Run(fmt.Sprintf("%d: %s", i, tt.name), func(t *testing.T) { + defer dropState() + if err := fs.WriteFile("/lefthook.yml", tt.global, 0o644); err != nil { t.Errorf("unexpected error: %s", err) } @@ -127,7 +129,6 @@ post-commit: require.ElementsMatch(t, tt.okList, okList) require.ElementsMatch(t, tt.failList, failList) }) - dropState() } } @@ -141,6 +142,7 @@ post-commit: test1: run: echo `) + defer dropState() fs := afero.Afero{Fs: afero.NewMemMapFs()} if err := fs.WriteFile("/lefthook.yml", global, 0o644); err != nil { t.Errorf("unexpected error: %s", err) @@ -158,7 +160,6 @@ post-commit: require.ElementsMatch(t, nil, okList) require.ElementsMatch(t, []string{"test0"}, failList) require.Equal(t, true, isPipeBroken) - dropState() } func dropState() { diff --git a/internal/log/log.go b/internal/log/log.go index 404e756b..656c45f2 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -105,11 +105,6 @@ func Bold(arg interface{}) aurora.Value { return std.aurora.Bold(arg) } -func Brown(arg interface{}) aurora.Value { - // aurora deprecated brown ?? - return std.aurora.Yellow(arg) -} - func SetOutput(out io.Writer) { std.SetOutput(out) }