| #!/bin/sh | |
| # From Gerrit Code Review 2.13.5-2617-gba50ae91fd | |
| # | |
| # Part of Gerrit Code Review (https://www.gerritcodereview.com/) | |
| # | |
| # 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|Depends-On|Issue|Test|Feature|Fixes|Fixed" | |
| 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 | |
| # Do not add Change-Id to temp commits | |
| if echo "$clean_message" | head -1 | grep -q '^\(fixup\|squash\)!' | |
| 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 | |
| # Get core.commentChar from git config or use default symbol | |
| commentChar=`git config --get core.commentChar` | |
| commentChar=${commentChar:-#} | |
| # 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 commentChar without any spaces before it. | |
| /^'"$commentChar"'/ { 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 |