Skip to content

Commit

Permalink
feat: support json configs (#489)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrexox authored May 22, 2023
1 parent 6bba269 commit 2453910
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 13 deletions.
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ linters:
- govet
- ineffassign
- misspell
- nakedret
- nestif
- noctx
- nolintlint
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## master (unreleased)

- feat: support json configs ([#489](https://github.com/evilmartians/lefthook/pull/489)) by @mrexox

## 1.4.1 (2024-05-22)

- fix: add win32 binary to artifacts (by @mrexox)
Expand Down
75 changes: 75 additions & 0 deletions internal/config/load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,4 +466,79 @@ pre-push:
}
})
}

for i, tt := range [...]struct {
name string
yaml, json string
result *Config
}{
{
name: "simple configs",
yaml: `
pre-commit:
commands:
echo:
run: echo 1
`,
json: `
{
"pre-commit": {
"commands": {
"echo": { "run": "echo 1" }
}
}
}`,
result: &Config{
SourceDir: DefaultSourceDir,
SourceDirLocal: DefaultSourceDirLocal,
Hooks: map[string]*Hook{
"pre-commit": {
Commands: map[string]*Command{
"echo": {
Run: "echo 1",
},
},
},
},
},
},
} {
fs := afero.Afero{Fs: afero.NewMemMapFs()}
repo := &git.Repository{
Fs: fs,
RootPath: root,
InfoPath: filepath.Join(root, ".git", "info"),
}

t.Run(fmt.Sprintf("%d: %s", i, tt.name), func(t *testing.T) {
yamlConfig := filepath.Join(root, "lefthook.yml")
if err := fs.WriteFile(yamlConfig, []byte(tt.yaml), 0o644); err != nil {
t.Errorf("unexpected error: %s", err)
}

checkConfig, err := Load(fs.Fs, repo)
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))
}

if err = fs.Remove(yamlConfig); err != nil {
t.Errorf("unexpected error: %s", err)
}

if err = fs.WriteFile(filepath.Join(root, "lefthook.json"), []byte(tt.json), 0o644); err != nil {
t.Errorf("unexpected error: %s", err)
}

checkConfig, err = Load(fs.Fs, repo)
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))
}
})
}
}
48 changes: 36 additions & 12 deletions internal/lefthook/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import (
"bufio"
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"

"github.com/gobwas/glob"
"github.com/spf13/afero"

"github.com/evilmartians/lefthook/internal/config"
Expand All @@ -21,12 +24,15 @@ const (
configFileMode = 0o666
checksumFileMode = 0o644
hooksDirMode = 0o755
configGlob = "lefthook.y*ml"
timestampBase = 10
timestampBitsize = 64
)

var lefthookChecksumRegexp = regexp.MustCompile(`(\w+)\s+(\d+)`)
var (
lefthookChecksumRegexp = regexp.MustCompile(`(\w+)\s+(\d+)`)
configGlob = glob.MustCompile("lefthook.{json,yaml,yml}")
errNoConfig = fmt.Errorf("no lefthook config found")
)

type InstallArgs struct {
Force, Aggressive bool
Expand Down Expand Up @@ -69,7 +75,6 @@ func (l *Lefthook) readOrCreateConfig() (*config.Config, error) {

if !l.configExists(l.repo.RootPath) {
log.Info("Config not found, creating...")

if err := l.createConfig(l.repo.RootPath); err != nil {
return nil, err
}
Expand All @@ -79,13 +84,13 @@ func (l *Lefthook) readOrCreateConfig() (*config.Config, error) {
}

func (l *Lefthook) configExists(path string) bool {
paths, err := afero.Glob(l.Fs, filepath.Join(path, configGlob))
paths, err := afero.ReadDir(l.Fs, path)
if err != nil {
return false
}

for _, config := range paths {
if ok, _ := afero.Exists(l.Fs, config); ok {
for _, file := range paths {
if ok := configGlob.Match(file.Name()); ok {
return true
}
}
Expand Down Expand Up @@ -199,27 +204,46 @@ func (l *Lefthook) hooksSynchronized() bool {
}

func (l *Lefthook) configLastUpdateTimestamp() (timestamp int64, err error) {
m, err := afero.Glob(l.Fs, filepath.Join(l.repo.RootPath, configGlob))
paths, err := afero.ReadDir(l.Fs, l.repo.RootPath)
if err != nil {
return
}
var config os.FileInfo
for _, file := range paths {
if ok := configGlob.Match(file.Name()); ok {
config = file
break
}
}

info, err := l.Fs.Stat(m[0])
if err != nil {
if config == nil {
err = errNoConfig
return
}

timestamp = info.ModTime().Unix()
timestamp = config.ModTime().Unix()
return
}

func (l *Lefthook) configChecksum() (checksum string, err error) {
m, err := afero.Glob(l.Fs, filepath.Join(l.repo.RootPath, configGlob))
paths, err := afero.ReadDir(l.Fs, l.repo.RootPath)
if err != nil {
return
}

file, err := l.Fs.Open(m[0])
var config string
for _, file := range paths {
if ok := configGlob.Match(file.Name()); ok {
config = file.Name()
break
}
}
if len(config) == 0 {
err = errNoConfig
return
}

file, err := l.Fs.Open(filepath.Join(l.repo.RootPath, config))
if err != nil {
return
}
Expand Down

0 comments on commit 2453910

Please sign in to comment.