diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 5313a62..991d69a 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -140,6 +140,55 @@ description: "Run 'goreturns -l -d [$ARGS] $FILE' for each staged .go file" pass_filenames: true +# ============================================================================== +# go-revive +# * File-based +# * Executes if any .go files modified +# ============================================================================== +- id: go-revive + name: 'go-revive' + entry: go-revive.sh + types: [go] + exclude: '(^|/)vendor/' + language: 'script' + description: "Run 'revive [$ARGS] $FILE' for each staged .go file" + pass_filenames: true + +# ============================================================================== +# go-revive-mod +# * Folder-Based +# * Recursive +# * Targets first parent folder with a go.mod file +# * Executes if any .go files modified +# * Executes if go.mod modified +# ============================================================================== +- id: go-revive-mod + name: 'go-revive-mod' + entry: go-revive-mod.sh + files: '(\.go$)|(\bgo\.mod$)' + exclude: '(^|/)vendor/' + language: 'script' + description: "Run 'cd $(mod_root $FILE); revive [$ARGS] ./...' for each staged .go file" + pass_filenames: true + require_serial: true + +# ============================================================================== +# go-revive-repo-mod +# * Repo-Based +# * Recursive +# * Targets ALL folders with a go.mod file +# * Executes if any .go files modified +# * Executes if go.mod modified +# ============================================================================== +- id: go-revive-repo-mod + name: 'go-revive-repo-mod' + entry: go-revive-repo-mod.sh + files: '(\.go$)|(\bgo\.mod$)' + exclude: '(^|/)vendor/' + language: 'script' + description: "Run 'cd $(mod_root); revive [$ARGS] ./...' for each module in the repo" + pass_filenames: false + # ============================================================================== # go-sec-mod # * Folder-Based diff --git a/README.md b/README.md index 48ea0e0..aebc0e7 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,12 @@ You can copy/paste the following snippet into your `.pre-commit-config.yaml` fil - id: go-vet-repo-mod - id: go-vet-repo-pkg # + # Revive + # + - id: go-revive + - id: go-revive-mod + - id: go-revive-repo-mod + # # GoSec # - id: go-sec-mod @@ -137,6 +143,7 @@ For file and repo-based hooks, this isn't an issue, but for module and package-b args: [arg1, arg2, ..., '--'] # Pass options ('--' is optional) always_run: true # Run even if no matching files staged alias: hook-alias # Create an alias + verbose: true # Display output, even if no errors ``` #### Passing Options To Hooks @@ -160,6 +167,11 @@ When configured to `"always_run"`, a hook is executed as if EVERY matching file #### Aliases Consider adding aliases to longer-named hooks for easier CLI usage. +#### Verbose Hook Output +When the `"verbose"` flag is enabled, all output generated by the hook will be displayed, even if there were no errors. + +This can be useful, for example, for hooks that display warnings, but don't generate error codes for them. + -------- ## Hooks @@ -175,6 +187,7 @@ Consider adding aliases to longer-named hooks for easier CLI usage. - Style Checkers - [go-lint](#go-lint) - [go-critic](#go-critic) + - [go-revive](#go-revive) - GolangCI-Lint - [golangci-lint](#golangci-lint) @@ -361,6 +374,37 @@ go get -u golang.org/x/lint/golint - https://golang.org/doc/effective_go.html - https://golang.org/wiki/CodeReviewComments +------------- +### go-revive +~6x faster, stricter, configurable, extensible, and beautiful drop-in replacement for golint. + +| Hook ID | Description +|-----------|------------ +| `go-revive` | Run `'revive [$ARGS] $FILE'` for each staged .go file +| `go-revive-mod` | Run `'cd $(mod_root $FILE); revive [$ARGS] ./...'` for each staged .go file +| `go-revive-repo-mod` | Run `'cd $(mod_root); revive [$ARGS] ./...'` for each module in the repo + +##### Install +``` +go get -u github.com/mgechev/revive +``` + +##### Useful Args +``` +-config [PATH] : Path to config file (TOML) +-exclude [PATTERN] : Pattern for files/directories/packages to be excluded from linting +-formatter [NAME] : formatter to be used for the output +``` + +##### Displaying Warnings +By default, `revive` doesn't generate errors on warnings, so warning messages may not be displayed if there are no accompanying error messages. + +You can use the `"verbose: true"` hook configuration to always show hook output. + +##### Help + - https://github.com/mgechev/revive#usage + - `revive -h` + ------------- ### go-critic The most opinionated Go source code linter for code audit. diff --git a/go-revive-mod.sh b/go-revive-mod.sh new file mode 100755 index 0000000..7800c24 --- /dev/null +++ b/go-revive-mod.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +cmd=(revive) + +export GO111MODULE=on + +# Walks up the file path looking for go.mod +# +function find_module_roots() { + for arg in "$@" ; do + local path="${arg}" + if [ "${path}" == "" ]; then + path="." + elif [ -f "${path}" ]; then + path=$(dirname "${path}") + fi + while [ "${path}" != "." ] && [ ! -f "${path}/go.mod" ]; do + path=$(dirname "${path}") + done + if [ -f "${path}/go.mod" ]; then + echo "${path}" + fi + done +} + +OPTIONS=() +# If arg doesn't pass [ -f ] check, then it is assumed to be an option +# +while [ $# -gt 0 ] && [ "$1" != "-" ] && [ "$1" != "--" ] && [ ! -f "$1" ]; do + OPTIONS+=("$1") + shift +done + +FILES=() +# Assume start of file list (may still be options) +# +while [ $# -gt 0 ] && [ "$1" != "-" ] && [ "$1" != "--" ]; do + FILES+=("$1") + shift +done + +# If '--' next, then files = options +# +if [ $# -gt 0 ]; then + if [ "$1" == "-" ] || [ "$1" == "--" ]; then + shift + # Append to previous options + # + OPTIONS=("${OPTIONS[@]}" "${FILES[@]}") + FILES=() + fi +fi + +# Any remaining arguments are assumed to be files +# +while [ $# -gt 0 ]; do + FILES+=("$1") + shift +done + +errCode=0 +for sub in $(find_module_roots "${FILES[@]}" | sort -u) ; do + pushd "${sub}" >/dev/null + "${cmd[@]}" "${OPTIONS[@]}" ./... + if [ $? -ne 0 ]; then + errCode=1 + fi + popd >/dev/null +done +exit $errCode diff --git a/go-revive-repo-mod.sh b/go-revive-repo-mod.sh new file mode 100755 index 0000000..198d6d1 --- /dev/null +++ b/go-revive-repo-mod.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +cmd=(revive) + +export GO111MODULE=on + +OPTIONS=() +# Build options list, ignoring '-', '--', and anything after +# +while [ $# -gt 0 ] && [ "$1" != "-" ] && [ "$1" != "--" ]; do + OPTIONS+=("$1") + shift +done + +errCode=0 +# Assume parent folder of go.mod is module root folder +# +for sub in $(find . -name go.mod -not -path '*/vendor/*' | xargs -n1 dirname | sort -u) ; do + pushd "${sub}" >/dev/null + "${cmd[@]}" "${OPTIONS[@]}" ./... + if [ $? -ne 0 ]; then + errCode=1 + fi + popd >/dev/null +done +exit $errCode diff --git a/go-revive.sh b/go-revive.sh new file mode 100755 index 0000000..0d4b032 --- /dev/null +++ b/go-revive.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +cmd=(revive) + +OPTIONS=() +# If arg doesn't pass [ -f ] check, then it is assumed to be an option +# +while [ $# -gt 0 ] && [ "$1" != "-" ] && [ "$1" != "--" ] && [ ! -f "$1" ]; do + OPTIONS+=("$1") + shift +done + +FILES=() +# Assume start of file list (may still be options) +# +while [ $# -gt 0 ] && [ "$1" != "-" ] && [ "$1" != "--" ]; do + FILES+=("$1") + shift +done + +# If '--' next, then files = options +# +if [ $# -gt 0 ]; then + if [ "$1" == "-" ] || [ "$1" == "--" ]; then + shift + # Append to previous options + # + OPTIONS=("${OPTIONS[@]}" "${FILES[@]}") + FILES=() + fi +fi + +# Any remaining arguments are assumed to be files +# +while [ $# -gt 0 ]; do + FILES+=("$1") + shift +done + +errCode=0 +for file in "${FILES[@]}"; do + "${cmd[@]}" "${OPTIONS[@]}" "${file}" + if [ $? -ne 0 ]; then + errCode=1 + fi +done +exit $errCode diff --git a/sample-config.yaml b/sample-config.yaml index a49e7a7..032dfef 100644 --- a/sample-config.yaml +++ b/sample-config.yaml @@ -97,6 +97,12 @@ repos: - id: go-vet-repo-mod - id: go-vet-repo-pkg # + # Revive + # + - id: go-revive + - id: go-revive-mod + - id: go-revive-repo-mod + # # GoSec # - id: go-sec-mod