Skip to content

Commit

Permalink
Merge pull request #20 from devops-kung-fu/2.0.1-wip
Browse files Browse the repository at this point in the history
feat: 2.0.1
  • Loading branch information
djschleen committed Apr 5, 2021
2 parents d825126 + 26710c5 commit bc7e94f
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 59 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@

hookz
.vscode/
coverage.out
coverage.out
.gitorade
6 changes: 0 additions & 6 deletions .gitorade

This file was deleted.

15 changes: 12 additions & 3 deletions .hookz.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
version: 2.0
version: 2.1.1
hooks:
- type: pre-commit
actions:
- name: "Git Pull (Ensure there are no upstream changes that are not local)"
exec: git
args: ["pull"]
- name: "Go Tidy"
- name: "Go Tidy (Recursive)"
script: "
#!/bin/bash \n
echo -e Tidying all found go.mod occurrences\n
find . -name go.mod -print0 | xargs -0 -n1 dirname | xargs -L 1 bash -c 'cd \"$0\" && pwd && go mod tidy' \n
"
- name: "Go Build (Ensure pulled modules do not break the build)"
exec: go
args: ["mod", "tidy"]
args: ["build"]
- name: "Update all go dependencies to latest"
exec: go
args: ["get", "-u", "./..."]
- name: "Run gofmt to format the code"
exec: gofmt
args: ["-s", "-w", "**/*.go"]
- name: "Add all changed files during the pre-commit stage"
exec: git
args: ["add", "."]
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@ build: ## Builds the application
test: ## Runs tests and coverage
go test -v -coverprofile=coverage.out ./... && go tool cover -func=coverage.out

install: build ## Builds an executable local version of Hookz and puts in in /usr/local/bin
sudo chmod +x hookz
sudo mv hookz /usr/local/bin

all: title build test ## Makes all targets

76 changes: 63 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# hookz

