| #!/bin/sh |
| |
| # This hook automatically adds a Gerrit Change-ID to commit messages. |
| |
| # From Gerrit Code Review 2.11-rc1-208-g79f5f81 |
| # |
| # Part of Gerrit Code Review (http://code.google.com/p/gerrit/) |
| # |
| # Copyright (C) 2009 The Android Open Source Project |
| # |
| # 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. |
| # |
| |
| unset GREP_OPTIONS |
| |
| CHANGE_ID_AFTER="Bug|Issue" |
| MSG="$1" |
| |
| # Check for, and add if missing, a unique Change-Id |
| # |
| add_ChangeId() { |
| clean_message=$(sed -e ' |
| /^diff --git .*/{ |
| s/// |
| q |
| } |
| /^Signed-off-by:/d |
| /^#/d |
| ' "$MSG" | git stripspace) |
| if test -z "$clean_message" |
| then |
| return |
| fi |
| |
| if test "false" = "$(git config --bool --get gerrit.createChangeId)" |
| then |
| return |
| fi |
| |
| # Does Change-Id: already exist? if so, exit (no change). |
| if grep -i '^Change-Id:' "$MSG" >/dev/null |
| then |
| return |
| fi |
| |
| id=$(_gen_ChangeId) |
| T="$MSG.tmp.$$" |
| AWK=awk |
| if [ -x /usr/xpg4/bin/awk ]; then |
| # Solaris AWK is just too broken |
| AWK=/usr/xpg4/bin/awk |
| fi |
| |
| # How this works: |
| # - parse the commit message as (textLine+ blankLine*)* |
| # - assume textLine+ to be a footer until proven otherwise |
| # - exception: the first block is not footer (as it is the title) |
| # - read textLine+ into a variable |
| # - then count blankLines |
| # - once the next textLine appears, print textLine+ blankLine* as these |
| # aren't footer |
| # - in END, the last textLine+ block is available for footer parsing |
| $AWK ' |
| BEGIN { |
| # while we start with the assumption that textLine+ |
| # is a footer, the first block is not. |
| isFooter = 0 |
| footerComment = 0 |
| blankLines = 0 |
| } |
| |
| # Skip lines starting with "#" without any spaces before it. |
| /^#/ { next } |
| |
| # Skip the line starting with the diff command and everything after it, |
| # up to the end of the file, assuming it is only patch data. |
| # If more than one line before the diff was empty, strip all but one. |
| /^diff --git / { |
| blankLines = 0 |
| while (getline) { } |
| next |
| } |
| |
| # Count blank lines outside footer comments |
| /^$/ && (footerComment == 0) { |
| blankLines++ |
| next |
| } |
| |
| # Catch footer comment |
| /^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) { |
| footerComment = 1 |
| } |
| |
| /]$/ && (footerComment == 1) { |
| footerComment = 2 |
| } |
| |
| # We have a non-blank line after blank lines. Handle this. |
| (blankLines > 0) { |
| print lines |
| for (i = 0; i < blankLines; i++) { |
| print "" |
| } |
| |
| lines = "" |
| blankLines = 0 |
| isFooter = 1 |
| footerComment = 0 |
| } |
| |
| # Detect that the current block is not the footer |
| (footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) { |
| isFooter = 0 |
| } |
| |
| { |
| # We need this information about the current last comment line |
| if (footerComment == 2) { |
| footerComment = 0 |
| } |
| if (lines != "") { |
| lines = lines "\n"; |
| } |
| lines = lines $0 |
| } |
| |
| # Footer handling: |
| # If the last block is considered a footer, splice in the Change-Id at the |
| # right place. |
| # Look for the right place to inject Change-Id by considering |
| # CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first, |
| # then Change-Id, then everything else (eg. Signed-off-by:). |
| # |
| # Otherwise just print the last block, a new line and the Change-Id as a |
| # block of its own. |
| END { |
| unprinted = 1 |
| if (isFooter == 0) { |
| print lines "\n" |
| lines = "" |
| } |
| changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):" |
| numlines = split(lines, footer, "\n") |
| for (line = 1; line <= numlines; line++) { |
| if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) { |
| unprinted = 0 |
| print "Change-Id: I'"$id"'" |
| } |
| print footer[line] |
| } |
| if (unprinted) { |
| print "Change-Id: I'"$id"'" |
| } |
| }' "$MSG" > "$T" && mv "$T" "$MSG" || rm -f "$T" |
| } |
| |
| _gen_ChangeIdInput() { |
| echo "tree $(git write-tree)" |
| if parent=$(git rev-parse "HEAD^0" 2>/dev/null) |
| then |
| echo "parent $parent" |
| fi |
| echo "author $(git var GIT_AUTHOR_IDENT)" |
| echo "committer $(git var GIT_COMMITTER_IDENT)" |
| echo |
| printf '%s' "$clean_message" |
| } |
| |
| _gen_ChangeId() { |
| _gen_ChangeIdInput | |
| git hash-object -t commit --stdin |
| } |
| |
| add_ChangeId |