#!C:/Program\ Files/Git/usr/bin/sh.exe # This pre-commit hook checks, if the SQL files to be committed have a valid script version defined. # If not, the file name and/or the update statement within the script are replaced/added. # 1. Make sure, that the repo is up-to-date before checking echo "Pulling the latest changes before detecting the latest script version.." git pull # 2. Get the commit to check against if git rev-parse --verify HEAD >/dev/null 2>&1 then against=HEAD else # Initial commit: diff against an empty tree object against=$(git hash-object -t tree /dev/null) fi # 3. If you want to allow non-ASCII filenames set this variable to true. allownonascii=$(git config --bool hooks.allownonascii) # 4. Redirect output to stderr.# exec 1>&2 # 5. Cross platform projects tend to avoid non-ASCII filenames. In addition, we do not allow any blanks within the file names. if [ "$allownonascii" != "true" ] && test $(git diff --cached --name-only --diff-filter=A -z $against | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 then cat <<\EOF Error: Attempt to add a non-ASCII file name. This can cause problems if you want to work with people on other platforms. To be portable it is advisable to rename the file. If you know what you are doing you can disable this check using: git config hooks.allownonascii true EOF exit 1 fi # 6. If there are whitespace errors, print the offending file names and fail. exec git diff-index --check --cached $against -- ### # Auto-generates / sets the correct script version of each script. # # The version stated in the file name is considered as default, so the version stated within the file must be equal to this. # -> The version within the script will be replaced by the version in the file name. # ### # Get all staged files OUTPUT=$(git diff --name-only --staged) # Each script number must be at least '1' NR=1 # By default, no info should be displayed INFO="\n" SHOWINFO=0 # Checks on correct version format PATTERN_DATE="'[0-9]{6}[0-9]*'" # Checks on 6 digits (date) + n continuous numbers (#script of this day), e.g. 19081299 PATTERN_SCRIPT="^DB_V_[0-9]{6}[0-9]*[\.]sql$" PATTERN_SQL="^.*[\.]sql$" # Get the current date and format it to fit our version formatting rules SCRIPTDATE=$(date +'%y%m%d') SAVEIFS=$IFS IFS=$(echo -en "\n\b") for FILE in $OUTPUT do if [[ $FILE =~ $PATTERN_SQL ]] then # Rename the file that it matches our internal rules. # Only adjust script version if it doesn't follow the pattern "DB_V_yymmddc" [c=counter] if ! [[ $FILE =~ $PATTERN_SCRIPT ]] then # Keep generating filenames with increasing counter for the current day until we found a scriptname which isn't taken yet while true do SCRIPTNAME=DB_V_$SCRIPTDATE$NR.sql if [ ! -f $SCRIPTNAME ] then break; fi ((NR++)) done mv $FILE $SCRIPTNAME HASH=$(git hash-object -w $SCRIPTNAME) # Use file hash to identify the staged file so it will be marked as renamed git update-index --add --cacheinfo 100644 $HASH $FILE # Create tmp file to notify post-commit hook to amend-commit the renamed files SHOWINFO=1 INFO="$INFO \n\nYour SQL script '$FILE' has been renamed to '$SCRIPTNAME'." else # File name is valid SCRIPTNAME=$FILE # Extract date + version number from scriptName and set it as the version to be compared PATTERN_DATE_FILENAME="[0-9]{6}[0-9]*" DATE_FILENAME=$(echo "$SCRIPTNAME" | egrep -o $PATTERN_DATE_FILENAME | head -n1) fi ### # Set version within script for 'print_sth' procedure or add it, if missing ### # 1. Find a line that starts with a 'script version definition' (and is not a comment or of any other type) lineBegin="^" sBase="execute procedure print_sth(" # Find the BEGIN of the version string in file sBaseFound=$(grep -c -i "$lineBegin$sBase" "$SCRIPTNAME") # Find the complete version string in file. # If there was a valid version string found in the file name before, use this one for the comparison. if ! [[ $DATE_FILENAME = '' ]] then newVersion=$sBase"'$DATE_FILENAME', 0);" sCompleteFound=$(grep -c -i "$lineBegin$sBase'$DATE_FILENAME'" "$SCRIPTNAME") else sCompleteFound=$(grep -c -i "$lineBegin$sBase$PATTERN_DATE" "$SCRIPTNAME") newVersion=$sBase"'$SCRIPTDATE$NR', 0);" fi # No script version definition was found: # Append the script version at the end of the file. if [[ $sBaseFound = 0 ]] then sed -i '${s/$/'"\n\n$newVersion"'/}' $SCRIPTNAME sed -i '$acommit;' $SCRIPTNAME fi # An invalid script version definition was found: # Replace the existing definition with a valid one. if [[ $sBaseFound > 0 ]] && [[ $sCompleteFound = 0 ]] then sed -i "s/$lineBegin$sBase.*/$newVersion/g" $SCRIPTNAME fi # If a change was applied: # Add/reset the appropriate files (stage them again) and inform the user if [[ $sBaseFound = 0 ]] || [[ $sCompleteFound = 0 ]] then SHOWINFO=1 INFO="$INFO \n\nFurther information:\nThe 'update systeminfo' command within your script '$FILE' was invalid or missing." if ! [[ $DATE_FILENAME = '' ]] then INFO="$INFO \nIt has automatically been set to the version that is stated in the file name ($DATE_FILENAME)." else INFO="$INFO \nIt has automatically been set to the first version that isn't used ($SCRIPTDATE$NR)." fi INFO="$INFO \nPlease try to commit your changes again.\n" # Add the renamed script to the staging area. # This is necessary because we applied changes to the file contents git add $SCRIPTNAME # If file was renamed before: # Remove the renamed file from the staging area if [ $SCRIPTNAME != $FILE ] then git reset HEAD $FILE fi fi fi done IFS=$SAVEIFS # Show info only if set before. If true, the hook prevents git from continuing its processing. if [ $SHOWINFO = 1 ] then echo -e $INFO exit 1 fi