aboutsummaryrefslogblamecommitdiffstats
path: root/scripts/pre-push
blob: 7da1f575db358311f6930d25e8b68009c4e7ab2a (plain) (tree)























                                                                              


                                                         
                                

                                      

                                                       
                                                    




                                                                












                                                                                                                                    







                                             







                          


                                                                                               
              



                                                                               
               











                                                        
                  



                                                                
                   



                                            
                  



                                                                                                 
                   






                                                                                                              
                          



                                                                                        
                           



                                                                      
                          





                                                                                           
                           



                                                                        
                          



                                                                            
                           



                                                                                                                                 
                                                                         

                                                                                                                                  
                        
                              




                                                                                                                
                               

                              
                              

                                       
                                                                                     

                                                                            
                                                                                                           


                                                           
                               

                              


                                                                                                                                           
                          




                                                                                                       
                           














                                                                                                                              
                          




                                                                                                     
                           




                                                                       
                          



                                                                                                                       
                           




                                                                                 
                          



                                                                                                                         
                           


                          
                            
                                            









                                                 
                          



                                                                       
                           

                          

                                             
                          




                                                                         
                           




                                                
                      



                                                                                             
                       



                                            
                      



                                                                                       
                       


                      
                      



                                                                                         
                       



                      













                                                                                                                                                 




                                                           
 
#!/bin/sh

# This is a git pre-push hook script.
# It limits what you can push toward https://github.com/erlang/otp.git
#
# To activate, make a copy as .git/hooks/pre-push in your repo.

# Called by "git push"
# after it has checked the remote status, but before anything has been
# pushed.  If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
#   <local ref> <local sha1> <remote ref> <remote sha1>
#

# Bump this version to give users an update notification.
PRE_PUSH_SCRIPT_VERSION=1

NEW_RELEASES="22 21 20 19 18 17"
OLD_RELEASES="r16 r15 r14 r13"
RELEASES="$NEW_RELEASES $OLD_RELEASES"

# First commit on master, not allowed in other branches
MASTER_ONLY=f633fe962ea7078c32f8c81d34950c0ebce0f472

# Number of commits and files allowed in one push by this script
NCOMMITS_MAX=100
NFILES_MAX=100


# Example testing this script for "git push upstream OTP-20.3.8.2":
#
#> null=0000000000000000000000000000000000000000
#> echo "refs/tags/OTP-20.3.8.2 dummysha refs/tags/OTP-20.3.8.2 $null" | scripts/pre-push upstream https://github.com/erlang/otp.git

# Example to test "git push upstream master"
#
#> local_sha=`git rev-parse master`
#> remote_sha=`git rev-parse upstream/master`
#> echo "refs/heads/master $local_sha refs/heads/master $remote_sha" | scripts/pre-push upstream https://github.com/erlang/otp.git


remote="$1"
url="$2"

null=0000000000000000000000000000000000000000

#echo "pre-push hook: remote=$remote"
#echo "pre-push hook: url=$url"

red_on() {
    printf '%b' "\033[31m"
}

red_off() {
    printf '%b' "\033[0m"
}

