Skip to content

Commit 6344f32

Browse files
authored
use lib/; my-cmd hooks; use printf; more vendor filtering (#13)
* Refactored to use include files, removing duplicate code * Adds my-cmd hooks to invoke custom tools * Replaces all usages of echo with printf * Adds more vendor filtering * Updates project description * Reverts copy/pasta in go-test hook docs added in gosec commit * Adds shellcheck hook to lint project files * Adds shfmt hook to normalize formatting in project files * Updates copyright year in LICENSE file
1 parent ad0f10b commit 6344f32

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+645
-1231
lines changed

.pre-commit-config.yaml

+34-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,43 @@
33
# See https://pre-commit.com/hooks.html for more hooks
44
# ==============================================================================
55
repos:
6-
- repo: https://github.com/pre-commit/pre-commit-hooks
6+
- repo: https://github.com/pre-commit/pre-commit-hooks
77
rev: v2.0.0
88
hooks:
99
- id: check-merge-conflict
1010
- id: trailing-whitespace
1111
- id: end-of-file-fixer
1212
- id: check-yaml
13+
# Bash helper hooks (local)
14+
#
15+
- repo: local
16+
hooks:
17+
# shellcheck (aliased to shck)
18+
#
19+
- id: shellcheck
20+
name: Run static analysis (shellcheck)
21+
entry: shellcheck
22+
language: system
23+
files: \.(sh|bash)$
24+
types: [file]
25+
alias: shck
26+
args: [ '-x' ]
27+
# shfmt
28+
#
29+
- id: shfmt
30+
name: Run lint check (shfmt -d)
31+
entry: shfmt
32+
language: system
33+
files: \.(sh|bash)$
34+
types: [file]
35+
args: [ '-i', '0', '-ci', '-sr', '-d' ]
36+
# shfmt -w (must manually invoke)
37+
#
38+
- id: shfmtw
39+
name: Auto-fix lint errors (shfmt -w)
40+
entry: shfmt
41+
language: system
42+
stages: [manual]
43+
files: \.(sh|bash)$
44+
types: [file]
45+
args: [ '-i', '0', '-ci', '-sr', '-kp', '-w' ]

.pre-commit-hooks.yaml

+95
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,98 @@
1+
# ==============================================================================
2+
# my-cmd
3+
# * File-based
4+
# * Executes if any .go files modified
5+
# ==============================================================================
6+
- id: my-cmd
7+
name: 'my-cmd'
8+
entry: my-cmd.sh
9+
types: [go]
10+
exclude: '(^|/)vendor/'
11+
language: 'script'
12+
description: "Run '$ARGS[0] [$ARGS[1:]] $FILE' for each staged .go file"
13+
pass_filenames: true
14+
15+
# ==============================================================================
16+
# my-cmd-mod
17+
# * Folder-Based
18+
# * Recursive
19+
# * Targets first parent folder with a go.mod file
20+
# * Executes if any .go files modified
21+
# * Executes if go.mod modified
22+
# ==============================================================================
23+
- id: my-cmd-mod
24+
name: 'my-cmd-mod'
25+
entry: my-cmd-mod.sh
26+
files: '(\.go$)|(\bgo\.mod$)'
27+
exclude: '(^|/)vendor/'
28+
language: 'script'
29+
description: "Run 'cd $(mod_root $FILE); $ARGS[0] [$ARGS[1:]] ./...' for each staged .go file"
30+
pass_filenames: true
31+
require_serial: true
32+
33+
# ==============================================================================
34+
# my-cmd-pkg
35+
# * Folder-Based
36+
# * Targets folder containing staged file
37+
# * Executes if any .go files modified
38+
# ==============================================================================
39+
- id: my-cmd-pkg
40+
name: 'my-cmd-pkg'
41+
entry: my-cmd-pkg.sh
42+
types: [go]
43+
exclude: '(^|/)vendor/'
44+
language: 'script'
45+
description: "Run '$ARGS[0] [$ARGS[1:]] ./$(dirname $FILE)' for each staged .go file"
46+
pass_filenames: true
47+
require_serial: true
48+
49+
# ==============================================================================
50+
# my-cmd-repo
51+
# * Repo-Based
52+
# * Recursive
53+
# * Executes if any .go files modified
54+
# ==============================================================================
55+
- id: my-cmd-repo
56+
name: 'my-cmd-repo'
57+
entry: my-cmd-repo.sh
58+
types: [go]
59+
exclude: '(^|/)vendor/'
60+
language: 'script'
61+
description: "Run '$ARGS[0] [$ARGS[1:]]' in the repo root folder"
62+
pass_filenames: false
63+
64+
# ==============================================================================
65+
# my-cmd-repo-mod
66+
# * Repo-Based
67+
# * Recursive
68+
# * Targets ALL folders with a go.mod file
69+
# * Executes if any .go files modified
70+
# * Executes if go.mod modified
71+
# ==============================================================================
72+
- id: my-cmd-repo-mod
73+
name: 'my-cmd-repo-mod'
74+
entry: my-cmd-repo-mod.sh
75+
files: '(\.go$)|(\bgo\.mod$)'
76+
exclude: '(^|/)vendor/'
77+
language: 'script'
78+
description: "Run 'cd $(mod_root); $ARGS[0] [$ARGS[1:]] /...' for each module in the repo"
79+
pass_filenames: false
80+
81+
# ==============================================================================
82+
# my-cmd-repo-pkg
83+
# * Repo-Based
84+
# * Recursive
85+
# * Executes if any .go files modified
86+
# ==============================================================================
87+
- id: my-cmd-repo-pkg
88+
name: 'my-cmd-repo-pkg'
89+
entry: my-cmd-repo-pkg.sh
90+
types: [go]
91+
exclude: '(^|/)vendor/'
92+
language: 'script'
93+
description: "Run '$ARGS[0] [$ARGS[1:]] ./...' in repo root folder"
94+
pass_filenames: false
95+
196
# ==============================================================================
297
# go-build-mod
398
# * Folder-Based

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2019 TekWize.ly
3+
Copyright (c) 2019-2021 TekWize.ly
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

+93-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Pre-Commit-GoLang [![MIT license](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/tekwizely/pre-commit-golang/blob/master/LICENSE)
22

3-
A set of git pre-commit hooks for Golang with support for Modules.
3+
A set of git pre-commit hooks for Golang with support for multi-module monorepos, the ability to pass arguments to all hooks, and the ability to invoke custom go tools.
44

5-
Requires the [Pre-Commit.com](https://pre-commit.com) Hook Management framework.
5+
Requires the [Pre-Commit.com](https://pre-commit.com) Hook Management Framework.
66

77
---------------
88
## Installation
@@ -89,6 +89,19 @@ You can copy/paste the following snippet into your `.pre-commit-config.yaml` fil
8989
- id: golangci-lint-pkg
9090
- id: golangci-lint-repo-mod
9191
- id: golangci-lint-repo-pkg
92+
#
93+
# Invoking Custom Go Tools
94+
# - Configured *entirely* through the `args` attribute, ie:
95+
# args: [ go, test ]
96+
# - Use the `name` attribute to provide better messaging when the hook runs
97+
# - Use the `alias` attribute to be able invoke your hook via `pre-commit run`
98+
#
99+
- id: my-cmd
100+
- id: my-cmd-mod
101+
- id: my-cmd-pkg
102+
- id: my-cmd-repo
103+
- id: my-cmd-repo-mod
104+
- id: my-cmd-repo-pkg
92105
```
93106
94107
-----------
@@ -127,6 +140,7 @@ Hooks have suffixes in their name that indicate their targets:
127140
| \<none> | Files | Targets staged files directly |
128141
| `-mod` | Module | Targets module root folders of staged `.go` files |
129142
| `-pkg` | Package | Targets folders containing staged `.go` files |
143+
| `-repo` | Repo Root | Targets the repo root folder |
130144
| `-repo-mod` | All Modules | Targets all module root folders in the repo |
131145
| `-repo-pkg` | All Packages | Targets all package folders in the repo |
132146

@@ -136,6 +150,14 @@ Due to OS command-line-length limits, Pre-Commit can invoke a hook multiple time
136150

137151
For file and repo-based hooks, this isn't an issue, but for module and package-based hooks, there is a potential for the hook to run against the same module or package multiple times, duplicating any errors or warnings.
138152

153+
-------------------------
154+
### Invoking Custom Tools
155+
While this project includes builtin hooks for many popular go tools, it's not possible to include builtin hooks for every tool that users might want to use.
156+
157+
To help accommodate those users, this project includes the ability to invoke custom go tools.
158+
159+
See the [my-cmd](#my-cmd) hooks for more information.
160+
139161
--------------------------
140162
### Useful Hook Parameters
141163
```
@@ -190,6 +212,8 @@ This can be useful, for example, for hooks that display warnings, but don't gene
190212
- [go-revive](#go-revive)
191213
- GolangCI-Lint
192214
- [golangci-lint](#golangci-lint)
215+
- Invoking Custom Tools
216+
- [my-cmd](#my-cmd)
193217
194218
------------
195219
### go-build
@@ -215,10 +239,10 @@ Automates testing, printing a summary of test resutls.
215239
216240
| Hook ID | Description
217241
|--------------------|------------
218-
| `go-test-mod` | Run `'cd $(mod_root $FILE); gosec [$ARGS] ./...'` for each staged .go file
219-
| `go-test-pkg` | Run `'gosec [$ARGS] ./$(dirname $FILE)'` for each staged .go file
220-
| `go-test-repo-mod` | Run `'cd $(mod_root); gosec [$ARGS] ./...'` for each module in the repo
221-
| `go-test-repo-pkg` | Run `'gosec [$ARGS] ./...'` in repo root folder
242+
| `go-test-mod` | Run `'cd $(mod_root $FILE); go test [$ARGS] ./...'` for each staged .go file
243+
| `go-test-pkg` | Run `'go test [$ARGS] ./$(dirname $FILE)'` for each staged .go file
244+
| `go-test-repo-mod` | Run `'cd $(mod_root); go test [$ARGS] ./...'` for each module in the repo
245+
| `go-test-repo-pkg` | Run `'go test [$ARGS] ./...'` in repo root folder
222246
223247
##### Install
224248
Comes with Golang ( [golang.org](https://golang.org/) )
@@ -484,6 +508,69 @@ bingo install github.com/golangci/golangci-lint/cmd/golangci-lint
484508
- https://github.com/golangci/golangci-lint#config-file
485509
- `golangci-lint config -h`
486510
511+
----------
512+
### my-cmd
513+
514+
Using the `my-cmd-*` hooks, you can invoke custom go tools in various contexts.
515+
516+
| Hook ID | Description
517+
|-------------------|------------
518+
| `my-cmd` | Run `'$ARGS[0] [$ARGS[1:]] $FILE'` for each staged .go file
519+
| `my-cmd-mod` | Run `'cd $(mod_root $FILE); $ARGS[0] [$ARGS[1:]] ./...'` for each staged .go file
520+
| `my-cmd-pkg` | Run `'$ARGS[0] [$ARGS[1:]] ./$(dirname $FILE)'` for each staged .go file
521+
| `my-cmd-repo` | Run `'$ARGS[0] [$ARGS[1:]]'` in the repo root folder
522+
| `my-cmd-repo-mod` | Run `'cd $(mod_root); $ARGS[0] [$ARGS[1:]] /...'` for each module in the repo
523+
| `my-cmd-repo-pkg` | Run `'$ARGS[0] [$ARGS[1:]] ./...'` in repo root folder
524+
525+
#### Configuring the hooks
526+
527+
The my-cmd hooks are configured **entirely** through the pre-commit `args` attribute, including specifying which tool to run (ie `$ARGS[0]` above)
528+
529+
#### Examples
530+
531+
Here's an example of what it would look like to use the my-cmd hooks to invoke `go test` if it wasn't already included:
532+
533+
_.pre-commit-config.yaml_
534+
```
535+
# ...
536+
hooks:
537+
# Run 'cd $(mod_root $FILE); go test ./...' for each staged .go file
538+
- id: my-cmd-mod
539+
name: go-test-mod
540+
alias: go-test-mod
541+
args: [ go, test ]
542+
```
543+
544+
##### Names &amp; Aliases
545+
546+
It is recommended that you use both `name` and `alias` attributes when defining my-cmd hooks.
547+
548+
The name will provide better messaging when the hook runs.
549+
550+
The alias will enable you to invoke the hook manually from the command-line when needed (see `pre-commit help run`)
551+
552+
##### error-on-output
553+
554+
Some tools, like `gofmt`, `goimports`, and `goreturns`, don't generate error codes, but instead expect the presence of any output to indicate warning/error conditions.
555+
556+
The my-cmd hooks accept an `--error-on-output` argument to indicate this behavior.
557+
558+
Here's an example of what it would look like to use the my-cmd hooks to invoke `gofmt` if it wasn't already included:
559+
560+
_.pre-commit-config.yaml_
561+
```
562+
# ...
563+
hooks:
564+
# Run 'gofmt -l -d $FILE' for each staged .go file
565+
# Treat any output as indication of failure
566+
- id: my-cmd
567+
name: go-fmt
568+
alias: go-fmt
569+
args: [ --error-on-output, gofmt, -l, -d ]
570+
```
571+
572+
**NOTE:** When used, the `--error-on-output` option **must** be the first argument.
573+
487574
----------
488575
## License
489576

go-build-mod.sh

+4-68
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,6 @@
11
#!/usr/bin/env bash
2-
2+
# shellcheck disable=SC2034 # vars used by sourced script
3+
error_on_output=0
34
cmd=(go build -o /dev/null)
4-
5-
export GO111MODULE=on
6-
7-
# Walks up the file path looking for go.mod
8-
#
9-
function find_module_roots() {
10-
for arg in "$@" ; do
11-
local path="${arg}"
12-
if [ "${path}" == "" ]; then
13-
path="."
14-
elif [ -f "${path}" ]; then
15-
path=$(dirname "${path}")
16-
fi
17-
while [ "${path}" != "." ] && [ ! -f "${path}/go.mod" ]; do
18-
path=$(dirname "${path}")
19-
done
20-
if [ -f "${path}/go.mod" ]; then
21-
echo "${path}"
22-
fi
23-
done
24-
}
25-
26-
OPTIONS=()
27-
# If arg doesn't pass [ -f ] check, then it is assumed to be an option
28-
#
29-
while [ $# -gt 0 ] && [ "$1" != "-" ] && [ "$1" != "--" ] && [ ! -f "$1" ]; do
30-
OPTIONS+=("$1")
31-
shift
32-
done
33-
34-
FILES=()
35-
# Assume start of file list (may still be options)
36-
#
37-
while [ $# -gt 0 ] && [ "$1" != "-" ] && [ "$1" != "--" ]; do
38-
FILES+=("$1")
39-
shift
40-
done
41-
42-
# If '--' next, then files = options
43-
#
44-
if [ $# -gt 0 ]; then
45-
if [ "$1" == "-" ] || [ "$1" == "--" ]; then
46-
shift
47-
# Append to previous options
48-
#
49-
OPTIONS=("${OPTIONS[@]}" "${FILES[@]}")
50-
FILES=()
51-
fi
52-
fi
53-
54-
# Any remaining arguments are assumed to be files
55-
#
56-
while [ $# -gt 0 ]; do
57-
FILES+=("$1")
58-
shift
59-
done
60-
61-
errCode=0
62-
for sub in $(find_module_roots "${FILES[@]}" | sort -u) ; do
63-
pushd "${sub}" >/dev/null
64-
"${cmd[@]}" "${OPTIONS[@]}" ./...
65-
if [ $? -ne 0 ]; then
66-
errCode=1
67-
fi
68-
popd >/dev/null
69-
done
70-
exit $errCode
5+
# shellcheck source=lib/cmd-mod.bash
6+
. "$(dirname "${0}")/lib/cmd-mod.bash"

0 commit comments

Comments
 (0)