Skip to content

Commit

Permalink
[skip travis]add config runners
Browse files Browse the repository at this point in the history
  • Loading branch information
A.A.Abroskin committed Feb 19, 2019
1 parent 82d21ed commit 187e049
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 36 deletions.
60 changes: 58 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,57 @@ git commit -am "It fail"

Done! Pretty simple, huh?

### Complete example
`hookah.yml`
```yml
source_dir: ".hookah"
source_dir_local: ".hookah-local"

pre-commit:
# Specify additional parameters for script files
scripts:
"hello.js":
runner: node
"any.go":
runner: go run

# Describe what files will be placed in runner command
# Default: git_staged
# Available: all, git_staged, none
files: git_staged

# If nothing was found - skip command
# Default: true
skip_empty: true

commands:
eslint:
include: ".js|.ts"
exclude: ".css"
runner: yarn eslint {files} # {files} will be replaced by matched files as arguments
rubocop:
include: ".rb"
exclude: "spec"
runner: bundle exec rubocop {files}
audit:
runner: bundle audit
skip_empty: false
```
If your team have backend and frontend developers, you can skip unnsecesary hooks this way:
`hookah-local.yml`
```yml
pre-commit:
# I am fronted developer. Skip all this backend stuff!
scripts:
"any.go":
skip: true
commands:
rubocop:
skip: true
audit:
skip: true
```

### I want to run hook groups directly!

No problem, hookah have command for that:
Expand All @@ -119,8 +170,7 @@ Next customize the `any.go` script:
```yaml
pre-commit:
"any.go":
runner: "go"
runner_args: "run"
runner: "go run"
```

Done! Now our script will be executed like this:
Expand Down Expand Up @@ -179,3 +229,9 @@ func main() {
}
```
We include context package only for convenience. It`s just few useful functions.

### Uninstall

```bash
hookah uninstall
```
214 changes: 181 additions & 33 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package cmd