if [ "$url" = 'https://github.com/erlang/otp.git' -o "$url" = '[email protected]:erlang/otp.git' ]
then
    if [ $remote = "$url" ]; then
	red_on
        echo "$0 says:"
        echo "***"
        echo "*** Push to $url without using a named remote is NOT ALLOWED!!!!"
        echo "***"
	red_off
        exit 1
    fi
    IFS=' '
    while read local_ref local_sha remote_ref remote_sha
    do
	#echo "pre-push hook:  local_ref=$local_ref"
	#echo "pre-push hook: remote_ref=$remote_ref"
	#echo "pre-push hook:  local_sha=$local_sha"
	#echo "pre-push hook: remote_sha=$remote_sha"

	if [ "$local_sha" = $null ]
	then
	    red_on
            echo "$0 says:"
            echo "***"
            echo "*** DELETE push to '$remote' NOT ALLOWED!!!!!"
            echo "***"
	    red_off
            exit 1
	fi
	if [ "$local_ref" != "$remote_ref" ]
	then
	    red_on
	    echo "$0 says:"
	    echo "***"
	    echo "*** RENAME push: $local_ref pushed as $remote_ref to '$remote' NOT ALLOWED!!!!"
	    echo "***"
	    red_off
	    exit 1
	fi
	case "$remote_ref" in
            refs/heads/master | refs/heads/maint | refs/heads/maint-[0-9][0-9] | refs/heads/maint-r[0-9][0-9])
		branch=${remote_ref#refs/heads/}
                if [ "$remote_sha" = $null ]
                then
		    red_on
                    echo "$0 says:"
		    echo "***"
		    echo "*** UNKNOWN BRANCH: '$branch' does not exist at '$remote'!!!!"
		    echo "***"
		    red_off
		    exit 1
                fi
		if ! git log -1 --oneline $remote_sha > /dev/null 2>&1
		then
		    red_on
		    echo "$0 says:"
		    echo "***"
		    echo "*** The top of '$branch' at '$remote' ($remote_sha)"
		    echo "*** does not exist locally!!!"
		    echo "*** You probably need to refresh local '$branch' and redo merge."
		    echo "***"
		    red_off
		    exit 1
		fi
		if ! git merge-base --is-ancestor $remote_sha $local_sha
		then
		    red_on
		    echo "$0 says:"
		    echo "***"
		    echo "*** FORCE push branch to '$remote' NOT ALLOWED!!!"
		    echo "***"
		    red_off
		    exit 1
		fi
                if [ $remote_ref != refs/heads/master -a "$MASTER_ONLY" ] && git merge-base --is-ancestor $MASTER_ONLY $local_sha
                then
		    THIS_SCRIPT=`git rev-parse --git-path hooks/pre-push`
		    THIS_SCRIPT=`realpath $THIS_SCRIPT`
		    if git show refs/remotes/$remote/master:scripts/pre-push | diff -q --context=0 $THIS_SCRIPT - > /dev/null 2>&1
		    then
			red_on
			echo "$0 says:"
			echo "***"
			echo "*** INVALID MERGE: Commit $MASTER_ONLY should not be reachable from '$branch'!!!!"
			echo "***                You have probably merged master into '$branch' by mistake"
			echo "***"
			red_off
			exit 1
		    else
			red_on
			echo "$0 says:"
			echo "***"
			echo "*** The pre-push hook of this OTP repo needs updating."
			echo "*** Do it by executing the following command:"
			echo "***"
			echo "***     git show refs/remotes/$remote/master:scripts/pre-push > $THIS_SCRIPT"
			echo "***"
			echo "*** And then retry the push."
			echo "***"
			red_off
			exit 1
		    fi
                fi
                if [ ${remote_ref#refs/heads/maint-} != $remote_ref ] && git merge-base --is-ancestor refs/remotes/$remote/maint $local_sha
                then
		    red_on
		    echo "$0 says:"
		    echo "***"
		    echo "*** INVALID MERGE: Branch maint should not be reachable from '$branch'!!!!"
                    echo "***                You have probably merged maint into '$branch' by mistake."
		    echo "***"
		    red_off
		    exit 1
                fi
                if [ $remote_ref = refs/heads/maint -o $remote_ref = refs/heads/master ]; then
                    for x in $RELEASES; do
                        if ! git merge-base --is-ancestor refs/remotes/$remote/maint-$x $local_sha; then
                            echo "$0 says:"
		            echo "***"
		            echo "*** WARNING: Branch '$remote/maint-$x' is not reachable from '$branch'!!!!"
                            echo "***          Someone needs to merge 'maint-$x' forward and push."
		            echo "***"
                        fi
                    done
                fi
                if [ $remote_ref = refs/heads/master ] && ! git merge-base --is-ancestor refs/remotes/$remote/maint $local_sha
                then
		    red_on
                    echo "$0 says:"
		    echo "***"
		    echo "*** INVALID PUSH: Branch '$remote/maint' is not reachable from master!!!!"
                    echo "***               Someone needs to merge maint forward to master and push."
		    echo "***"
		    red_off
		    exit 1
                fi
		NCOMMITS=`git rev-list --count $remote_sha..$local_sha`
		if [ $NCOMMITS -gt $NCOMMITS_MAX ]
		then
		    red_on
		    echo "$0 says:"
		    echo "***"
		    echo "*** HUGE push: $NCOMMITS commits (> $NCOMMITS_MAX) to '$branch' at '$remote' NOT ALLOWED!!!!"
		    echo "***"
		    red_off
		    exit 1
		fi
		NFILES=`git diff --name-only $remote_sha $local_sha | wc --lines`
		if [ $NFILES -gt $NFILES_MAX ]
		then
		    red_on
		    echo "$0 says:"
		    echo "***"
		    echo "*** HUGE push: $NFILES changed files (> $NFILES_MAX) to '$branch' at '$remote' NOT ALLOWED!!!!"
		    echo "***"
		    red_off
		    exit 1
		fi
		;;
	    refs/tags/OTP-*)
		tag=${remote_ref#refs/tags/}
		REL="UNKNOWN"
		for x in $NEW_RELEASES; do
		    if [ ${tag#OTP-$x.} != $tag ]
		    then
			REL=$x
			break
		    fi
		done
		if [ $REL = "UNKNOWN" ]
		then
		    red_on
		    echo "$0 says:"
		    echo "***"
		    echo "*** Unknown OTP release number in tag '$tag'"
		    echo "***"
		    red_off
		    exit 1
		fi
		if [ "$remote_sha" != $null ]
		then
		    red_on
		    echo "$0 says:"
		    echo "***"
		    echo "*** FORCE push tag to '$remote' NOT ALLOWED!!!"
		    echo "*** Tag '$tag' already exists at '$remote'."
		    echo "***"
		    red_off
		    exit 1
		fi
		;;
            refs/heads/*)
		branch=${remote_ref#refs/heads/}
		red_on
		echo "$0 says:"
		echo "***"
		echo "*** UNKNOWN branch name: '$branch' pushed to '$remote' NOT ALLOWED!!!!"
		echo "***"
		red_off
		exit 1
		;;
	    refs/tags/*)
		tag=${remote_ref#refs/tags/}
		red_on
		echo "$0 says:"
		echo "***"
		echo "*** UNKNOWN tag name: '$tag' pushed to '$remote' NOT ALLOWED!!!!"
		echo "***"
		red_off
		exit 1
		;;
	    *)
		red_on
		echo "$0 says:"
		echo "***"
		echo "*** STRANGE ref: '$remote_ref' pushed to '$remote' NOT ALLOWED!!!!"
		echo "***"
		red_off
		exit 1
		;;
	esac
    done

    echo "$0: OK"

    THIS_SCRIPT=`git rev-parse --git-path hooks/pre-push`
    THIS_SCRIPT=`realpath $THIS_SCRIPT`
    if git show refs/remotes/$remote/master:scripts/pre-push | diff --context=0 $THIS_SCRIPT - | grep -q PRE_PUSH_SCRIPT_VERSION > /dev/null 2>&1
    then
	echo ""
	echo "NOTE: There is a newer version of the pre-push hook in this OTP repo."
	echo "      You can install it by executing the following command:"
	echo
	echo "     git show refs/remotes/$remote/master:scripts/pre-push > $THIS_SCRIPT"
	echo
    fi
else
    echo "$0: No checks done for remote '$remote' at $url."
fi

exit 0