Skip to content

Commit

Permalink
feature: Skip unstaged changes for pre-commit hook (#402)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrexox authored Feb 22, 2023
1 parent ed50a36 commit 802de54
Show file tree
Hide file tree
Showing 21 changed files with 735 additions and 296 deletions.
80 changes: 47 additions & 33 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,50 @@ linters-settings:
linters:
disable-all: true
enable:
- bodyclose
- depguard
- dogsled
- dupl
- errcheck
- exhaustive
- exportloopref
- gci
- goconst
- gocyclo
- gocyclo
- godot
- godox
- gofmt
- gofumpt
- goimports
- gomnd
- goprintffuncname
- gosimple
- govet
- ineffassign
- misspell
- nakedret
- nestif
- noctx
- nolintlint
- revive
- staticcheck
- typecheck
- unconvert
- unparam
- unused
- whitespace
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- contextcheck
- decorder
- depguard
- dogsled
- dupl
- dupword
- durationcheck
- errcheck
- errchkjson
- errname
- errorlint
- exhaustive
- exportloopref
- forbidigo
- gci
- gochecknoinits
- goconst
- gocritic
- gocyclo
- godot
- godox
- gofmt
- gofumpt
- goheader
- goimports
- gomnd
- goprintffuncname
- gosimple
- govet
- ineffassign
- misspell
- nakedret
- nestif
- noctx
- nolintlint
- revive
- staticcheck
- typecheck
- unconvert
- unparam
- unused
- whitespace
4 changes: 4 additions & 0 deletions internal/config/available_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ var AvailableHooks = [...]string{
"sendemail-validate",
}

func HookUsesStagedFiles(hook string) bool {
return hook == "pre-commit"
}

func HookAvailable(hook string) bool {
for _, name := range AvailableHooks {
if name == hook {
Expand Down
2 changes: 1 addition & 1 deletion internal/config/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func mergeCommands(base, extra *viper.Viper) (map[string]*Command, error) {

for key, replace := range runReplaces {
if replace.Run != "" {
commands[key].Run = strings.Replace(commands[key].Run, CMD, replace.Run, -1)
commands[key].Run = strings.ReplaceAll(commands[key].Run, CMD, replace.Run)
}
}

Expand Down
4 changes: 3 additions & 1 deletion internal/config/load.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"errors"
"fmt"
"path/filepath"
"regexp"
Expand Down Expand Up @@ -82,7 +83,8 @@ func mergeAll(fs afero.Fs, repo *git.Repository) (*viper.Viper, error) {
}

if err := merge("lefthook-local", "", extends); err != nil {
if _, notFoundErr := err.(viper.ConfigFileNotFoundError); !notFoundErr {
var notFoundErr viper.ConfigFileNotFoundError
if ok := errors.As(err, &notFoundErr); !ok {
return nil, err
}
}
Expand Down
8 changes: 3 additions & 5 deletions internal/config/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,11 +416,9 @@ pre-push:

if err != nil {
t.Errorf("should parse configs without errors: %s", err)
} else {
if !cmp.Equal(checkConfig, tt.result, cmpopts.IgnoreUnexported(Hook{})) {
t.Errorf("configs should be equal")
t.Errorf("(-want +got):\n%s", cmp.Diff(tt.result, checkConfig))
}
} else if !cmp.Equal(checkConfig, tt.result, cmpopts.IgnoreUnexported(Hook{})) {
t.Errorf("configs should be equal")
t.Errorf("(-want +got):\n%s", cmp.Diff(tt.result, checkConfig))
}
})
}
Expand Down
2 changes: 1 addition & 1 deletion internal/config/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func mergeScripts(base, extra *viper.Viper) (map[string]*Script, error) {

for key, replace := range runReplaces {
if replace.Runner != "" {
scripts[key].Runner = strings.Replace(scripts[key].Runner, CMD, replace.Runner, -1)
scripts[key].Runner = strings.ReplaceAll(scripts[key].Runner, CMD, replace.Runner)
}
}

Expand Down
68 changes: 68 additions & 0 deletions internal/git/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package git

import (
"os"
"os/exec"
"strings"
)

type Exec interface {
Cmd(cmd string) (string, error)
CmdArgs(args ...string) (string, error)
CmdLines(cmd string) ([]string, error)
RawCmd(cmd string) (string, error)
}

type OsExec struct{}

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

// Cmd runs plain string command. Trims spaces around output.
func (o *OsExec) Cmd(cmd string) (string, error) {
args := strings.Split(cmd, " ")
return o.CmdArgs(args...)
}

// CmdLines runs plain string command, returns its output split by newline.
func (o *OsExec) CmdLines(cmd string) ([]string, error) {
out, err := o.RawCmd(cmd)
if err != nil {
return nil, err
}

return strings.Split(out, "\n"), nil
}

// CmdArgs runs a command provided with separted words. Trims spaces around output.
func (o *OsExec) CmdArgs(args ...string) (string, error) {
out, err := o.rawExecArgs(args...)
if err != nil {
return "", err
}

return strings.TrimSpace(out), nil
}

// RawCmd runs a plain string command returning unprocessed output as string.
func (o *OsExec) RawCmd(cmd string) (string, error) {
args := strings.Split(cmd, " ")
return o.rawExecArgs(args...)
}

// rawExecArgs executes git command with LEFTHOOK=0 in order
// to prevent calling subsequent lefthook hooks.
func (o *OsExec) rawExecArgs(args ...string) (string, error) {
cmd := exec.Command(args[0], args[1:]...)
cmd.Env = append(os.Environ(), "LEFTHOOK=0")

out, err := cmd.CombinedOutput()
if err != nil {
return "", err
}

return string(out), nil
}
16 changes: 9 additions & 7 deletions internal/git/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,22 @@ func (r *Repository) updateRemote(path, ref string) error {
log.Debugf("Updating remote config repository: %s", path)

if len(ref) != 0 {
cmdFetch := []string{"git", "-C", path, "fetch", "--quiet", "--depth", "1", "origin", ref}
_, err := execGit(strings.Join(cmdFetch, " "))
_, err := r.Git.CmdArgs(
"git", "-C", path, "fetch", "--quiet", "--depth", "1",
"origin", ref,
)
if err != nil {
return err
}

cmdFetch = []string{"git", "-C", path, "checkout", "FETCH_HEAD"}
_, err = execGit(strings.Join(cmdFetch, " "))
_, err = r.Git.CmdArgs(
"git", "-C", path, "checkout", "FETCH_HEAD",
)
if err != nil {
return err
}
} else {
cmdFetch := []string{"git", "-C", path, "pull", "--quiet"}
_, err := execGit(strings.Join(cmdFetch, " "))
_, err := r.Git.CmdArgs("git", "-C", path, "pull", "--quiet")
if err != nil {
return err
}
Expand All @@ -99,7 +101,7 @@ func (r *Repository) cloneRemote(path, url, ref string) error {
}
cmdClone = append(cmdClone, url)

_, err := execGit(strings.Join(cmdClone, " "))
_, err := r.Git.CmdArgs(cmdClone...)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 802de54

Please sign in to comment.