import (
"errors"
"hookah/context"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"

"github.com/logrusorgru/aurora"
Expand All @@ -25,6 +27,14 @@ var (
const (
runnerConfigKey string = "runner"
runnerArgsConfigKey string = "runner_args"
scriptsConfigKey string = "scripts"
commandsConfigKey string = "commands"
includeConfigKey string = "include"
excludeConfigKey string = "exclude"
skipConfigKey string = "skip"
skipEmptyConfigKey string = "skip_empty"
filesConfigKey string = "files"
subFiles string = "{files}"
)

// runCmd represents the run command
Expand Down Expand Up @@ -55,29 +65,30 @@ func RunCmdExecutor(args []string, fs afero.Fs) error {

sourcePath := filepath.Join(getSourceDir(), getHooksGroup())
executables, err := afero.ReadDir(fs, sourcePath)
check(err)

if len(executables) == 0 {
log.Println(aurora.Cyan("RUNNING HOOKS GROUP:"), aurora.Bold(getHooksGroup()), aurora.Brown("(SKIP EMPTY)"))
} else {
if err == nil && len(executables) > 0 {
log.Println(aurora.Cyan("RUNNING HOOKS GROUP:"), aurora.Bold(getHooksGroup()))
}

for _, executable := range executables {
execute(sourcePath, executable)
for _, executable := range executables {
executeScript(sourcePath, executable)
}
}

sourcePath = filepath.Join(getLocalSourceDir(), getHooksGroup())
executables, err = afero.ReadDir(fs, sourcePath)
if err == nil {
if len(executables) == 0 {
log.Println(aurora.Cyan("RUNNING LOCAL HOOKS GROUP:"), aurora.Bold(getHooksGroup()), aurora.Brown("(SKIP EMPTY)"))
} else {
log.Println(aurora.Cyan("RUNNING LOCAL HOOKS GROUP:"), aurora.Bold(getHooksGroup()))
}
if err == nil && len(executables) > 0 {
log.Println(aurora.Cyan("RUNNING LOCAL HOOKS GROUP:"), aurora.Bold(getHooksGroup()))

for _, executable := range executables {
execute(sourcePath, executable)
executeScript(sourcePath, executable)
}
}

commands := getCommands()
if len(commands) != 0 {
log.Println(aurora.Cyan("RUNNING COMMANDS HOOKS GROUP:"), aurora.Bold(getHooksGroup()))

for commandName := range commands {
executeCommand(commandName)
}
}

Expand All @@ -89,51 +100,107 @@ func RunCmdExecutor(args []string, fs afero.Fs) error {
return errors.New("Have failed script")
}

func execute(source string, executable os.FileInfo) {
func executeCommand(commandName string) {
setExecutableName(commandName)

var files []string
switch getCommandFiles() {
case "git_staged":
files, _ = context.StagedFiles()
case "all":
files, _ = context.AllFiles()
case "none":
files = []string{}
default:
files = []string{}
}
files = FilterInclude(files, getCommandIncludeRegexp())
files = FilterExclude(files, getCommandExcludeRegexp())

runner := strings.Replace(getRunner(commandsConfigKey), subFiles, strings.Join(files, " "), -1)
runnerArg := strings.Split(runner, " ")

command := exec.Command(runnerArg[0], runnerArg[1:]...)

command.Stdout = os.Stdout
command.Stderr = os.Stderr
command.Stdin = os.Stdin

log.Println(aurora.Cyan(" EXECUTE >"), aurora.Bold(getExecutableName()))

if isSkipCommmand() {
log.Println(aurora.Brown("(SKIP BY SETTINGS)"))
return
}
if len(files) < 1 && isSkipEmptyCommmand() {
log.Println(aurora.Brown("(SKIP. NO FILES FOR INSPECTING)"))
return
}

err := command.Start()
if err != nil {
log.Println(err)
}

err = command.Wait()
if err == nil {
okList = append(okList, getExecutableName())
} else {
failList = append(failList, getExecutableName())
}
}

func executeScript(source string, executable os.FileInfo) {
setExecutableName(executable.Name())

log.Println(aurora.Cyan(" EXECUTE >"), aurora.Bold(getExecutableName()))

if isSkipScript() {
log.Println(aurora.Brown("(SKIP BY SETTINGS)"))
return
}

pathToExecutable := filepath.Join(source, getExecutableName())

command := exec.Command(pathToExecutable)

if haveRunner() {
command = exec.Command(
getRunner(),
getRunnerArgs(),
pathToExecutable,
)
if haveRunner(scriptsConfigKey) {
runnerArg := strings.Split(getRunner(scriptsConfigKey), " ")
runnerArg = append(runnerArg, pathToExecutable)

command = exec.Command(runnerArg[0], runnerArg[1:]...)
}

command.Stdout = os.Stdout
command.Stderr = os.Stderr
command.Stdin = os.Stdin

command.Start()
err := command.Start()
if os.IsPermission(err) {
log.Println(aurora.Brown("(SKIP NOT EXECUTABLE FILE)"))
return
}
if err != nil {
log.Println(err)
}

err := command.Wait()
err = command.Wait()
if err == nil {
okList = append(okList, getExecutableName())
} else {
failList = append(failList, getExecutableName())
}
}

func haveRunner() (out bool) {
if runner := getRunner(); runner != "" {
func haveRunner(source string) (out bool) {
if runner := getRunner(source); runner != "" {
out = true
}
return
}

func getRunner() string {
key := strings.Join([]string{getHooksGroup(), getExecutableName(), runnerConfigKey}, ".")
return viper.GetString(key)
}

func getRunnerArgs() string {
key := strings.Join([]string{getHooksGroup(), getExecutableName(), runnerArgsConfigKey}, ".")
func getRunner(source string) string {
key := strings.Join([]string{getHooksGroup(), source, getExecutableName(), runnerConfigKey}, ".")
return viper.GetString(key)
}

Expand Down Expand Up @@ -168,3 +235,84 @@ func printSummary() {
log.Printf("[ %s ] %s\n", aurora.Red("FAIL"), fileName)
}
}

func isSkipScript() bool {
key := strings.Join([]string{getHooksGroup(), scriptsConfigKey, getExecutableName(), skipConfigKey}, ".")
return viper.GetBool(key)
}

func isSkipCommmand() bool {
key := strings.Join([]string{getHooksGroup(), commandsConfigKey, getExecutableName(), skipConfigKey}, ".")
return viper.GetBool(key)
}

func isSkipEmptyCommmand() bool {
key := strings.Join([]string{getHooksGroup(), commandsConfigKey, getExecutableName(), skipEmptyConfigKey}, ".")
if viper.IsSet(key) {
return viper.GetBool(key)
}

key = strings.Join([]string{getHooksGroup(), skipEmptyConfigKey}, ".")
if viper.IsSet(key) {
return viper.GetBool(key)
}

return true
}

func getCommands() map[string]interface{} {
key := strings.Join([]string{getHooksGroup(), commandsConfigKey}, ".")
return viper.GetStringMap(key)
}

func getCommandIncludeRegexp() string {
key := strings.Join([]string{getHooksGroup(), commandsConfigKey, getExecutableName(), includeConfigKey}, ".")
return viper.GetString(key)
}

func getCommandExcludeRegexp() string {
key := strings.Join([]string{getHooksGroup(), commandsConfigKey, getExecutableName(), excludeConfigKey}, ".")
return viper.GetString(key)
}

func getCommandFiles() string {
key := strings.Join([]string{getHooksGroup(), commandsConfigKey, getExecutableName(), filesConfigKey}, ".")
if viper.GetString(key) != "" {
return viper.GetString(key)
}

key = strings.Join([]string{getHooksGroup(), filesConfigKey}, ".")
if viper.GetString(key) != "" {
return viper.GetString(key)
}

return "git_staged"
}

func FilterInclude(vs []string, matcher string) []string {
if matcher == "" {
return vs
}

vsf := make([]string, 0)
for _, v := range vs {
if res, _ := regexp.MatchString(matcher, v); res {
vsf = append(vsf, v)
}
}
return vsf
}

func FilterExclude(vs []string, matcher string) []string {
if matcher == "" {
return vs
}

vsf := make([]string, 0)
for _, v := range vs {
if res, _ := regexp.MatchString(matcher, v); !res {
vsf = append(vsf, v)
}
}
return vsf
}
Loading

0 comments on commit 187e049

Please sign in to comment.