#!/bin/sh #$Id$ #Copyright (c) 2014-2020 Pierre Pronchery #This file is part of DeforaOS Devel scripts # #Redistribution and use in source and binary forms, with or without #modification, are permitted provided that the following conditions #are met: #1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. #2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # #THIS SOFTWARE IS PROVIDED BY THE EDGEBSD PROJECT AND CONTRIBUTORS #``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED #TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR #PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS #BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR #CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF #SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS #INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN #CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) #ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE #POSSIBILITY OF SUCH DAMAGE. #variables #executables GIT="git" SED="sed" SORT="sort" TOLOWER="_tolower" TR="tr" UNIQ="uniq" #settings GITWEB_URL= PREFIX="/usr/local" PROGNAME="deforaos-git-message" REDMINE_URL= SYSCONFDIR="$PREFIX/etc" #load local settings [ -f "$SYSCONFDIR/DeforaOS/$PROGNAME.conf" ] && . "$SYSCONFDIR/DeforaOS/$PROGNAME.conf" [ -f "$HOME/.config/DeforaOS/$PROGNAME.conf" ] && . "$HOME/.config/DeforaOS/$PROGNAME.conf" #functions #count_lines _count_lines() { lines_cnt=0 while read line; do lines_cnt=$((lines_cnt + 1)) done echo "$lines_cnt" } #error _error() { echo "$PROGNAME: $@" 1>&2 return 2 } #link _link_branch() { repository="$1" branch="$2" [ -n "$GITWEB_URL" ] && echo "$GITWEB_URL?p=${repository}.git;a=shortlog;h=refs/heads/$branch" [ -n "$REDMINE_URL" ] && echo "$REDMINE_URL/repository/${repository}/show?rev=$branch" | $TOLOWER } #link_commit _link_commit() { repository="$1" rev="$2" shortrev=$(_shorten 8 "$rev") [ -n "$GITWEB_URL" ] && echo "$GITWEB_URL?p=${repository}.git;a=commit;h=$shortrev" [ -n "$REDMINE_URL" ] && echo "$REDMINE_URL/repository/${repository}/revisions/$shortrev" | $TOLOWER } #message_post_commit _message_post_commit() { if [ $# -ne 0 ]; then _usage "post-commit" return $? fi while read oldrev newrev refname; do #XXX ignore errors _message_update "$refname" "$oldrev" "$newrev" done return 0 } #message_post_receive _message_post_receive() { if [ $# -ne 0 ]; then _usage "post-receive" return $? fi while read oldrev newrev refname; do #XXX ignore errors _message_update "$refname" "$oldrev" "$newrev" done return 0 } #message_update _message_update() { if [ $# -ne 3 ]; then _usage "update refname oldrev newrev" return $? fi refname="$1" oldrev="$2" newrev="$3" nullrev="0000000000000000000000000000000000000000" author="$GL_USER" [ -z "$author" ] && author="$USER" repository="${GL_REPO#DeforaOS/}" branch= type="push" #analyze the push message= [ -n "$repository" ] && message="$repository: " [ -n "$author" ] && message="$message$author" branch= case "$refname" in refs/heads/*) branch=${refname#refs/heads/} [ -n "$branch" ] && message="$message [$branch]" type="branch" ;; refs/tags/*) tag=${refname#refs/tags/} [ -n "$tag" ] && message="$message [$tag]" type="tag" ;; *) [ -n "$refname" ] && message="$message [$refname]" ;; esac if [ "$oldrev" = "$nullrev" ]; then echo "$message new $type at $(_shorten 8 "$newrev")" _link_commit "$repository" "$newrev" elif [ "$newrev" = "$nullrev" ]; then echo "$message $type deleted" else commit_cnt=0 all_files= base=$($GIT merge-base "$oldrev" "$newrev") revisions=$($GIT rev-list "${base}..${newrev}") type=$($GIT cat-file -t "$newrev") log= for revision in $revisions; do #$GIT cat-file commit "$revision" #obtain the first log message [ -z "$log" ] && log=$($GIT log -n 1 --oneline "$revision") #count the file alterations files=$($GIT log -n 1 --name-only --pretty=format:'' "$revision") all_files="$all_files$files" #count the number of commits commit_cnt=$((commit_cnt + 1)) done all_files=$(echo "$all_files" | $SED -e '/^$/d') files_cnt=$(echo "$all_files" | _count_lines) unique_files_cnt=$(echo "$all_files" | $SORT | $UNIQ | _count_lines) if [ $commit_cnt -eq 1 -a -n "$log" ]; then message="$message $log" elif [ $commit_cnt -lt 2 ]; then message="$message $commit_cnt $type pushed" else message="$message $commit_cnt ${type}s pushed" fi message="$message ($files_cnt" if [ $files_cnt -lt 2 ]; then message="$message alteration" else message="$message alterations" fi if [ $unique_files_cnt -lt 2 ]; then message="$message in $unique_files_cnt file)" else message="$message in $unique_files_cnt files)" fi if [ "$oldrev" != "$base" ]; then message="$message (force push)" fi echo "$message" if [ $commit_cnt -eq 1 ]; then _link_commit "$repository" "$newrev" elif [ -n "$branch" ]; then _link_branch "$repository" "$branch" fi fi return 0 } #shorten _shorten() { echo "$2" | $SED -e "s/^\\(.\\{$1\\}\\).*\$/\\1/" } #tolower _tolower() { $TR A-Z a-z } #usage _usage() { if [ $# -gt 0 ]; then echo "Usage: $PROGNAME $@" 1>&2 else echo "Usage: $PROGNAME hook [argument...]" 1>&2 fi return 1 } #main #parse options while getopts "O:" name; do case "$name" in O) export "${OPTARG%%=*}"="${OPTARG#*=}" ;; *) _usage exit $? ;; esac done shift $((OPTIND - 1)) if [ $# -eq 0 ]; then _usage exit $? fi hook="$1" shift case "$hook" in "post-commit") _message_post_commit "$@" exit $? ;; "post-receive") _message_post_receive "$@" exit $? ;; "update") _message_update "$@" exit $? ;; *) _error "$hook: Unknown hook" exit $? ;; esac