Upgrade update-stable to enforce candidate/topic as well.
authorStephen Haberman <stephen@exigencecorp.com>
Sun, 24 Aug 2008 21:31:11 +0000 (16:31 -0500)
committerStephen Haberman <stephen@exigencecorp.com>
Sun, 24 Aug 2008 21:31:11 +0000 (16:31 -0500)
For now we're still doing the topic is locked upon candidate
creation. I'd still prefer remerging.

server/update-stable
tests/t2102-server-update-stable-candidate.sh [new file with mode: 0644]

index 6c89e51..fb1a8e6 100644 (file)
@@ -1,10 +1,18 @@
 #!/bin/sh
 
 #
-# This enforces 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.
+# This enforces stable/candidate/topic patterns.
+#
+# Specifically:
+#
+# * stable must be moved 1 merge commit at a time (see below)
+# * candidates/topics are frozen once merged into stable
+# * topics are frozen once merged into candidates
+#
+# 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:
 #
@@ -40,56 +48,93 @@ refname="$1"
 oldrev="$2"
 newrev="$3"
 
-if expr "$oldrev" : '0*$' >/dev/null ; then
+. $(dirname $0)/functions
+set_change_type
+
+if [[ "$refname" =~ refs/heads/(.*) ]] ; then
+       short_refname=${refname##refs/heads/}
+else
        exit 0
 fi
 
-if [ "$refname" != "refs/heads/stable" ] ; then
+# create/delete is okay
+if [ "$change_type" != "update" ] ; then
        exit 0
 fi
 
-# 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
-       echo "----------------------------------------------------"
-       echo
-       echo "Moving stable must entail a single commit"
-       echo
-       echo "----------------------------------------------------"
-       exit 1
-fi
+if [ "$short_refname" == "stable" ] ; then
+       # Stable enforcement
 
-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
-       echo "----------------------------------------------------"
-       echo
-       echo "Moving stable must entail a merge commit"
-       echo
-       echo "----------------------------------------------------"
-       exit 1
-fi
+       # 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
+               echo "----------------------------------------------------"
+               echo
+               echo "Moving stable must entail a single commit"
+               echo
+               echo "----------------------------------------------------"
+               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
-       echo "----------------------------------------------------"
-       echo
-       echo "Moving stable must have the previous stable as the first parent"
-       echo
-       echo "----------------------------------------------------"
-       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
+               echo "----------------------------------------------------"
+               echo
+               echo "Moving stable must entail a merge commit"
+               echo
+               echo "----------------------------------------------------"
+               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
+               echo "----------------------------------------------------"
+               echo
+               echo "Moving stable must have the previous stable as the first parent"
+               echo
+               echo "----------------------------------------------------"
+               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
+               echo "----------------------------------------------------"
+               echo
+               echo "Moving stable must not result in any changes from $second_parent"
+               echo
+               echo "----------------------------------------------------"
+               exit 1
+       fi
+else
+       # Check if candidate/topic is already in stable
+       git branch --contains "$oldrev" | grep stable >/dev/null
+       if [ $? -eq 0 ] ; then
+               echo "----------------------------------------------------"
+               echo
+               echo "$short_refname has been merged into stable"
+               echo
+               echo "----------------------------------------------------"
+               exit 1
+       fi
+
+       # For now candidates can mix amongst each other so early exit
+       if [[ "$refname" =~ refs/heads/candidate(.*) ]] ; then
+               exit 0
+       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
-       echo "----------------------------------------------------"
-       echo
-       echo "Moving stable must not result in any changes from $second_parent"
-       echo
-       echo "----------------------------------------------------"
-       exit 1
+       # Check if topic is already in candidates
+       candidate=$(git branch --contains "$oldrev" | grep -oP candidate.* --max-count=1)
+       if [ $? -eq 0 ] ; then
+               echo "----------------------------------------------------"
+               echo
+               echo "$short_refname has been merged into $candidate"
+               echo
+               echo "----------------------------------------------------"
+               exit 1
+       fi
 fi
 
diff --git a/tests/t2102-server-update-stable-candidate.sh b/tests/t2102-server-update-stable-candidate.sh
new file mode 100644 (file)
index 0000000..45f1782
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/sh
+
+test_description='server update candidate enforcer'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       echo setup >a &&
+       git add a &&
+       git commit -m "a" &&
+       git clone ./. server &&
+       git remote add origin ./server &&
+       rm -fr server/.git/hooks
+'
+
+# setup the update hook
+install_update_hook 'update-stable'
+
+test_expect_success 'initial stable commit works' '
+       # do one stable-less commit
+       echo $test_name >a &&
+       git commit -a -m "$test_name" &&
+       git push origin master &&
+
+       git checkout -b stable &&
+       git push origin stable &&
+       git config --add branch.stable.remote origin &&
+       git config --add branch.stable.merge refs/heads/stable
+'
+
+test_expect_success 'create topic1 and topic2' '
+       git checkout -b topic1 stable &&
+       echo "$test_name topic1" >a.topic1 &&
+       git add a.topic1 &&
+       git commit -m "start topic1" &&
+
+       git checkout -b topic2 stable &&
+       echo "$test_name topic2" >a.topic2 &&
+       git add a.topic2 &&
+       git commit -m "start topic2" &&
+
+       git push origin topic2 topic1
+'
+
+test_expect_success 'create candidate1' '
+       git checkout -b candidate1 stable &&
+       git merge topic1 topic2 &&
+       git push origin candidate1
+'
+
+test_expect_success 'topic1 cannot be changed' '
+       git checkout topic1 &&
+       echo "$test_name" >a.topic1 &&
+       git commit -a -m "$test_name" &&
+       ! git push origin topic1 2>push.err &&
+       cat push.err | grep "topic1 has been merged into candidate1"
+'
+
+test_expect_success 'candidate1 can be changed' '
+       git checkout candidate1 &&
+       echo "$test_name" >a.topic1 &&
+       git commit -a -m "$test_name" &&
+       git push origin candidate1
+'
+
+test_expect_success 'merge candidate into stable' '
+       git checkout stable &&
+       git merge candidate1 --no-ff &&
+       git push origin stable
+'
+
+test_expect_success 'candidate cannot be changed' '
+       git checkout candidate1 &&
+       echo "$test_name" >a.topic1 &&
+       git commit -a -m "$test_name" &&
+       ! git push origin candidate1 2>push.err &&
+       cat push.err | grep "candidate1 has been merged into stable"
+       ! cat push.err | grep "candidate1 has been merged into candidate1"
+'
+
+test_expect_success 'topic1 cannot be changed' '
+       # It is already changed but error message should chagne
+       git checkout topic1 &&
+       ! git push origin topic1 2>push.err &&
+       cat push.err | grep "topic1 has been merged into stable"
+'
+
+test_done
+