diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 85f038d..bed99e6 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -72,3 +72,20 @@ language: script files: \.go$ exclude: vendor\/.*$ + +# --------------------------------------------------------------------------------------------------------------------- +# GNU Make specific hooks +# --------------------------------------------------------------------------------------------------------------------- + +# Validate targets that are marked as PHONY +- id: phony-targets + name: phony-targets + description: Linter for detecting targets marked as PHONY that don't exist. + entry: pre_commit_hooks/make/phony-targets.sh + language: script + files: (Makefile|Makefile.*|.+.mak|.+.mk)$ + exclude: > + (?x)^( + .+\.vendor\/.*$| + .+\.terraform\/.*$| + )$ diff --git a/README.md b/README.md index 88f0ead..7b13923 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,10 @@ Currently, the following hooks are supported: It's fast: on average 5 times faster than gometalinter. It's easy to integrate and use, has nice output and has a minimum number of false positives. +**GNU Make** +- [phony-targets](https://github.com/mineiros-io/pre-commit-hooks/blob/master/pre_commit_hooks/make/phony-targets.sh): + This hook validates if targets that are marked as `PHONY` actually exist. + ## Installation & Dependencies Install [pre-commit](https://pre-commit.com/). E.g. `brew install pre-commit` @@ -49,6 +53,7 @@ repos: - id: gofmt - id: goimports - id: golint + - id: phony-targets ``` Once you created the configuration file inside your repository, you must run `pre-commit install` to activate the hooks. diff --git a/pre_commit_hooks/make/phony-targets.sh b/pre_commit_hooks/make/phony-targets.sh new file mode 100755 index 0000000..d24cf7c --- /dev/null +++ b/pre_commit_hooks/make/phony-targets.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -e + +EXITCODE=0 + +validate_phony_targets() { + local file=$1 + local source=$(make -npq -f "${file}" | grep -E '^.PHONY:') + local targets=$(sed -n 's#^.PHONY:\(.*\)#\1#p' <<< "${source}") + + for target in $targets; do + # The q command for setting exit codes if a pattern doesn't match, + # isn't supported in OSX / BSD sed. + # We check the exact match as a workaround instead. + # If the pattern doesn't match that means that the target doesn't exist. + if test -z "$(sed -ne "s#^\(${target}:\).*#\1#p" "${file}")"; then + echo "No target found for PHONY target: '$target'" + EXITCODE=1 + fi + done +} + +for file in "$@"; do + validate_phony_targets "$file" +done + +exit $EXITCODE