-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathupdate-stable
executable file
·109 lines (97 loc) · 3.13 KB
/
update-stable
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
#!/bin/bash
#
# This enforces stable moving in approved ways.
#
# Specifically:
#
# * stable must move by only 1 commit-per-push
# * the stable commit must have 2 and only 2 parents
# * The first parent must be the previous stable commit
# * The second parent is the tip of the candidate branch being released
# * the stable commit must have the same contents as the candidate tip
# * Any merge conflicts should have been resolved in the candidate tip
# by pulling stable into the candidate and having qa/tests done--pulling
# candidate into stable should then apply cleanly
#
# For DAG aesthetics, we prefer stable only moving in the approved way,
# which is via empty (no change) merge commits. The rationale is that
# in the DAG we want a simple, one-commit move from each release to the
# next.
#
# We started out with:
#
# * -- A stable
# \ \
# \ * -- * -- B topic1
# \ /
# * -- * -- * topic2
#
# And then publishing stable was a matter of fast-forwarding
# from A to B.
#
# In a complicated (non-rebased) DAG, this becomes hard to follow,
# so want we want instead is:
#
# * -- A ----------- C stable
# \ \ /
# \ * -- * -- B topic1
# \ /
# * -- * -- * topic2
#
# Where commit C lists as it's first parent the prior stable
# commit and as it's second parent the release candidate. No
# other parents are allowed (e.g. no octopus merges here, which
# would insinuate qa didn't happen on the merged result).
#
# Also, we want to enforce that C does not actually introduce
# any diffs to the files between B and C--as they would be changes
# that QA does not see.
#
. $(dirname $0)/functions
refname="$1"
oldrev="$2"
newrev="$3"
case "$refname" in
refs/heads/*)
short_refname=${refname##refs/heads/}
;;
*)
exit 0
;;
esac
set_change_type
if [ "$change_type" == "delete" ] ; then
exit 0
fi
# create/delete is okay
if [ "$change_type" != "update" ] ; then
exit 0
fi
if [ "$short_refname" == "stable" ] ; then
# Stable enforcement
# read backwards:
# - all commits from old..new
# - unless they were already pointed to by a branch
# = all new commits on stable
count=$(git rev-parse --not --branches | git rev-list --stdin $oldrev..$newrev | wc -l)
if [ "$count" -ne "1" ] ; then
display_error_message "Moving stable must entail a single commit"
exit 1
fi
number_of_parents=$(git rev-list --no-walk --parents $newrev | sed 's/ /\n/g' | grep -v $newrev | wc -l)
if [ "$number_of_parents" -ne "2" ] ; then
display_error_message "Moving stable must entail a merge commit"
exit 1
fi
first_parent=$(git rev-list --no-walk --parents $newrev | sed 's/ /\n/g' | grep -v $newrev | head --lines=1)
if [ "$first_parent" != "$oldrev" ] ; then
display_error_message "Moving stable must have the previous stable as the first parent"
exit 1
fi
second_parent=$(git rev-list --no-walk --parents $newrev | sed 's/ /\n/g' | grep -v $newrev | tail --lines=1)
changed_lines=$(git diff $second_parent..$newrev | wc -l)
if [ "$changed_lines" -ne "0" ] ; then
display_error_message "Moving stable must not result in any changes from $second_parent"
exit 1
fi
fi