diff --git a/cmd/lefthook/main.go b/cmd/lefthook/main.go index 16b81695..8ab96621 100644 --- a/cmd/lefthook/main.go +++ b/cmd/lefthook/main.go @@ -10,7 +10,9 @@ func main() { rootCmd := newRootCmd() if err := rootCmd.Execute(); err != nil { - log.Errorf("Error: %s", err) + if err.Error() != "" { + log.Errorf("Error: %s", err) + } os.Exit(1) } } diff --git a/internal/config/load.go b/internal/config/load.go index 38d93b8d..560a1c0b 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -2,6 +2,7 @@ package config import ( "path/filepath" + "regexp" "strings" "github.com/spf13/afero" @@ -14,6 +15,8 @@ const ( DefaultColorsEnabled = true ) +var hookKeyRegexp = regexp.MustCompile(`^(?P[^.]+)\.(scripts|commands)`) + // Loads configs from the given directory with extensions. func Load(fs afero.Fs, path string) (*Config, error) { global, err := read(fs, path, "lefthook") @@ -103,21 +106,27 @@ func unmarshalConfigs(base, extra *viper.Viper, c *Config) error { c.Hooks = make(map[string]*Hook) for _, hookName := range AvailableHooks { - baseHook := base.Sub(hookName) - extraHook := extra.Sub(hookName) - - resultHook, err := unmarshalHooks(baseHook, extraHook) - if err != nil { + if err := addHook(hookName, base, extra, c); err != nil { return err } + } - if resultHook == nil { + // For extra non-git hooks. + // This behavior will be deprecated in next versions. + for _, maybeHook := range base.AllKeys() { + if !hookKeyRegexp.MatchString(maybeHook) { continue } - resultHook.processDeprecations() + matches := hookKeyRegexp.FindStringSubmatch(maybeHook) + hookName := matches[hookKeyRegexp.SubexpIndex("hookName")] + if _, ok := c.Hooks[hookName]; ok { + continue + } - c.Hooks[hookName] = resultHook + if err := addHook(hookName, base, extra, c); err != nil { + return err + } } // Merge config and unmarshal it @@ -130,3 +139,23 @@ func unmarshalConfigs(base, extra *viper.Viper, c *Config) error { return nil } + +func addHook(hookName string, base, extra *viper.Viper, c *Config) error { + baseHook := base.Sub(hookName) + extraHook := extra.Sub(hookName) + + resultHook, err := unmarshalHooks(baseHook, extraHook) + if err != nil { + return err + } + + if resultHook == nil { + return nil + } + + resultHook.processDeprecations() + + c.Hooks[hookName] = resultHook + + return nil +} diff --git a/internal/config/load_test.go b/internal/config/load_test.go index 22b5f47a..ecf343d8 100644 --- a/internal/config/load_test.go +++ b/internal/config/load_test.go @@ -141,6 +141,42 @@ pre-push: }, }, }, + { + name: "with extra hooks", + global: []byte(` +tests: + commands: + tests: + run: go test ./... + +lints: + scripts: + "linter.sh": + runner: bash +`), + result: &Config{ + SourceDir: DefaultSourceDir, + SourceDirLocal: DefaultSourceDirLocal, + Colors: true, // defaults to true + Hooks: map[string]*Hook{ + "tests": { + Parallel: false, + Commands: map[string]*Command{ + "tests": { + Run: "go test ./...", + }, + }, + }, + "lints": { + Scripts: map[string]*Script{ + "linter.sh": { + Runner: "bash", + }, + }, + }, + }, + }, + }, } { fs := afero.Afero{Fs: afero.NewMemMapFs()} t.Run(fmt.Sprintf("%d: %s", i, tt.name), func(t *testing.T) { diff --git a/internal/lefthook/run.go b/internal/lefthook/run.go index ce809c1a..6d21bfad 100644 --- a/internal/lefthook/run.go +++ b/internal/lefthook/run.go @@ -118,8 +118,7 @@ func (l *Lefthook) Run(hookName string, gitArgs []string) error { } if len(failList) > 0 { - log.Error() // A newline just to make it look prettier - return errors.New("some steps failed") + return errors.New("") // No error should be printed } return nil diff --git a/internal/lefthook/runner/execute_unix.go b/internal/lefthook/runner/execute_unix.go index be94eb04..c9fee9b3 100644 --- a/internal/lefthook/runner/execute_unix.go +++ b/internal/lefthook/runner/execute_unix.go @@ -11,8 +11,6 @@ import ( "strings" "github.com/creack/pty" - - "github.com/evilmartians/lefthook/internal/log" ) func Execute(root string, args []string) (*bytes.Buffer, error) { @@ -25,12 +23,8 @@ func Execute(root string, args []string) (*bytes.Buffer, error) { return nil, err } defer func() { _ = ptyOut.Close() }() - out := bytes.NewBuffer(make([]byte, 0)) - _, err = io.Copy(out, ptyOut) - if err != nil { - log.Debug(err) - } + _, _ = io.Copy(out, ptyOut) return out, command.Wait() }