pre-receive-check-policy 8.26 KB
Newer Older
1
2
3
4
#!/bin/bash

# This script checks gnome.org policy about how people are supposed to
# use git; the intent of the policy is to keep people from shooting
Krzesimir Nowak's avatar
Krzesimir Nowak committed
5
# themselves in the foot.
6
7
8
9
10
11
12
13
14
#
# Eventually, we'd like to have an ability to override policy; one way
# it could work is that if you did 'git push --exec=force' and you
# were a member of the right group, then run-git-or-special-cmd
# would set an environment variable that this script would interpret.

# Used in some of the messages
server=git.gnome.org

15
16
17
18
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)

in_import() {
    test -e "$GIT_DIR/pending"
19
20
}

21
22
23
24
forced() {
    test -n "$GNOME_GIT_FORCE"
}

25
26
27
28
29
30
check_commit() {
    commit=$1

    email="$(git log $commit -1 --pretty=format:%ae)"
    case "$email" in
	*localhost.localdomain|*\(none\))
31
	    if ! in_import && ! forced ; then
32
33
34
35
36
37
		cat <<- EOF >&2
			---
			The commits you are trying to push contain the author email
			address '$email'. Please configure your
			username and email address. See:

38
			  https://wiki.gnome.org/Git/Help/AuthorEmail
39
40
41
42
43

			For instructions about how to do this and how to fix your
			existing commits.
			---
			EOF
44
45
46
		exit 1
	    fi
	    ;;
47
48
49
50
    esac

    subject="$(git log $commit -1 --pretty=format:%s)"
    if expr "$subject" : ".*Merge branch.*of.*\(git\|ssh\):" > /dev/null 2>&1; then
51
	if ! in_import && ! forced ; then
52
53
54
	    cat <<- EOF >&2
				---
				The commit:
55

56
				EOF
57
	    git log $commit -1 >&2
58
	    cat <<- EOF >&2
59

60
61
62
				Looks like it was produced by typing 'git pull' without the --rebase
				option when you had local changes. Running 'git  pull --rebase' now
				will fix the problem. Then please try, 'git push' again. Please see:
63

64
				  https://wiki.gnome.org/Git/Help/ExtraMergeCommits
65
66
				---
				EOF
67
	    exit 1
68
	fi