[![Go Report Card](https://goreportcard.com/badge/github.com/devops-kung-fu/hookz)](https://goreportcard.com/report/github.com/devops-kung-fu/hookz)
[![Go Report Card](https://goreportcard.com/badge/github.com/devops-kung-fu/hookz)](https://goreportcard.com/report/github.com/devops-kung-fu/hookz) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/devops-kung-fu/hookz)

Manages git hooks inside a local git repository based on a configuration.

Expand All @@ -25,18 +25,18 @@ To install hookz, [download the latest release](https://github.com/devops-kung-
Linux Example:

```bash
sudo chmod +x hookz-2.0.0-linux-amd64
sudo mv hookz-2.0.0-linux-amd64 /usr/local/bin/hookz
sudo chmod +x hookz-2.1.0-linux-amd64
sudo mv hookz-2.1.0-linux-amd64 /usr/local/bin/hookz
```

## Configuration

Hookz uses a configuration file to generate hooks in your local git repository. This file needs to be in the root of your repository and must be named *.hookz.yaml*

Take for example the following configuration:
### Example Configuration

``` yaml
version: 2.0
version: 2.1
hooks:
- type: pre-commit
actions:
Expand All @@ -59,17 +59,46 @@ hooks:
args: ["-e", "Done!"]
```
Hooks will read this exampe configuration and create a pre-commit hook and a post-commit hook based on this yaml.
Hooks will read this example configuration and create a pre-commit hook and a post-commit hook based on this yaml.
An action with an URL will download the binary from the defined URL and configure the hook to execute the command with the defined arguments before a commit happens.
The post-commit in this configuration will execute a command named "dude" with the arguments "Hello World" after a commit has occurred. Note that the _dude_ command must be on your path. If it isn't this post-commit will fail because the command isn't found.
## Support for multiple commands in a hook
### Optional elements
The following notes apply to the elements in the YAML:
|Attribute|Notes|
|---|---|
|URL|If this exists, then exec and script are ignored. The URL must be a link to an executable binary|
|exec|If this exists then URL and script are ignored|
|script|If this exists then URL, exec, and args are ignored|
|args|Optional in all cases|
### Inline scripting
Scripts can be embedded into the .hookz.yaml in multiline format such as follows:
__NOTE:__ There needs to be a \n at the end of a line if a multi-line statement exists in the script: node, and special characters need to be escaped properly.
``` yaml
- type: pre-commit
actions:
- name: "Go Tidy (Recursive)"
script: "
#!/bin/bash \n
echo -e Tidying all found go.mod occurrences \n
find . -name go.mod -print0 | xargs -0 -n1 dirname | xargs -L 1 bash -c 'cd \"$0\" && pwd && go mod tidy' \n
"
```
If you have args flags set, they can be referenced as $1, $2, etc. in your script in a similar manner as passing parameters in. Any scripting language is supported.
### Support for multiple commands in a hook
If multiple hooks are defined in the configuration with the same type (ie: pre-commit) they will be configured to run in the order they appear in the file. There is no need to group types together, they will be written to the appropriate hooks.
## Hook types
### Hook types
Hook types that will execute are the same as supported by _git_. Examples are as follows:
Expand All @@ -87,15 +116,15 @@ Hook types that will execute are the same as supported by _git_. Examples are as
* pre-receive
* update
## Return Codes
### Return Codes
Any non-zero return code from a command executed in a hook will return a FAIL.
## Running Hookz
![](img/hookz.png)
To generate the hooks as defined in your configuration simply execute the following command in the root of your local repository where the .hookz.yaml file resides:
To generate the hooks as defined in your configuration simply execute the following command in the _root of your local repository_ where the .hookz.yaml file resides:
``` bash
hookz initialize # you can also use the init alias
Expand All @@ -113,7 +142,14 @@ To re-download any file defined in an URL key:
hookz update
```

## Verbose option
### Applying changes to the .hookz.yaml
If there is a modification to the .hookz.yaml file in your application, you'll need to apply the changes using the following:

``` bash
hookz reset
```

### Verbose option

The initialize (init) and reset command optionally take a verbosity flag to indicate extended output should be displayed when a hook executes. This is handy for debugging or seeing errors that may be suppressed by hookz.

Expand All @@ -123,10 +159,24 @@ hookz reset --verbose
```
## Example Hooks

### Recursively tidy all go.mod files in subdirectories

```yaml
version: 2.1.0
hooks:
- type: pre-commit
actions:
- name: "Go Tidy (Recursive)"
script: "
#!/bin/bash \n
echo -e Tidying all found go.mod occurrences\n
find . -name go.mod -print0 | xargs -0 -n1 dirname | xargs -L 1 bash -c 'cd \"$0\" && pwd && go mod tidy' \n
"
```
### Update all go modules to the latest version before committing
```yaml
version: 2.0
version: 2.1.0
hooks:
- type: pre-commit
actions:
Expand All @@ -138,7 +188,7 @@ hooks:
### Pull from your remote branch before committing
``` yaml
version: 2.0
version: 2.1.0
hooks:
- type: pre-commit
actions:
Expand Down
65 changes: 58 additions & 7 deletions cmd/init.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package cmd

import (
"errors"
"fmt"
"os"
"path/filepath"

"github.com/segmentio/ksuid"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -47,14 +47,54 @@ func createFile(name string) error {
return nil
}

func createScriptFile(content string) (name string, err error) {
var _, statErr = os.Stat(name)
k, idErr := ksuid.NewRandom()
name, _ = filepath.Abs(fmt.Sprintf(".git/hooks/%s", k.String()))
if idErr != nil {
fmt.Printf("Error generating KSUID: %v\n", err)
return
}

if os.IsNotExist(statErr) {
hookzFile, hookzFileErr := filepath.Abs(fmt.Sprintf(".git/hooks/%s.hookz", k.String()))
createFile(hookzFile)
if err != nil {
err = hookzFileErr
return
}

var file, createErr = os.Create(name)
if err != nil {
err = createErr
return
}

err = os.Chmod(name, 0777)
if err != nil {
return
}

file, err = os.OpenFile(name, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return
}
_, err = file.WriteString(content)
if err != nil {
return
}

defer file.Close()
}

return
}

func writeHooks() error {
var config, err = readConfig()
if err != nil {
return err
}
if config.Version != Version {
return errors.New("Version Mismatch: Expected v1.1 - Check your .hookz.yaml configuration\n")
}

exitCodeBlock := `
commandexit=$?
Expand Down Expand Up @@ -99,23 +139,34 @@ blackText='\033[0;30m'
if err != nil {
return err
}
_, err = file.WriteString(fmt.Sprintf("%s", header))
_, err = file.WriteString(header)
if err != nil {
return err
}

defer file.Close()

fmt.Println(fmt.Sprintf("\n[*] Writing %s ", hook.Type))
for _, action := range hook.Actions {

var argsString string
for _, arg := range action.Args {
argsString = fmt.Sprintf("%s %s", argsString, arg)
}

if action.URL != nil {
if action.Exec == nil && action.URL != nil {
filename, _ := downloadURL(*action.URL)
action.Exec = &filename
}

if action.Exec == nil && action.Script != nil {
scriptFileName, err := createScriptFile(*action.Script)
if err != nil {
return err
}
action.Exec = &scriptFileName
}

fmt.Println(fmt.Sprintf(" Adding %s action: %s", hook.Type, action.Name))
_, err = file.WriteString(fmt.Sprintf("name='%s'\ntype='%s'\n", action.Name, hook.Type))
if err != nil {
return err
Expand Down
9 changes: 5 additions & 4 deletions cmd/remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import (

var (
removeCmd = &cobra.Command{
Use: "remove",
Short: "Removes the hooks as defined in the .hooks.yaml file.",
Long: "Removes the hooks as defined in the .hooks.yaml file.",
Use: "remove",
Aliases: []string{"delete"},
Short: "Removes the hooks as defined in the .hooks.yaml file and any generated scripts.",
Long: "Removes the hooks as defined in the .hooks.yaml file and any generated scripts.",
Run: func(cmd *cobra.Command, args []string) {
hookzHeader()
fmt.Println("Removing git hooks...")
fmt.Println("[*] Removing existing hooks...")
if isErrorBool(removeHooks(), "[ERROR]") {
return
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ var (
Long: "Rebuilds the hooks as defined in the .hooks.yaml file.",
Run: func(cmd *cobra.Command, args []string) {
hookzHeader()
fmt.Println("Resetting git hooks...")
fmt.Println("Resetting git hooks")
fmt.Println()
fmt.Println("[*] Removing existing hooks...")
if isErrorBool(removeHooks(), "[ERROR]") {
return
}
Expand Down
Loading

0 comments on commit bc7e94f

Please sign in to comment.