summaryrefslogtreecommitdiffstats
path: root/src/VREF/VOTES
diff options
context:
space:
mode:
Diffstat (limited to 'src/VREF/VOTES')
-rwxr-xr-xsrc/VREF/VOTES80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/VREF/VOTES b/src/VREF/VOTES
new file mode 100755
index 0000000..8dc3563
--- /dev/null
+++ b/src/VREF/VOTES
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+# gitolite VREF to count votes before allowing pushes to certain branches.
+
+# This approximates gerrit's voting (but it is SHA based; I believe Gerrit is
+# more "changeset" based). Here's how it works:
+
+# - A normal developer "bob" proposes changes to master by pushing a commit to
+# "pers/bob/master", then informs the voting members by email.
+
+# - Some or all of the voting members fetch and examine the commit. If they
+# approve, they "vote" for the commit like so. For example, say voting
+# member "alice" fetched bob's proposed commit into "bob-master" on her
+# clone, then tested or reviewed it. She would approve it by running:
+# git push origin bob-master:votes/alice/master
+
+# - Once enough votes have been tallied (hopefully there is normal team
+# communication that says "hey I approved your commit", or it can be checked
+# by 'git ls-remote origin' anyway), Bob, or any developer, can push the
+# same commit (same SHA) to master and the push will succeed.
+
+# - Finally, a "trusted" developer can push a commit to master without
+# worrying about the voting restriction at all.
+
+# The config for this example would look like this:
+
+# repo foo
+# # allow personal branches (to submit proposed changes)
+# RW+ pers/USER/ = @devs
+# - pers/ = @all
+#
+# # allow only voters to vote
+# RW+ votes/USER/ = @voters
+# - votes/ = @all
+#
+# # normal access rules go here; should allow *someone* to push master
+# RW+ = @devs
+#
+# # 2 votes required to push master, but trusted devs don't have this restriction
+# RW+ VREF/VOTES/2/master = @trusted-devs
+# - VREF/VOTES/2/master = @devs
+
+# Note: "2 votes required to push master" means at least 2 refs matching
+# "votes/*/master" have the same SHA as the one currently being pushed.
+
+# ----------------------------------------------------------------------
+
+# see gitolite docs for what the first 7 arguments mean
+
+# inputs:
+# arg-8 is a number; see below
+# arg-9 is a simple branch name (i.e., "master", etc). Currently this code
+# does NOT do vote counting for branch names with more than one component
+# (like foo/bar).
+# outputs (STDOUT)
+# nothing
+# exit status:
+# always 0
+
+die() { echo "$@" >&2; exit 1; }
+[ -z "$8" ] && die "not meant to be run manually"
+
+ref=$1
+newsha=$3
+refex=$7
+votes_needed=$8
+branch=$9
+
+# nothing to do if the branch being pushed is not "master" (using our example)
+[ "$ref" = "refs/heads/$branch" ] || exit 0
+
+# find how many votes have come in
+votes=`git for-each-ref refs/heads/votes/*/$branch | grep -c $newsha`
+
+# send back a vref if we don't have the minimum votes needed. For trusted
+# developers this will invoke the RW+ rule and pass anyway, but for others it
+# will invoke the "-" rule and fail.
+[ $votes -ge $votes_needed ] || echo $refex "require at least $votes_needed votes to push $branch"
+
+exit 0