69
    fi
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

    body="$(git log $commit -1 --pretty=format:%b)"
    if expr "$body" : ".*FIXME: need commit message" > /dev/null 2>&1; then
	if ! in_import && ! forced ; then
	    cat <<- EOF >&2
				---
				The commit:

				EOF
	    git log $commit -1 >&2
	    cat <<- EOF >&2

				Was created by git-bz from a plain diff. Please edit the commit message
				to properly describe the commit using 'git commit --amend' or
				(for an older commit) 'git rebase -i'. Then try 'git push' again.
				EOF
	    exit 1
        fi
    fi

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
check_ref_update() {
    oldrev=$1
    newrev=$2
    refname=$3

    change_type=update
    if expr $oldrev : "^0\+$" > /dev/null 2>&1; then
	change_type=create
    fi

    if expr $newrev : "^0\+$" > /dev/null 2>&1; then
	if [ x$change_type = xcreate ] ; then
	    # Deleting an invalid ref, allow
	    return 0
	fi
	change_type=delete
    fi

    case $refname in
	refs/heads/*)
	    # Branch update
	    branchname=${refname#refs/heads/}

115
116
117
118
119
	    is_wip=false
	    case $branchname in
		wip/*) is_wip=true ;;
	    esac

120
	    range=
121
122
	    case $change_type in
		create)
123
124
125
126
127
128
129
130
		    if [ "x$branchname" = xHEAD ] ; then
			cat <<- EOF >&2
				---
				You are trying to push the branch 'HEAD'.
				---
				EOF
			exit 1
		    fi
131
		    range="$newrev"
132
133
134
135
136
137
138
		    ;;
		delete)
		    # We really don't like to allow deleting any branch, but
		    # people need to do it to clean up accidentally pushed
		    # branches. Deleting master, however, has no purpose other
		    # than getting around the no-fast-forward restrictions
		    if [ "x$branchname" = xmaster ] ; then
139
140
141
142
143
			cat <<- EOF >&2
				---
				You are trying to delete the branch 'master'.
				---
				EOF
144
			exit 1
145
146
147
		    fi
		    ;;
		update)
148
		    range="$oldrev..$newrev"
149
		    if [ "`git merge-base $oldrev $newrev`" != $oldrev ] && ! $is_wip && ! forced ; then
150
151
152
153
154
		        # Non-fast-forward update. Right now we have
		        # receive.denyNonFastforwards in the git configs for
		        # our repositories anyways, but catching it here would
		        # allow overriding without having to change the config
			# temporarily.
155
156
157
158
159
			cat <<- EOF >&2
				---
				You are trying to update the branch '$branchname' in a way that is not
				a fast-forward update. Please see:

160
				  https://wiki.gnome.org/Git/Help/NonFastForward
161
162
				---
				EOF
163
			exit 1
164
165
166
		    fi
		    ;;
	    esac
167
168
169
170

	    # For new commits introduced with this branch update, we want to run some
	    # checks to catch common mistakes.
	    #
171
	    # Expression here is same as in post-receive-notify-cia; we take
172
173
174
175
176
177
178
179
180
181
182
	    # all the branches in the repo, as "^/ref/heads/branchname", other than the
            # branch we are actualy committing to, and exclude commits already on those
            # branches from the list of commits between $oldrev and $newrev.

	    if [ -n "$range" ] ; then
		for merged in $(git rev-parse --symbolic-full-name --not --branches | \
                    egrep -v "^\^$refname$" | \
		    git rev-list --reverse --stdin "$range"); do
		    check_commit $merged
		done
	    fi
183
184
185
186
187
188
189
190
191
192
193
194
	    ;;
	refs/tags/*)
	    # Tag update
	    tagname=${refname#refs/tags/}

	    case $change_type in
		create)
		    object_type=`git cat-file -t $newrev`
		    case $object_type in
			commit)
			    # Lightweight tag; we allow an import containing these
			    # tags, but forbid them in general
195
			    if ! in_import && ! forced ; then
196
197
				cat <<- EOF >&2
					---
198
					You are trying to push the lightweight tag '$tagname'. You should either
Andrea Veri's avatar
Andrea Veri committed
199
					make use of a signed (-s) or annotated tag (-a) instead. More details at:
200

201
					  https://wiki.gnome.org/Git/Help/LightweightTags
202
203
					---
					EOF
204
				exit 1
205
206
207
208
			    fi
			    ;;
			tag)
			    # Annotated tag
209
210
211
212
213
214
215
216
					if [ "${tagname}" = "HEAD" ]; then
						cat <<- EOF >&2
							---
							You are trying to push a tag named '$tagname'. This is not allowed.
							---
							EOF
						exit 1
					fi
217
218
219
			    ;;
			*)
			    # git is happy to allow tagging random objects, we aren't
220
221
222
223
224
225
			    cat <<- EOF >&2
						---
						You are trying to push the tag '$tagname', which points to an object
						of type $object_type. (It should point to a commit or tag object.)
						---
						EOF
226
			    exit 1
227
228
229
230
231
232
233
			    ;;
		    esac
		    ;;
		delete)
		    # Deleting a tag is probably someone trying to work-around
		    # not being able to update a tag. Disallowing lightweight
		    # tags will cut down on accidentally pushing tags called 'list'
234
		    # or whatever. During import we allow the user to clean up
Krzesimir Nowak's avatar
Krzesimir Nowak committed
235
236
237
238
239
		    # accidentally pushed tags. An exception to above rule is
		    # deleting tag named HEAD. There are some projects which
		    # created such tag before rejecting its creation was added
		    # to policy.
		    if ! in_import && ! forced && [ 'x'"$tagname" != 'xHEAD' ] ; then
240
241
242
			cat <<- EOF >&2
				---
				You are trying to delete the tag '$tagname'.
243

244
				  https://wiki.gnome.org/Git/Help/TagUpdates
245
246
				---
				EOF
247
			exit 1
248
		    fi
249
250
		    ;;
		update)
251
		    if  ! forced ; then
252
253
254
			cat <<- EOF >&2
				---
				You are trying to replace the tag '$tagname' with a new tag. Please see:
255

256
				  https://wiki.gnome.org/Git/Help/TagUpdates
257
258
				---
				EOF
259
			exit 1
260
		    fi
261
262
263
264
265
		    ;;
	    esac
	    ;;
	refs/remotes/*)
	    # Remote tracking branch
266
267
268
	    cat <<- EOF >&2
				---
				You are trying to push the remote tracking branch:
269

270
				  $refname
271

272
273
274
				to $server.
				---
				EOF
275
	    exit 1
276
	    ;;
Ray Strode's avatar
Ray Strode committed
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
	refs/notes/*)
	    # notes (addendums to existing commits)
	    notename=${refname#refs/notes/}

	    case $change_type in
		create)
		    ;;
		delete)
		    if [ "x$notename" = xcommits ] ; then
			cat <<- EOF >&2
				---
				You are trying to delete the note 'commits'.
				---
				EOF
			exit 1
		    fi
		    ;;
		update)
		    if [ "`git merge-base $oldrev $newrev`" != $oldrev ] && ! forced ; then
		        # Non-fast-forward update. Right now we have
		        # receive.denyNonFastforwards in the git configs for
		        # our repositories anyways, but catching it here would
		        # allow overriding without having to change the config
			# temporarily.
			cat <<- EOF >&2
				---
				You are trying to update the note '$notename' in a way that is not
				a fast-forward update. Please see:

Andrea Veri's avatar
Andrea Veri committed
306
				  https://wiki.gnome.org/Git/Help/NonFastForward
Ray Strode's avatar
Ray Strode committed
307
308
309
310
311
312
313
				---
				EOF
			exit 1
		    fi
		    ;;
	    esac
	    ;;
314
315
	*)
	    # Something else
316
317
318
	    cat <<- EOF >&2
				---
				You are trying to push the ref:
319

320
				  $refname
321

Krzesimir Nowak's avatar
Krzesimir Nowak committed
322
				to $server. This is not a branch or tag.
323
324
				---
				EOF
325
	    exit 1
326
327
328
329
330
331
332
	    ;;
    esac

    return 0
}

if [ $# = 3 ] ; then
333
    check_ref_update $@
334
335
else
    while read oldrev newrev refname; do
336
	check_ref_update $oldrev $newrev $refname
337
338
339
340
    done
fi

exit 0