summaryrefslogtreecommitdiff
path: root/git_hooks/pre-commit
blob: bc98c81582dacd0232562a822655d3e689712abd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/bin/bash
# Auto format changed java files using google-java-format.
# To install, copy this file into $repo/.git/hooks and remove the .sh extension.
# Download the google-java-format JAR from
#   https://github.com/google/google-java-format
# A more mature implementation of this would be a plugin for Yelp's pre-commit library:
#   http://pre-commit.com/
echo "Running auto-formatter for any changed Java files"
echo "(formatting changes will be automatically added to your commit)"

# Grab root directory to help with creating an absolute path for changed files.
root_dir="$(git rev-parse --show-toplevel)"
[ -d "${root_dir}" ] || exit 1

# TODO add your path here.
jar_base_dir="git_hooks/"

# To avoid any unexpected behavior, we need to "stash" any unstaged changes.
# We could use "git stash" but the situation gets complicated because we
# need to make additional changes with the formatter.
# Here's how we could do this if we didn't need to make additional changes:
#   http://stackoverflow.com/a/20480591
# But since we do, we follow the same general pattern as the "pre-commit" lib:
#   https://github.com/pre-commit/pre-commit/blob/master/pre_commit/staged_files_only.py#L15
# Basically we just diff the unstaged changes, store the patch, and apply it later.
# In the future, we should consider migrating to using that library.
staged_changes_diff=$(mktemp -t format_patch)
git diff --ignore-submodules --binary --exit-code --no-color > $staged_changes_diff
if [ $? -eq 1 ]; then 
    echo "Found unstaged changes, storing in ${staged_changes_diff}"
    echo "Clearing unstaged changes for formatting, will restore after formatting."
    git checkout -- ${root_dir}
    stored_staged_changes=true
else
    stored_staged_changes=false
fi

formatter_jar="${root_dir}/${jar_base_dir}/google-java-format-1.6-SNAPSHOT-all-deps.jar"
formatter_cmd="java -jar ${formatter_jar}"
# Format file in-place and use 4-space style (AOSP).
formatter_args="--replace --aosp"

# filter=ACMR shows only added, changed, modified, or renamed files.
# Get only java files and prepend the root directory to make the paths absolute.
# Only format files in src/main/java and src/test/java (src/test/test-project contains java files that need to be left alone)
changed_java_files=($(git diff --cached --name-only --diff-filter=ACMR src/main/java src/test/java \
    | grep ".*java$" \
    | sed "s:^:${root_dir}/:"))
# If we have changed java files, format them!
if [ ${#changed_java_files[@]} -gt 0 ]; then
    # Do the formatting, stage the changes, and print out which files were changed.
    eval ${formatter_cmd} ${formatter_args} "${changed_java_files[@]}"
    git add "${changed_java_files[@]}"
    echo "${changed_java_files[@]}" | xargs basename | sed "s/^/	Formatting: /"
fi

echo "Finished formatting."

if $stored_staged_changes ; then
    echo "Restoring unstaged changes"
    git apply "${staged_changes_diff}"

    if [ $? -eq 1 ]; then
        echo "Shoot! We failed to re-apply your unstaged changes."
        echo "The patch for these changes is preserved at ${staged_changes_diff}"
    fi
fi