#!/usr/bin/env bash #============================================================================= # Copyright 2010-2012 Kitware, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #============================================================================= . "${BASH_SOURCE%/*}/hooks-config.bash" # Start with project-specific hook. hooks_start commit-msg "$@" # Prepare a copy of the message: # - strip comment lines # - stop at "diff --git" (git commit -v) commit_msg="$GIT_DIR/COMMIT_MSG" sed -n -e '/^#/d' -e '/^diff --git/q' -e 'p;d' "$1" > "$commit_msg" die_advice=' To continue editing, run the command git commit -e -F '"$commit_msg"' (assuming your working directory is at the top).' die() { echo 'commit-msg hook failure' 1>&2 echo '-----------------------' 1>&2 echo '' 1>&2 echo "$@" 1>&2 test -n "$die_advice" && echo "$die_advice" 1>&2 exit 1 } #----------------------------------------------------------------------------- # Check the commit message layout with a simple state machine. msg_is_merge() { echo "$line" | grep "^Merge " >/dev/null 2>&1 } msg_is_revert() { echo "$line" | grep "^Revert " >/dev/null 2>&1 } msg_first() { len=$(echo -n "$line" | wc -c) if test $len -eq 0; then # not yet first line return elif test $len -lt 8; then die 'The first line must be at least 8 characters: -------- '"$line"' --------' elif test $len -gt 78 && ! msg_is_merge && ! msg_is_revert; then die 'The first line may be at most 78 characters: ------------------------------------------------------------------------------ '"$line"' ------------------------------------------------------------------------------' elif echo "$line" | grep "^[ ]\|[ ]$" >/dev/null 2>&1; then die 'The first line may not have leading or trailing space: ['"$line"']' else # first line okay state=second fi } msg_second() { if test "x$line" != "x"; then die 'The second line must be empty: '"$line" else state=rest fi } msg_rest() { if echo "$line" | grep -q "^Change-Id:"; then state=gerrit fi } msg_gerrit() { test "x$line" = "x" && return echo "$line" | grep -q '^[A-Za-z0-9-][A-Za-z0-9-]*:' && return die 'The Change-Id line must appear in a footer at the bottom.' } # Pipe commit message into the state machine. state=first cat "$commit_msg" | while IFS='' read line; do msg_$state || break done && rm -f "$commit_msg" || exit 1 die_advice='' # No more temporary message file. #----------------------------------------------------------------------------- # Optionally run Gerrit's commit-msg hook to add a Change-Id line. gerrit_advice() { gerrits=$(git config -l |grep '^remote\.[^=]\+url=.*review.*$') test "x$gerrits" != "x" || return 0 echo 'Some config values look like Gerrit Code Review URLs:' echo '' echo "$gerrits" | sed 's/^/ /' echo ' This hook can automatically add a "Change-Id" footer to commit messages to make interaction with Gerrit easier. To enable this feature, run git config hooks.GerritId true Then run "git commit --amend" to fix this commit. Otherwise, run git config hooks.GerritId false to disable the feature and this message.' } gerrit_error() { die 'non-bool config value hooks.GerritId = '"$hooks_GerritId" } gerrit_hook() { "$HOOKS_DIR/gerrit/commit-msg" "$@" || die 'gerrit/commit-msg failed' } hooks_GerritId=$(git config --get hooks.GerritId) case "$hooks_GerritId" in 'true') gerrit_hook "$@" ;; 'false') ;; '') gerrit_advice ;; *) gerrit_error ;; esac #----------------------------------------------------------------------------- # Chain to project-specific hook. hooks_chain commit-msg "$@"