Last active
January 3, 2016 09:09
-
-
Save canton7/8440936 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
SVN="svn/trunk" | |
MASTER="master" | |
die() { echo "$@" >&2; exit 1; } | |
ensure_clean() | |
{ | |
if ! git diff --no-ext-diff --ignore-submodules --quiet --exit-code; then | |
die ">> FATAL: Working tree contains unstaged changes. Aborting" | |
elif ! git diff-index --cached --quiet --ignore-submodules HEAD --; then | |
die ">> FATA: Index contains uncommitted changes. Aborting" | |
fi | |
} | |
ensure_review_branch() | |
{ | |
parse_review_branch | |
[[ -z "$REVIEW_BRANCH" ]] && die ">> FATAL: Current branch must be in the form 'review/xx'" | |
} | |
parse_review_branch() | |
{ | |
REVIEW_BRANCH=$(git symbolic-ref HEAD | grep -E 'refs/heads/review/[[:digit:]]' | cut -d '/' -f 3-) | |
REVIEW_ID=$(echo "$REVIEW_BRANCH" | cut -d '/' -f 2) | |
} | |
label_branch() | |
{ | |
local review_id="$1" | |
( | |
cd "$(git rev-parse --show-toplevel)"; | |
git filter-branch -f --msg-filter "sed -e \"/Review-ID:/d\" | sed -e :a -e \"/^\\n*$/N;/\\n$/ba\" && echo \"\\nReview-ID: $review_id\"" $SVN..HEAD | |
) | |
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d | |
} | |
branch_name_for_hash() | |
{ | |
local hash="$@" | |
echo $(git for-each-ref --format="%(objectname)%09%(refname:short)" refs/heads/ | grep "$hash" | cut -f 2 | head -n 1) | |
} | |
find_revision_range() | |
{ | |
# If they passed --revision-range, we don't add our own | |
if [[ "$@" == *--revision-range=* ]]; then | |
REVISION_RANGE="" | |
return | |
fi | |
local head=$(git rev-parse HEAD) | |
local latest_review=$(git for-each-ref --format="%(objectname)" refs/heads/review/* | { \ | |
while read commit; do | |
# Is it a direct ancestor, but not the current commit? | |
if [[ "$commit" != "$head" && "$(git merge-base HEAD "$commit")" = "$commit" ]]; then | |
# Is it newer than the previously-stored revision branch? | |
if [[ -z "$latest_review" || "$(git merge-base "$commit" "$latest_review")" = "$latest_review" ]]; then | |
latest_review="$commit" | |
fi | |
fi | |
done | |
echo $latest_review | |
}) | |
if [[ -z "$latest_review" ]]; then | |
REVISION_RANGE="" | |
else | |
echo ">> Found revision range: $(branch_name_for_hash "$latest_review")" | |
REVISION_RANGE="--revision-range=$latest_review" | |
fi | |
} | |
cmd_label() | |
{ | |
ensure_clean | |
# They can either pass the review ID as the first arg, or be on a review branch | |
local review_id="$1" | |
[[ -z "$review_id" ]] && parse_review_branch && review_id="$REVIEW_ID" | |
[[ -z "$review_id" ]] && die ">> FATAL: Either be on a review branch, or pass in the review ID as an argument" | |
label_branch $review_id | |
} | |
cmd_submit() | |
{ | |
ensure_clean | |
parse_review_branch | |
find_revision_range "$@" | |
# If it's not an update, and they're on a review branch, it's probably a mistake | |
[[ -n "$REVIEW_ID" ]] && die ">> FATAL: It looks like you're on a review branch. This is probably a mistake?" | |
local regex="Review request #([[:digit:]]+) posted" | |
local full_output=$(post-review "$REVISION_RANGE" "$@") | |
echo "$full_output" | |
local filtered_output=$(echo "$full_output" | grep -E "$regex") | |
[[ "$filtered_output" =~ $regex ]] || die ">> FATAL: Could not find review ID in output" | |
local review_id=${BASH_REMATCH[1]} | |
local review_branch="review/$review_id" | |
git show-ref --verify --quiet refs/heads/$review_branch | |
[[ $? -eq 0 ]] && die ">> Review branch $review_branch already exists, so not touching it" | |
git checkout -b $review_branch | |
} | |
cmd_update() | |
{ | |
ensure_clean | |
ensure_review_branch | |
find_revision_range "$@" | |
post-review -r "$REVIEW_ID" --diff-only --no-guess-fields --no-guess-summary --no-guess-description "$REVISION_RANGE" "$@" | |
} | |
cmd_commit() | |
{ | |
ensure_clean | |
ensure_review_branch | |
# Make sure we're up to date | |
git svn fetch | |
[[ "$(git merge-base $SVN HEAD)" != "$(git rev-parse $SVN)" ]] && die ">> FATAL: Rebase onto $SVN" | |
git checkout $MASTER | |
git merge --ff-only $REVIEW_BRANCH || die ">> FATAL: Failed to fast-forward master to $REVIEW_BRANCH" | |
git branch -d $REVIEW_BRANCH | |
label_branch $REVIEW_ID | |
git svn dcommit | |
rbt close --close-type=submitted $REVIEW_ID | |
} | |
cmd_apply() | |
{ | |
ensure_clean | |
local review_id="$1" | |
[[ -z "$review_id" ]] && parse_review_branch && review_id=$REVIEW_ID | |
[[ -z "$review_id" ]] && die ">> FATAL: Either be on a review branch, or pass in the review ID as an argument" | |
local review_branch="review/$review_id" | |
if [[ -n "$REVIEW_BRANCH" ]]; then | |
echo ">> Branch $REVIEW_BRANCH already exists. Resetting to $SVN" | |
[[ "$(git symbolic-ref HEAD)" != "refs/heads/$REVIEW_BRANCH" ]] && git checkout $REVIEW_BRANCH | |
git reset --hard $SVN | |
else | |
local review_branch="review/$review_id" | |
echo ">> Creating $review_branch, based on $SVN" | |
git checkout -b $review_branch $SVN | |
fi | |
rbt patch --px=0 $review_id | |
} | |
usage() | |
{ | |
echo "Usage: $0 [submit|label|update|commit|apply] [review-id] [args]" | |
echo | |
echo "The commands label,update,apply will grab the review ID from the current branch" | |
echo "name if avaible, or from the first argument (e.g. 'git review label 23')." | |
echo | |
echo "The commit command requires that you're on a review/xx branch, and submit doesn't" | |
echo "care what branch you're on." | |
echo | |
echo "The submit and update commands will automatically determine the --revision-range" | |
echo "argument (the latest review/xx branch that's an ancestor of HEAD) if this argument" | |
echo "isn't given" | |
echo | |
echo "Subcommands:" | |
echo " submit: Runs 'post-review $@' on the current branch, and retrieves the ID," | |
echo " then creates a branch review/xx at the current point." | |
echo " label: For each commit between HEAD and $SVN, adds a Review-ID: xx line." | |
echo " update: Updates the review with a new patch, derived from the current HEAD." | |
echo " commit: Requires you to be on a review/xx branch. Merges the branch into master," | |
echo " and dcommits, then closes the related review." | |
echo " apply: If you're on a review/xx branch, resets it to $SVN and applies the latest" | |
echo " patch from ReviewBoard. If you're not, creates such a branch based on $SVN" | |
echo " and applies the patch. Useful to checking someone else's patch." | |
} | |
SUBCOMMAND="$1" | |
shift | |
case "$SUBCOMMAND" in | |
submit) | |
cmd_submit "$@" | |
;; | |
label) | |
cmd_label "$@" | |
;; | |
update) | |
cmd_update "$@" | |
;; | |
commit) | |
cmd_commit "$@" | |
;; | |
apply) | |
cmd_apply "$@" | |
;; | |
*) | |
usage | |
exit 1 | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment