Skip to content

Commit

Permalink
feat: Add output setting (#637)
Browse files Browse the repository at this point in the history
* add new output and deprecate `skip_output`

* fix by codereview

* rename methods from Settings, change tests
  • Loading branch information
prog-supdex authored Mar 11, 2024
1 parent 33edff8 commit ce6c29b
Show file tree
Hide file tree
Showing 9 changed files with 440 additions and 99 deletions.
38 changes: 38 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,46 @@ If you want to specify a minimum version for lefthook binary (e.g. if you need s
min_version: 1.1.3
```

### `output`

You can manage verbosity using the `output` config. You can specify what to print in your output by setting these values, which you need to have

Possible values are `meta,summary,success,failure,execution,execution_out,execution_info,skips`.
By default, all output values are enabled

You can also disable all output with setting `output: false`. In this case only errors will be printed.

This config quiets all outputs except for errors.

`output` is enabled if there is no `skip_output` and `LEFTHOOK_QUIET`.

**Example**

```yml
# lefthook.yml
output:
- meta # Print lefthook version
- summary # Print summary block (successful and failed steps)
- empty_summary # Print summary heading when there are no steps to run
- success # Print successful steps
- failure # Print failed steps printing
- execution # Print any execution logs (but prints if the execution failed)
- execution_out # Print execution output (but still prints failed commands output)
- execution_info # Print `EXECUTE > ...` logging
- skips # Print "skip" (i.e. no files matched)
```
You can also *extend* this list with an environment variable `LEFTHOOK_OUTPUT`:

```bash
LEFTHOOK_OUTPUT="meta,success,summary" lefthook run pre-commit
```

### `skip_output`

> **Deprecated:** This feature is deprecated and might be removed in future versions. Please, use `[output]` instead for managing verbosity.

You can manage the verbosity using the `skip_output` config. You can set whether lefthook should print some parts of its output.

Possible values are `meta,summary,success,failure,execution,execution_out,execution_info,skips`.
Expand Down
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Config struct {
SourceDirLocal string `mapstructure:"source_dir_local"`
Rc string `mapstructure:"rc,omitempty"`
SkipOutput interface{} `mapstructure:"skip_output,omitempty"`
Output interface{} `mapstructure:"output,omitempty"`
Extends []string `mapstructure:"extends,omitempty"`
NoTTY bool `mapstructure:"no_tty,omitempty"`
AssertLefthookInstalled bool `mapstructure:"assert_lefthook_installed,omitempty"`
Expand Down
35 changes: 23 additions & 12 deletions internal/lefthook/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import (
)

const (
envEnabled = "LEFTHOOK" // "0", "false"
envSkipOutput = "LEFTHOOK_QUIET" // "meta,success,failure,summary,skips,execution,execution_out,execution_info"
envEnabled = "LEFTHOOK" // "0", "false"
envSkipOutput = "LEFTHOOK_QUIET" // "meta,success,failure,summary,skips,execution,execution_out,execution_info"
envOutput = "LEFTHOOK_OUTPUT" // "meta,success,failure,summary,skips,execution,execution_out,execution_info"
)

type RunArgs struct {
Expand Down Expand Up @@ -75,12 +76,22 @@ func (l *Lefthook) Run(hookName string, args RunArgs, gitArgs []string) error {
log.SetLevel(log.WarnLevel)
}

tags := os.Getenv(envSkipOutput)
outputLogTags := os.Getenv(envOutput)
outputSkipTags := os.Getenv(envSkipOutput)

var logSettings log.SkipSettings
(&logSettings).ApplySettings(tags, cfg.SkipOutput)
var logSettings log.Settings

if !logSettings.SkipMeta() {
if outputSkipTags == "" && cfg.SkipOutput == nil {
logSettings = log.NewSettings()
logSettings.ApplySettings(outputLogTags, cfg.Output)
} else {
log.Warn("skip_output is deprecated, please use output option")

logSettings = log.NewSkipSettings() //nolint:staticcheck //SA1019: for temporary backward compatibility
logSettings.ApplySettings(outputSkipTags, cfg.SkipOutput)
}

if logSettings.LogMeta() {
log.Box(
log.Cyan("🥊 lefthook ")+log.Gray(fmt.Sprintf("v%s", version.Version(false))),
log.Gray("hook: ")+log.Bold(hookName),
Expand Down Expand Up @@ -176,7 +187,7 @@ Run 'lefthook install' manually.`,
return errors.New("Interrupted")
}

if !logSettings.SkipSummary() {
if logSettings.LogSummary() {
printSummary(time.Since(startTime), results, logSettings)
}

Expand All @@ -192,16 +203,16 @@ Run 'lefthook install' manually.`,
func printSummary(
duration time.Duration,
results []run.Result,
logSettings log.SkipSettings,
logSettings log.Settings,
) {
summaryPrint := log.Separate

if logSettings.SkipExecution() || (logSettings.SkipExecutionInfo() && logSettings.SkipExecutionOutput()) {
if !logSettings.LogExecution() || !(logSettings.LogExecutionInfo() && logSettings.LogExecutionOutput()) {
summaryPrint = func(s string) { log.Info(s) }
}

if len(results) == 0 {
if !logSettings.SkipEmptySummary() {
if logSettings.LogEmptySummary() {
summaryPrint(
fmt.Sprintf(
"%s %s %s",
Expand All @@ -218,7 +229,7 @@ func printSummary(
log.Cyan("summary: ") + log.Gray(fmt.Sprintf("(done in %.2f seconds)", duration.Seconds())),
)

if !logSettings.SkipSuccess() {
if logSettings.LogSuccess() {
for _, result := range results {
if result.Status != run.StatusOk {
continue
Expand All @@ -228,7 +239,7 @@ func printSummary(
}
}

if !logSettings.SkipFailure() {
if logSettings.LogFailure() {
for _, result := range results {
if result.Status != run.StatusErr {
continue
Expand Down
18 changes: 9 additions & 9 deletions internal/lefthook/run/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type Options struct {
HookName string
GitArgs []string
ResultChan chan Result
SkipSettings log.SkipSettings
SkipSettings log.Settings
DisableTTY bool
Force bool
Files []string
Expand Down Expand Up @@ -426,14 +426,14 @@ func (r *Runner) run(ctx context.Context, opts exec.Options, follow bool) bool {
log.SetName(opts.Name)
defer log.UnsetName(opts.Name)

if (follow || opts.Interactive) && !r.SkipSettings.SkipExecution() {
if (follow || opts.Interactive) && r.SkipSettings.LogExecution() {
r.logExecute(opts.Name, nil, nil)

var out io.Writer
if r.SkipSettings.SkipExecutionOutput() {
out = io.Discard
} else {
if r.SkipSettings.LogExecutionOutput() {
out = os.Stdout
} else {
out = io.Discard
}

err := r.executor.Execute(ctx, opts, out)
Expand Down Expand Up @@ -478,7 +478,7 @@ func intersect(a, b []string) bool {
}

func (r *Runner) logSkip(name, reason string) {
if r.SkipSettings.SkipSkips() {
if !r.SkipSettings.LogSkips() {
return
}

Expand All @@ -493,14 +493,14 @@ func (r *Runner) logSkip(name, reason string) {
}

func (r *Runner) logExecute(name string, err error, out io.Reader) {
if err == nil && r.SkipSettings.SkipExecution() {
if err == nil && !r.SkipSettings.LogExecution() {
return
}

var execLog string
var color lipgloss.TerminalColor
switch {
case r.SkipSettings.SkipExecutionInfo():
case !r.SkipSettings.LogExecutionInfo():
execLog = ""
case err != nil:
execLog = log.Red(fmt.Sprintf("%s ❯ ", name))
Expand All @@ -518,7 +518,7 @@ func (r *Runner) logExecute(name string, err error, out io.Reader) {
log.Info()
}

if err == nil && r.SkipSettings.SkipExecutionOutput() {
if err == nil && !r.SkipSettings.LogExecutionOutput() {
return
}

Expand Down
14 changes: 8 additions & 6 deletions internal/lefthook/run/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/evilmartians/lefthook/internal/config"
"github.com/evilmartians/lefthook/internal/git"
"github.com/evilmartians/lefthook/internal/lefthook/run/exec"
"github.com/evilmartians/lefthook/internal/log"
)

type TestExecutor struct{}
Expand Down Expand Up @@ -749,12 +750,13 @@ func TestRunAll(t *testing.T) {
executor := TestExecutor{}
runner := &Runner{
Options: Options{
Repo: repo,
Hook: tt.hook,
HookName: tt.hookName,
GitArgs: tt.args,
ResultChan: resultChan,
Force: tt.force,
Repo: repo,
Hook: tt.hook,
HookName: tt.hookName,
SkipSettings: log.NewSettings(),
GitArgs: tt.args,
ResultChan: resultChan,
Force: tt.force,
},
executor: executor,
}
Expand Down
140 changes: 140 additions & 0 deletions internal/log/settings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package log

import (
"strings"
)

const (
meta = 1 << iota
success
failure
summary
skips
execution
executionOutput
executionInfo
emptySummary
enableAll = ^0 // Set all bits as 1
)

type Settings interface {
ApplySettings(tags string, skipOutput interface{})
LogSuccess() bool
LogFailure() bool
LogSummary() bool
LogMeta() bool
LogExecution() bool
LogExecutionOutput() bool
LogExecutionInfo() bool
LogSkips() bool
LogEmptySummary() bool
}

type OutputSettings int16

func NewSettings() Settings {
var s OutputSettings
return &s
}

func (s *OutputSettings) ApplySettings(tags string, output interface{}) {
if tags == "" && (output == nil || output == "") {
s.enableAll(true)
return
}

if val, ok := output.(bool); ok {
s.enableAll(val)
return
}

if options, ok := output.([]interface{}); ok {
if len(options) == 0 {
s.enableAll(true)
return
}
for _, option := range options {
if optStr, ok := option.(string); ok {
s.applySetting(optStr)
}
}
}

if tags != "" {
for _, tag := range strings.Split(tags, ",") {
s.applySetting(tag)
}
}
}

func (s *OutputSettings) applySetting(setting string) {
switch setting {
case "meta":
*s |= meta
case "success":
*s |= success
case "failure":
*s |= failure
case "summary":
*s |= summary
case "skips":
*s |= skips
case "execution":
*s |= execution
case "execution_out":
*s |= executionOutput
case "execution_info":
*s |= executionInfo
case "empty_summary":
*s |= emptySummary
}
}

func (s *OutputSettings) enableAll(val bool) {
if val {
*s = enableAll // Enable all params
} else {
*s |= failure // Disable all params
}
}

// Checks the state of params.
func (s OutputSettings) isEnable(option int16) bool {
return int16(s)&option != 0
}

func (s OutputSettings) LogSuccess() bool {
return s.isEnable(success)
}

func (s OutputSettings) LogFailure() bool {
return s.isEnable(failure)
}

func (s OutputSettings) LogSummary() bool {
return s.isEnable(summary)
}

func (s OutputSettings) LogMeta() bool {
return s.isEnable(meta)
}

func (s OutputSettings) LogExecution() bool {
return s.isEnable(execution)
}

func (s OutputSettings) LogExecutionOutput() bool {
return s.isEnable(executionOutput)
}

func (s OutputSettings) LogExecutionInfo() bool {
return s.isEnable(executionInfo)
}

func (s OutputSettings) LogSkips() bool {
return s.isEnable(skips)
}

func (s OutputSettings) LogEmptySummary() bool {
return s.isEnable(emptySummary)
}
Loading

0 comments on commit ce6c29b

Please sign in to comment.