Useful Git hooks for developing in Go

I have setup some Git hooks that help me catch tests that fail, show golint , go vet errors.

Git hooks are located in .git/hooks.

Go test

My pre-push git hook file contains

#!/bin/bash

echo -e "\nRunning tests for you"
go test $(go list github.com/dgraph-io/dgraph/...| grep -v vendor)

So it runs all tests except those in the vendor folder for me before I push.


Golint and Go Vet

Taking some inspiration from here https://github.com/youtube/vitess/tree/master/misc/git/hooks, I setup a pre-commit hook which checks for go vet and golint errors for the staged files whose content was changed.

Contents of the pre-commit file

#!/bin/bash

sh .git/hooks/golint.sh
sh .git/hooks/govet.sh

golint.sh

#!/bin/bash

if [ -z "$GOPATH" ]; then
	echo "ERROR: pre-commit hook for golint: \$GOPATH is empty."
	exit 1
fi

if [ -z "$(which golint)" ]; then
	echo "golint not found, please run: go get github.com/golang/lint/golint"
	exit 1
fi

# This script does not handle file names that contain spaces.
gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '\.go$')

errors=

# Run on one file at a time because a single invocation of golint
# with multiple files requires the files to all be in one package.
gofiles_with_warnings=()
for gofile in $gofiles
do
	errcount=$(golint $gofile | wc -l)
	if [ "$errcount" -gt "0" ]; then
		errors=YES
		echo "$errcount suggestions for:"
		echo "golint $gofile"
		gofiles_with_warnings+=($gofile)
	fi
done

[ -z "$errors" ] && exit 0

# git doesn't give us access to user input, so let's steal it.
exec < /dev/tty
if [[ $? -eq 0 ]]; then
	# interactive shell. Prompt the user.
	echo
	echo "Lint suggestions were found. They're not enforced, but we're pausing"
	echo "to let you know before they get clobbered in the scrollback buffer."
	echo
	read -r -p 'Press enter to cancel, "s" to step through the warnings or type "ack" to continue: '
	if [ "$REPLY" = "ack" ]; then
		exit 0
	fi
	if [ "$REPLY" = "s" ]; then
		first_file="true"
		for gofile in "${gofiles_with_warnings[@]}"
		do
			echo
			if [ "$first_file" != "true" ]; then
				echo "Press enter to show the warnings for the next file."
				read
			fi
			golint $gofile
			first_file="false"
		done
	fi
else
	# non-interactive shell (e.g. called from Eclipse). Just display the errors.
	for gofile in "${gofiles_with_warnings[@]}"
	do
		golint $gofile
	done
fi
exit 1

govet.sh

#!/bin/bash


#!/bin/sh
# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# git go vet pre-commit hook
#
# To use, store as .git/hooks/pre-commit inside your repository and make sure
# it has execute permissions.

if [ -z "$GOPATH" ]; then
	echo "ERROR: pre-commit hook for go vet: \$GOPATH is empty. Please run 'source dev.env' to set the correct \$GOPATH."
	exit 1
fi

# This script does not handle file names that contain spaces.
gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '\.go$')

# If any checks are found to be useless, they can be disabled here.
# See the output of "go tool vet" for a list of flags.
vetflags="-all=true"

errors=

# Run on one file at a time because a single invocation of "go tool vet"
# with multiple files requires the files to all be in one package.
for gofile in $gofiles
do
	if ! go tool vet $vetflags $gofile 2>&1; then
		errors=YES
	fi
done

[ -z  "$errors" ] && exit 0

echo
echo "Please fix the go vet warnings above. To disable certain checks, change vetflags in misc/git/hooks/govet."
exit 1

Though this takes a bit more time, it helps catch obvious errors and avoid the back and forth while doing a PR review.

3 Likes

This is awesome, @pawan! How about checking these into contrib in dgraph, so we can then do a symlink to them from .git/hooks?

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.