summaryrefslogtreecommitdiff
path: root/scripts/git/pre-push.git-hook
blob: 1b88f1d5d6383a5058ab976669317d985f1880f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env bash

# git pre-push hook script to:
# 0) Call the pre-commit hook, if it is available
# 1) prevent "fixup!" and "squash!" commit from ending up in master, release-*
#    or maint-*
# 2) Disallow pushing branches other than master, release-*
#    and maint-* to origin (e.g. gitweb.torproject.org)
#
# To install this script, copy it into .git/hooks/pre-push path in your
# local copy of git repository. Make sure it has permission to execute.
# Furthermore, make sure that TOR_UPSTREAM_REMOTE_NAME environment
# variable is set to local name of git remote that corresponds to upstream
# repository on e.g. git.torproject.org.
#
# The following sample script was used as starting point:
# https://github.com/git/git/blob/master/templates/hooks--pre-push.sample

# Are you adding a new check to the git hooks?
#  - Common checks belong in the pre-commit hook
#  - Push-only checks belong in the pre-push hook

echo "Running pre-push hook"

z40=0000000000000000000000000000000000000000

upstream_name=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"}

workdir=$(git rev-parse --show-toplevel)

remote="$1"
remote_name=$(git remote --verbose | grep "$2" | awk '{print $1}' | head -n 1)


ref_is_upstream_branch() {
        if [ "$1" == "refs/heads/master" ] ||
                [[ "$1" == refs/heads/release-* ]] ||
                [[ "$1" == refs/heads/maint-* ]]
        then
                return 1
        fi
}

# shellcheck disable=SC2034
while read -r local_ref local_sha remote_ref remote_sha
do
	if [ "$local_sha" = $z40 ]
	then
		# Handle delete
		:
	else
		if [ "$remote_sha" = $z40 ]
		then
			# New branch, examine commits not in master
			range="master...$local_sha"
		else
			# Update to existing branch, examine new commits
			range="$remote_sha..$local_sha"
		fi

        # Call the pre-commit hook for the common checks, if it is executable
        # Only check the files newly modified in this branch
        CHECK_FILTER="git diff --name-only --diff-filter=ACMR $range"
        # Use the appropriate owned tor source list to filter the changed files
        if [ -d src/lib ]; then
            # This is the layout in 0.3.5
            CHECK_FILES="$($CHECK_FILTER \
                               src/lib/*/*.[ch] \
                               src/core/*/*.[ch] \
                               src/feature/*/*.[ch] \
                               src/app/*/*.[ch] \
                               src/test/*.[ch] \
                               src/test/*/*.[ch] \
                               src/tools/*.[ch] \
                          )"
        elif [ -d src/common ]; then
            # This was the layout before 0.3.5
            CHECK_FILES="$($CHECK_FILTER \
                               src/common/*/*.[ch] \
                               src/or/*/*.[ch] \
                               src/test/*.[ch] \
                               src/test/*/*.[ch] \
                               src/tools/*.[ch]
                          )"
        fi

        # We want word splitting here, because file names are space separated
        # shellcheck disable=SC2086
        if ! "$workdir/"scripts/git/pre-commit.git-hook $CHECK_FILES; then
            exit 1
        fi

        if [[ "$remote_name" != "$upstream_name" ]]; then
            echo "Not pushing to upstream - refraining from further checks"
            continue
        fi


                if (ref_is_upstream_branch "$local_ref" == 0 ||
                        ref_is_upstream_branch "$remote_ref"  == 0) &&
                        [ "$local_ref" != "$remote_ref" ]
                then
                        if [ "$remote" == "origin" ]
                        then
                                echo >&2 "Not pushing: $local_ref to $remote_ref"
			        echo >&2 "If you really want to push this, use --no-verify."
                                exit 1
                        else
                                continue
                        fi
                fi

                # Check for fixup! commit
                commit=$(git rev-list -n 1 --grep '^fixup!' "$range")
		if [ -n "$commit" ]
		then
			echo >&2 "Found fixup! commit in $local_ref, not pushing"
			echo >&2 "If you really want to push this, use --no-verify."
			exit 1
		fi

                # Check for squash! commit
                commit=$(git rev-list -n 1 --grep '^squash!' "$range")
		if [ -n "$commit" ]
		then
			echo >&2 "Found squash! commit in $local_ref, not pushing"
			echo >&2 "If you really want to push this, use --no-verify."
			exit 1
		fi
	fi
done

exit 0