Skip to content

Commit 802de54

Browse files
authored
feature: Skip unstaged changes for pre-commit hook (#402)
1 parent ed50a36 commit 802de54

21 files changed

+735
-296
lines changed

.golangci.yml

+47-33
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,50 @@ linters-settings:
99
linters:
1010
disable-all: true
1111
enable:
12-
- bodyclose
13-
- depguard
14-
- dogsled
15-
- dupl
16-
- errcheck
17-
- exhaustive
18-
- exportloopref
19-
- gci
20-
- goconst
21-
- gocyclo
22-
- gocyclo
23-
- godot
24-
- godox
25-
- gofmt
26-
- gofumpt
27-
- goimports
28-
- gomnd
29-
- goprintffuncname
30-
- gosimple
31-
- govet
32-
- ineffassign
33-
- misspell
34-
- nakedret
35-
- nestif
36-
- noctx
37-
- nolintlint
38-
- revive
39-
- staticcheck
40-
- typecheck
41-
- unconvert
42-
- unparam
43-
- unused
44-
- whitespace
12+
- asasalint
13+
- asciicheck
14+
- bidichk
15+
- bodyclose
16+
- containedctx
17+
- contextcheck
18+
- decorder
19+
- depguard
20+
- dogsled
21+
- dupl
22+
- dupword
23+
- durationcheck
24+
- errcheck
25+
- errchkjson
26+
- errname
27+
- errorlint
28+
- exhaustive
29+
- exportloopref
30+
- forbidigo
31+
- gci
32+
- gochecknoinits
33+
- goconst
34+
- gocritic
35+
- gocyclo
36+
- godot
37+
- godox
38+
- gofmt
39+
- gofumpt
40+
- goheader
41+
- goimports
42+
- gomnd
43+
- goprintffuncname
44+
- gosimple
45+
- govet
46+
- ineffassign
47+
- misspell
48+
- nakedret
49+
- nestif
50+
- noctx
51+
- nolintlint
52+
- revive
53+
- staticcheck
54+
- typecheck
55+
- unconvert
56+
- unparam
57+
- unused
58+
- whitespace

internal/config/available_hooks.go

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ var AvailableHooks = [...]string{
3939
"sendemail-validate",
4040
}
4141

42+
func HookUsesStagedFiles(hook string) bool {
43+
return hook == "pre-commit"
44+
}
45+
4246
func HookAvailable(hook string) bool {
4347
for _, name := range AvailableHooks {
4448
if name == hook {

internal/config/command.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func mergeCommands(base, extra *viper.Viper) (map[string]*Command, error) {
9696

9797
for key, replace := range runReplaces {
9898
if replace.Run != "" {
99-
commands[key].Run = strings.Replace(commands[key].Run, CMD, replace.Run, -1)
99+
commands[key].Run = strings.ReplaceAll(commands[key].Run, CMD, replace.Run)
100100
}
101101
}
102102

internal/config/load.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config
22

33
import (
4+
"errors"
45
"fmt"
56
"path/filepath"
67
"regexp"
@@ -82,7 +83,8 @@ func mergeAll(fs afero.Fs, repo *git.Repository) (*viper.Viper, error) {
8283
}
8384

8485
if err := merge("lefthook-local", "", extends); err != nil {
85-
if _, notFoundErr := err.(viper.ConfigFileNotFoundError); !notFoundErr {
86+
var notFoundErr viper.ConfigFileNotFoundError
87+
if ok := errors.As(err, &notFoundErr); !ok {
8688
return nil, err
8789
}
8890
}

internal/config/load_test.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,9 @@ pre-push:
416416

417417
if err != nil {
418418
t.Errorf("should parse configs without errors: %s", err)
419-
} else {
420-
if !cmp.Equal(checkConfig, tt.result, cmpopts.IgnoreUnexported(Hook{})) {
421-
t.Errorf("configs should be equal")
422-
t.Errorf("(-want +got):\n%s", cmp.Diff(tt.result, checkConfig))
423-
}
419+
} else if !cmp.Equal(checkConfig, tt.result, cmpopts.IgnoreUnexported(Hook{})) {
420+
t.Errorf("configs should be equal")
421+
t.Errorf("(-want +got):\n%s", cmp.Diff(tt.result, checkConfig))
424422
}
425423
})
426424
}

internal/config/script.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func mergeScripts(base, extra *viper.Viper) (map[string]*Script, error) {
7878

7979
for key, replace := range runReplaces {
8080
if replace.Runner != "" {
81-
scripts[key].Runner = strings.Replace(scripts[key].Runner, CMD, replace.Runner, -1)
81+
scripts[key].Runner = strings.ReplaceAll(scripts[key].Runner, CMD, replace.Runner)
8282
}
8383
}
8484

internal/git/exec.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package git
2+
3+
import (
4+
"os"
5+
"os/exec"
6+
"strings"
7+
)
8+
9+
type Exec interface {
10+
Cmd(cmd string) (string, error)
11+
CmdArgs(args ...string) (string, error)
12+
CmdLines(cmd string) ([]string, error)
13+
RawCmd(cmd string) (string, error)
14+
}
15+
16+
type OsExec struct{}
17+
18+
// NewOsExec returns an object that executes given commands
19+
// in the OS.
20+
func NewOsExec() *OsExec {
21+
return &OsExec{}
22+
}
23+
24+
// Cmd runs plain string command. Trims spaces around output.
25+
func (o *OsExec) Cmd(cmd string) (string, error) {
26+
args := strings.Split(cmd, " ")
27+
return o.CmdArgs(args...)
28+
}
29+
30+
// CmdLines runs plain string command, returns its output split by newline.
31+
func (o *OsExec) CmdLines(cmd string) ([]string, error) {
32+
out, err := o.RawCmd(cmd)
33+
if err != nil {
34+
return nil, err
35+
}
36+
37+
return strings.Split(out, "\n"), nil
38+
}
39+
40+
// CmdArgs runs a command provided with separted words. Trims spaces around output.
41+
func (o *OsExec) CmdArgs(args ...string) (string, error) {
42+
out, err := o.rawExecArgs(args...)
43+
if err != nil {
44+
return "", err
45+
}
46+
47+
return strings.TrimSpace(out), nil
48+
}
49+
50+
// RawCmd runs a plain string command returning unprocessed output as string.
51+
func (o *OsExec) RawCmd(cmd string) (string, error) {
52+
args := strings.Split(cmd, " ")
53+
return o.rawExecArgs(args...)
54+
}
55+
56+
// rawExecArgs executes git command with LEFTHOOK=0 in order
57+
// to prevent calling subsequent lefthook hooks.
58+
func (o *OsExec) rawExecArgs(args ...string) (string, error) {
59+
cmd := exec.Command(args[0], args[1:]...)
60+
cmd.Env = append(os.Environ(), "LEFTHOOK=0")
61+
62+
out, err := cmd.CombinedOutput()
63+
if err != nil {
64+
return "", err
65+
}
66+
67+
return string(out), nil
68+
}

internal/git/remote.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,22 @@ func (r *Repository) updateRemote(path, ref string) error {
6868
log.Debugf("Updating remote config repository: %s", path)
6969

7070
if len(ref) != 0 {
71-
cmdFetch := []string{"git", "-C", path, "fetch", "--quiet", "--depth", "1", "origin", ref}
72-
_, err := execGit(strings.Join(cmdFetch, " "))
71+
_, err := r.Git.CmdArgs(
72+
"git", "-C", path, "fetch", "--quiet", "--depth", "1",
73+
"origin", ref,
74+
)
7375
if err != nil {
7476
return err
7577
}
7678

77-
cmdFetch = []string{"git", "-C", path, "checkout", "FETCH_HEAD"}
78-
_, err = execGit(strings.Join(cmdFetch, " "))
79+
_, err = r.Git.CmdArgs(
80+
"git", "-C", path, "checkout", "FETCH_HEAD",
81+
)
7982
if err != nil {
8083
return err
8184
}
8285
} else {
83-
cmdFetch := []string{"git", "-C", path, "pull", "--quiet"}
84-
_, err := execGit(strings.Join(cmdFetch, " "))
86+
_, err := r.Git.CmdArgs("git", "-C", path, "pull", "--quiet")
8587
if err != nil {
8688
return err
8789
}
@@ -99,7 +101,7 @@ func (r *Repository) cloneRemote(path, url, ref string) error {
99101
}
100102
cmdClone = append(cmdClone, url)
101103

102-
_, err := execGit(strings.Join(cmdClone, " "))
104+
_, err := r.Git.CmdArgs(cmdClone...)
103105
if err != nil {
104106
return err
105107
}

0 commit comments

Comments
 (0)