Skip to content

Commit

Permalink
Merge pull request #24 from aaronjameslang/setup
Browse files Browse the repository at this point in the history
Add `proofr setup` subcommand for end user ease
  • Loading branch information
aaronjameslang authored Apr 9, 2017
2 parents faa153f + d7d4dc3 commit 882383f
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 8 deletions.
12 changes: 11 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
all: sniff test test-shells
all: build sniff test-libs test test-shells

build: bin/proofr

bin/proofr: $(wildcard lib/*)
mkdir -p bin
echo '#! /bin/sh' | cat - lib/setup.sh lib/main.sh > bin/proofr
chmod u+x bin/proofr

benchmark:
perf stat -r 10 make test
Expand All @@ -9,6 +16,9 @@ sniff:
test:
./test.sh

test-libs:
cd test && roundup || sh ./*-test.sh

test-shells:
./test-shells.sh

Expand Down
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,13 @@ Do you or your collaborators have trouble remembering how to format your commit
## Setup
```
echo 'proofr "$@" || exit $?' >> my-project/.git/hooks/commit-msg
chmod u+x my-project/.git/hooks/commit-msg
```
`cd my-project && proofr setup`
This should work most of the time, but assumes that you have your `PATH` set correctly. If you get `command not found: proofr` either fix your path or use a more specific path to `proofr`, e.g. `path/to/proofr "$@" || exit $?`
This will add `proofr` to the `commit-msg` hook of your project
After you've written your commit message, git will call `.git/hooks/commit-msg` and pass in the commit message as the first parameter. You can make `commit-msg` anything you like so long as it
## How `proofr` works
After each commit message you write, git will call `.git/hooks/commit-msg` and pass in the commit message as the first parameter. You can make `commit-msg` anything you like so long as it
- Calls `proofr`
- Passes `proofr` it's first argument
- Deals with `proofr`'s exit code
Expand All @@ -55,7 +54,7 @@ For background see http://githooks.com
Should work on most *nixes, including GNU/Linux, Mac OSX, and [Windows Subsystem for Linux](https://msdn.microsoft.com/en-gb/commandline/wsl/install_guide)
If you are unsure of compatibilty with your system, run `make` or `test.sh`. If your system is incompatible, please open an issue.
If you are unsure of compatibilty with your system, run `make`. If your system is incompatible, please open an issue.
## Contribution
Expand Down
30 changes: 30 additions & 0 deletions bin/proofr
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
#! /bin/sh
#! /bin/sh --version
set -eu

setup() {
file='.git/hooks/commit-msg'
if ( test -f "$file" && grep_for_proofr "$file" )
then
echo 'proofr already setup'
else
echo "$0" '"$@" || exit $?' >> "$file"
chmod u+x "$file"
fi
}

grep_for_proofr () {
grep --quiet '\bproofr\b' "$@"
}
#! /bin/sh --version
set -eu

if test 0 -eq "$#"
then
echo 'Read the README'
exit 1
fi

if test 'setup' = "$1"
then
setup
exit
fi

commit_message_file="$1"

cleanup_commit_message () {
Expand Down
99 changes: 99 additions & 0 deletions lib/main.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#! /bin/sh --version
set -eu

if test 0 -eq "$#"
then
echo 'Read the README'
exit 1
fi

if test 'setup' = "$1"
then
setup
exit
fi

commit_message_file="$1"

cleanup_commit_message () {
commit_message_file="$1"
while read -r line
do
if test "$line" = '# ------------------------ >8 ------------------------'
then
return
fi
if test "$( echo "$line" | cut -c 1)" = '#'
then
continue
fi
echo "$line"
done < "$commit_message_file"
}

commit_message="$(cleanup_commit_message "$commit_message_file")"
commit_message_subject="$(echo "$commit_message" | head -n 1 )"
commit_message_body="$(echo "$commit_message" | tail -n +2)"

# Pass if message is empty, exit early
test -z "$commit_message" && exit

grep_subject() {
echo "$commit_message_subject" | grep --quiet "$1"
}

if grep_subject '^Merge '
then
is_merge=true
else
is_merge=false
fi

rule() {
case $1 in
1) echo Separate subject from body with a blank line ;;
2) echo Limit the subject line to 50 characters ;;
3) echo Capitalize the subject line ;;
4) echo Do not end the subject line with a period ;;
5) echo Use the imperative mood in the subject line ;;
6) echo Wrap the body at 72 characters ;;
7) echo Use the body to explain _what_ and _why_ vs. _how_ ;;
esac
}

validate() {
case $1 in
1) # Message has one line, or second line is blank
test -z "$(echo "$commit_message_body" | head -n 1)" ;;
2) # Subject is no more than 51 characters (50 + newline)
test 51 -ge ${#commit_message_subject} ||
$is_merge ;;
3) # Subject does not begin with lowercase letter
! grep_subject '^[a-z]' ;;
4) # Subject does not end with a period
$is_merge || ! grep_subject '\.\s*$' ;;
5) # Subject does not begin with past tense
! grep_subject '^\w*ed\s' ;;
6) # Body does not contain line longer than 73 characters
echo "$commit_message_body" | while read -r line
do
test 73 -ge "${#line}" || return 1 # TODO this return shouldn't be required
done ;;
esac
}

calc_error_code() {
echo $((1<<$1))
}

exit_code=0

for index in $(seq 6)
do
validate "$index" && continue
rule "$index"
error_code=$(calc_error_code "$index")
exit_code=$(( exit_code + error_code ))
done

exit "$exit_code"
17 changes: 17 additions & 0 deletions lib/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#! /bin/sh --version
set -eu

setup() {
file='.git/hooks/commit-msg'
if ( test -f "$file" && grep_for_proofr "$file" )
then
echo 'proofr already setup'
else
echo "$0" '"$@" || exit $?' >> "$file"
chmod u+x "$file"
fi
}

grep_for_proofr () {
grep --quiet '\bproofr\b' "$@"
}
102 changes: 102 additions & 0 deletions test/setup-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#! /bin/sh --version
set -eu

# shellcheck source=lib/setup.sh
. ../lib/setup.sh

it_does_not_match_no_hook () {
input='some-other-command --abc proofrun'
actual="$(! echo "$input" | grep_for_proofr)"
test -z "$actual"
}

it_matches_hook () {
input='proofr "$@" || exit $?'
actual="$(echo "$input" | grep_for_proofr)"
test -z "$actual"
}

it_matches_other_hook () {
# shellcheck disable=SC2016
input='command proofr "$1"'
actual="$(echo "$input" | grep_for_proofr)"
test -z "$actual"
}

it_sets_up_hook () {
cd "$(mktemp -d proofr-test-XXXX)"
git init
file=".git/hooks/commit-msg"
echo banana > "$file"
../../bin/proofr setup
actual="$(cat "$file")"
expected='banana
../../bin/proofr "$@" || exit $?'
rm -rf "$PWD"
cd -
test "$expected" = "$actual"
}

it_sets_up_missing_hook () {
cd "$(mktemp -d proofr-test-XXXX)"
git init
file=".git/hooks/commit-msg"
rm -f "$file"
test -d "$(dirname "$file")"
! test -f "$file"
../../bin/proofr setup
test -x "$file"
actual="$(cat "$file")"
expected='../../bin/proofr "$@" || exit $?'
rm -rf "$PWD"
cd -
test "$expected" = "$actual"
}

it_sets_up_exisiting_hook () {
cd "$(mktemp -d proofr-test-XXXX)"
git init
file=".git/hooks/commit-msg"
echo banana proofr > "$file"
../../bin/proofr setup
actual="$(cat "$file")"
expected='banana proofr'
rm -rf "$PWD"
cd -
test "$expected" = "$actual"
}

it_sets_up_hook_and_hook_works () {
cd "$(mktemp -d proofr-test-XXXX)"
git init
PATH="$PWD/../../bin/:$PATH"
rm -f .git/hooks/commit-msg
proofr setup
test -x .git/hooks/commit-msg
git config user.name 'proofr test'
git config user.email '[email protected]'
actual="$(git commit --allow-empty --message 'Fix it')"
echo "$actual" | grep --quiet '\[master (root-commit) [0-9a-f]\{7\}\] Fix it'
actual="$(! git commit --allow-empty --message 'fixed it.' 2>&1)"
test 'Capitalize the subject line
Do not end the subject line with a period
Use the imperative mood in the subject line' = "$actual"
# test from a subdirectory
mkdir fig
cd fig
git commit --allow-empty --message 'Fix it again'
! git commit --allow-empty --message 'Fixed it again'
cd ../..
rm -rf "proofr-test-*"
}

if echo "$0" | grep --quiet -v 'roundup'
then
it_matches_hook
it_sets_up_hook
it_matches_other_hook
it_sets_up_missing_hook
it_sets_up_exisiting_hook
it_does_not_match_no_hook
it_sets_up_hook_and_hook_works
fi

0 comments on commit 882383f

Please sign in to comment.