Skip to content

Commit

Permalink
Merge branch 'master' into chore/more-linting
Browse files Browse the repository at this point in the history
  • Loading branch information
mrexox authored Mar 13, 2024
2 parents 2d5d587 + 96a206e commit 7245a72
Show file tree
Hide file tree
Showing 28 changed files with 788 additions and 177 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
strategy:
matrix:
go-version: [1.21.x]
os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
GOCOVERDIR: ${{ github.workspace }}/_icoverdir_
Expand Down Expand Up @@ -91,5 +91,5 @@ jobs:
steps:
- uses: coverallsapp/github-action@v2
with:
carryforward: "integration-1.21.x ubuntu-latest,integration-1.21.x macos-latest,1.21.x ubuntu-latest,1.21.x macos-latest,1.21.x windows-latest"
carryforward: "integration-1.21.x ubuntu-latest,integration-1.21.x macos-latest,integration-1.21.x windows-latest,1.21.x ubuntu-latest,1.21.x macos-latest,1.21.x windows-latest"
parallel-finished: true
53 changes: 53 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 Expand Up @@ -884,6 +922,21 @@ pre-commit:
run: yarn test
```

Skipping hook by running a command:

```yml
# lefthook.yml
pre-commit:
skip:
- run: test "${NO_HOOK}" -eq 1
commands:
lint:
run: yarn lint
text:
run: yarn test
```

**Notes**

Always skipping is useful when you have a `lefthook-local.yml` config and you don't want to run some commands locally. So you just overwrite the `skip` option for them to be `true`.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.21
require (
github.com/MakeNowJust/heredoc v1.0.0
github.com/briandowns/spinner v1.23.0
github.com/charmbracelet/lipgloss v0.9.1
github.com/charmbracelet/lipgloss v0.10.0
github.com/creack/pty v1.1.21
github.com/gobwas/glob v0.2.3
github.com/google/go-cmp v0.5.9
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A=
github.com/briandowns/spinner v1.23.0/go.mod h1:rPG4gmXeN3wQV/TsAY4w8lPdIM6RX3yqeBQJSrbXjuE=
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
Expand Down
3 changes: 2 additions & 1 deletion internal/config/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ func (c Command) Validate() error {
}

func (c Command) DoSkip(gitState git.State) bool {
return doSkip(gitState, c.Skip, c.Only)
skipChecker := NewSkipChecker(NewOsExec())
return skipChecker.Check(gitState, c.Skip, c.Only)
}

type commandRunReplace struct {
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: 35 additions & 0 deletions internal/config/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package config

import (
"os/exec"
"runtime"
)

type Exec interface {
Cmd(commandLine string) bool
}

type osExec struct{}

// NewOsExec returns an object that executes given commands in the OS.
func NewOsExec() Exec {
return &osExec{}
}

// Cmd runs plain string command. It checks only exit code and returns bool value.
func (o *osExec) Cmd(commandLine string) bool {
if commandLine == "" {
return false
}

var cmd *exec.Cmd
if runtime.GOOS == "windows" {
cmd = exec.Command("powershell", "-Command", commandLine)
} else {
cmd = exec.Command("sh", "-c", commandLine)
}

err := cmd.Run()

return err == nil
}
3 changes: 2 additions & 1 deletion internal/config/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ func (h *Hook) Validate() error {
}

func (h *Hook) DoSkip(gitState git.State) bool {
return doSkip(gitState, h.Skip, h.Only)
skipChecker := NewSkipChecker(NewOsExec())
return skipChecker.Check(gitState, h.Skip, h.Only)
}

func unmarshalHooks(base, extra *viper.Viper) (*Hook, error) {
Expand Down
3 changes: 2 additions & 1 deletion internal/config/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ type Script struct {
}

func (s Script) DoSkip(gitState git.State) bool {
return doSkip(gitState, s.Skip, s.Only)
skipChecker := NewSkipChecker(NewOsExec())
return skipChecker.Check(gitState, s.Skip, s.Only)
}

type scriptRunnerReplace struct {
Expand Down
50 changes: 0 additions & 50 deletions internal/config/skip.go

This file was deleted.

95 changes: 95 additions & 0 deletions internal/config/skip_checker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package config

import (
"github.com/gobwas/glob"

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

type SkipChecker struct {
Executor Exec
}

func NewSkipChecker(executor Exec) *SkipChecker {
if executor == nil {
executor = NewOsExec()
}

return &SkipChecker{Executor: executor}
}

func (sc *SkipChecker) Check(gitState git.State, skip interface{}, only interface{}) bool {
if skip != nil {
if sc.matches(gitState, skip) {
return true
}
}

if only != nil {
return !sc.matches(gitState, only)
}

return false
}

func (sc *SkipChecker) matches(gitState git.State, value interface{}) bool {
switch typedValue := value.(type) {
case bool:
return typedValue
case string:
return typedValue == gitState.Step
case []interface{}:
return sc.matchesSlices(gitState, typedValue)
}
return false
}

func (sc *SkipChecker) matchesSlices(gitState git.State, slice []interface{}) bool {
for _, state := range slice {
switch typedState := state.(type) {
case string:
if typedState == gitState.Step {
return true
}
case map[string]interface{}:
if sc.matchesRef(gitState, typedState) {
return true
}

if sc.matchesCommands(typedState) {
return true
}
}
}

return false
}

func (sc *SkipChecker) matchesRef(gitState git.State, typedState map[string]interface{}) bool {
ref, ok := typedState["ref"].(string)
if !ok {
return false
}

if ref == gitState.Branch {
return true
}

g := glob.MustCompile(ref)

return g.Match(gitState.Branch)
}

func (sc *SkipChecker) matchesCommands(typedState map[string]interface{}) bool {
commandLine, ok := typedState["run"].(string)
if !ok {
return false
}

result := sc.Executor.Cmd(commandLine)

log.Debugf("[lefthook] skip/only cmd: %s, result: %t", commandLine, result)

return result
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ import (
"github.com/evilmartians/lefthook/internal/git"
)

type mockExecutor struct{}

func (mc mockExecutor) Cmd(cmd string) bool {
return cmd == "success"
}

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

for _, tt := range [...]struct {
name string
state git.State
Expand Down Expand Up @@ -111,9 +119,27 @@ func TestDoSkip(t *testing.T) {
only: "rebase",
skipped: true,
},
{
name: "when skip with run command",
state: git.State{},
skip: []interface{}{map[string]interface{}{"run": "success"}},
skipped: true,
},
{
name: "when skip with multi-run command",
state: git.State{Branch: "feat"},
skip: []interface{}{map[string]interface{}{"run": "success", "ref": "feat"}},
skipped: true,
},
{
name: "when only with run command",
state: git.State{},
only: []interface{}{map[string]interface{}{"run": "fail"}},
skipped: true,
},
} {
t.Run(tt.name, func(t *testing.T) {
if doSkip(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
Loading

0 comments on commit 7245a72

Please sign in to comment.