diff --git a/CHANGELOG.md b/CHANGELOG.md index 83136d78..46c288c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## master (unreleased) +- fix: Omit LFS output unless it is required ([PR #373](https://github.com/evilmartians/lefthook/pull/373) by @mrexox) + ## 1.2.1 (2022-11-17) - fix: Remove quoting for scripts ([PR #371](https://github.com/evilmartians/lefthook/pull/371) by @stonesbg + @mrexox) diff --git a/docs/usage.md b/docs/usage.md index e6bc521d..9bcff124 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -279,9 +279,13 @@ SHA1=$3 ### Git LFS support +> :warning: If git-lfs binary is not installed and not required in your project, LFS hooks won't be executed, and you won't be warned about it. + Lefthook runs LFS hooks internally for the following hooks: - post-checkout - post-commit - post-merge - pre-push + +Errors are suppressed if git LFS is not required for the project. You can use [`LEFTHOOK_VERBOSE`](#lefthook_verbose) ENV to make lefthook show git LFS output. diff --git a/internal/lefthook/runner/execute_unix.go b/internal/lefthook/runner/execute_unix.go index 78e1f45f..0f307d68 100644 --- a/internal/lefthook/runner/execute_unix.go +++ b/internal/lefthook/runner/execute_unix.go @@ -76,10 +76,13 @@ func (e CommandExecutor) Execute(opts ExecuteOptions) (*bytes.Buffer, error) { return out, command.Wait() } -func (e CommandExecutor) RawExecute(command string, args ...string) error { +func (e CommandExecutor) RawExecute(command string, args ...string) (*bytes.Buffer, error) { cmd := exec.Command(command, args...) - cmd.Stdout = os.Stdout + + var out bytes.Buffer + + cmd.Stdout = &out cmd.Stderr = os.Stderr - return cmd.Run() + return &out, cmd.Run() } diff --git a/internal/lefthook/runner/execute_windows.go b/internal/lefthook/runner/execute_windows.go index fce93814..459a433f 100644 --- a/internal/lefthook/runner/execute_windows.go +++ b/internal/lefthook/runner/execute_windows.go @@ -51,10 +51,13 @@ func (e CommandExecutor) Execute(opts ExecuteOptions) (*bytes.Buffer, error) { return &out, command.Wait() } -func (e CommandExecutor) RawExecute(command string, args ...string) error { +func (e CommandExecutor) RawExecute(command string, args ...string) (*bytes.Buffer, error) { cmd := exec.Command(command, args...) - cmd.Stdout = os.Stdout + + var out bytes.Buffer + + cmd.Stdout = &out cmd.Stderr = os.Stderr - return cmd.Run() + return &out, cmd.Run() } diff --git a/internal/lefthook/runner/executor.go b/internal/lefthook/runner/executor.go index 863659e4..64617f69 100644 --- a/internal/lefthook/runner/executor.go +++ b/internal/lefthook/runner/executor.go @@ -16,5 +16,5 @@ type ExecuteOptions struct { // It is used here for testing purpose mostly. type Executor interface { Execute(opts ExecuteOptions) (*bytes.Buffer, error) - RawExecute(command string, args ...string) error + RawExecute(command string, args ...string) (*bytes.Buffer, error) } diff --git a/internal/lefthook/runner/runner.go b/internal/lefthook/runner/runner.go index 91cf699d..9a130cac 100644 --- a/internal/lefthook/runner/runner.go +++ b/internal/lefthook/runner/runner.go @@ -111,19 +111,37 @@ func (r *Runner) runLFSHook(hookName string) error { if git.IsLFSAvailable() { log.Debugf( - "Executing LFS Hook: `git lfs %s %s", hookName, strings.Join(r.args, " "), + "[git-lfs] executing hook: git lfs %s %s", hookName, strings.Join(r.args, " "), ) - err := r.exec.RawExecute( + out, err := r.exec.RawExecute( "git", append( []string{"lfs", hookName}, r.args..., )..., ) + + output := strings.Trim(out.String(), "\n") + if output != "" { + log.Debug("[git-lfs] output: ", output) + } if err != nil { - return errors.New("git-lfs command failed") + log.Debug("[git-lfs] error: ", err) + } + + if err == nil && output != "" { + log.Info(output) + } + + if err != nil && (requiredExists || configExists) { + log.Warn(output) + return fmt.Errorf("git-lfs command failed: %w", err) } - } else if requiredExists || configExists { + + return nil + } + + if requiredExists || configExists { log.Errorf( "This repository requires Git LFS, but 'git-lfs' wasn't found.\n"+ "Install 'git-lfs' or consider reviewing the files:\n"+ @@ -204,7 +222,7 @@ func (r *Runner) runScript(script *config.Script, path string, file os.FileInfo) // Skip non-regular files (dirs, symlinks, sockets, etc.) if !file.Mode().IsRegular() { - log.Debugf("File %s is not a regular file, skipping", file.Name()) + log.Debugf("[lefthook] file %s is not a regular file, skipping", file.Name()) return } @@ -377,7 +395,7 @@ func (r *Runner) buildCommandArgs(command *config.Command) ([]string, error) { runString = strings.ReplaceAll(runString, fmt.Sprintf("{%d}", i+1), gitArg) } - log.Debug("Executing command is: ", runString) + log.Debug("[lefthook] executing: ", runString) return strings.Split(runString, " "), nil } @@ -387,13 +405,13 @@ func prepareFiles(command *config.Command, files []string) []string { return []string{} } - log.Debug("Files before filters:\n", files) + log.Debug("[lefthook] files before filters:\n", files) files = filterGlob(files, command.Glob) files = filterExclude(files, command.Exclude) files = filterRelative(files, command.Root) - log.Debug("Files after filters:\n", files) + log.Debug("[lefthook] files after filters:\n", files) // Escape file names to prevent unexpected bugs var filesEsc []string @@ -403,7 +421,7 @@ func prepareFiles(command *config.Command, files []string) []string { } } - log.Debug("Files after escaping:\n", filesEsc) + log.Debug("[lefthook] files after escaping:\n", filesEsc) return filesEsc } diff --git a/internal/lefthook/runner/runner_test.go b/internal/lefthook/runner/runner_test.go index 2ca73ba2..0a58113a 100644 --- a/internal/lefthook/runner/runner_test.go +++ b/internal/lefthook/runner/runner_test.go @@ -27,8 +27,8 @@ func (e TestExecutor) Execute(opts ExecuteOptions) (out *bytes.Buffer, err error return } -func (e TestExecutor) RawExecute(command string, args ...string) error { - return nil +func (e TestExecutor) RawExecute(command string, args ...string) (*bytes.Buffer, error) { + return nil, nil } func TestRunAll(t *testing.T) {