#!/bin/bash #################################################################################### # reviewscript # a simple script to push reviews to codestriker from an svn checkout # (author line redacted by author) #################################################################################### CONFIG_FILE=${HOME}/.review_config # location of config file DOMAIN="redacted" # e-mail domain HOST="redacted" # codestriker host PATH="/codestriker/" # codestriker path REPO_BASE_MATCH="srv/svn-repository/" # part of svn path, ending at the repo base #################################################################################### write_user_config() { echo "USER_EMAIL=\"${USER_EMAIL}\"" > ${CONFIG_FILE} } add_domain_if_none() { if echo "$1" | grep '@' > /dev/null 2>&1 then echo -n "$1" else echo -n "$1@$2" fi } read_line_with_default() { read -p "$1 [$2]:" -e output if [ "x$output" = "x" ] then output="$2" fi echo -n "$output" } read_line_nonblank() { while true do read -p "$1:" -e output if [ ! "x$output" = "x" ] then break fi done echo -n "$output" } read_user_config() { . ${CONFIG_FILE} 2>/dev/null if [ "x${USER_EMAIL}" = "x" ] then email="$(read_line_with_default 'e-mail address' "$(whoami)")" USER_EMAIL="$(add_domain_if_none "$email" "$DOMAIN")" write_user_config fi } do_svn_stat() { if svn info > /dev/null 2>&1 then STAT="$(svn stat)" UNCOM="$(echo -n "$INFO" | grep '^?')" if [ $(echo -n "$UNCOM" | wc -l) -ne 0 ] then echo "$UNCOM" echo "---" echo "WARNING - some changed files are not ignored or added, are you sure you want to continue? (^C to cancel)" read pause fi else echo "Sorry, you have to post a review from an SVN working copy" exit 1 fi } read_project_id() { PROJECTS="$(wget http://${HOST}${PATH}?action=list_projects -q -O- | grep projectid | sed -e 's/^.*projectid=\(.*\)">\(.*\)<.*/\1:\2/')" echo -e 'ID\tNAME' SAVEIFS="$IFS" IFS=$'\012' for item in $PROJECTS do ID="$(echo "$item" | cut -d ':' -f 1)" NAME="$(echo "$item" | cut -d ':' -f 2-)" echo -e "$ID\\t$NAME" done while true do id=$(read_line_nonblank 'Project ID') name="" for item in $PROJECTS do ID="$(echo $item | cut -d ':' -f 1)" NAME="$(echo $item | cut -d ':' -f 2-)" if [ "${ID}" -eq "${id}" ] then id="${ID}" name="${NAME}" break fi done if [ ! "x$name" = "x" ] then break fi echo "Error, Invalid ID" done IFS="$SAVEIFS" PROJECT_ID="$id" PROJECT_NAME="$name" } read_review_info() { echo "Almost ready to commit review" echo "--" read_project_id REVIEW_TITLE="$(read_line_nonblank 'Review Title (must not be blank)')" reviewers="$(read_line_nonblank 'Reviewers (must not be blank)')" REVIEWERS="$(add_domain_if_none "$reviewers" "$DOMAIN")" BUGLIST="$(read_line_with_default 'Bugs closed (comma-separated, may be blank)' '')" CCLIST="$(read_line_with_default 'CC list (may be blank)' '')" } get_diff() { URL="$(svn info | grep 'URL:' | sed -e "s|^.*${REPO_BASE_MATCH}\(.*\)$|\1|")" DIFF="$(svn diff --non-interactive | sed -e "s|^Index: \(.*\)$|Index: ${URL}\1|" -e "s|^+++ \(.*\)$|+++ ${URL}\1|" -e "s|^--- \(.*\)$|--- ${URL}\1|")" } show_review_preview() { ( echo "Project:${PROJECT_NAME} (${PROJECT_ID})" echo "From:${USER_EMAIL}" echo "To:${REVIEWERS}" echo "CC:${CCLIST}" echo "Subject:${REVIEW_TITLE}" echo "Closes Bugs:${BUGLIST}" echo "====" echo "${INFO}" echo "====" echo "${DIFF}" ) | less echo "If you are OK with this review, please hit enter, otherwise press ^C." read confirm } write_line() { echo '--F00BAR' echo "Content-Disposition: form-data; name=\"${1}\"" echo echo "${2}" } post_review() { #this is where it gets tricky #shouldn't be too hard OUTPUT="$( ( write_line action submit_new_topic write_line topic_title "${REVIEW_TITLE}" write_line topic_description "fill me out" write_line projectid "${PROJECT_ID}" write_line bug_ids "${BUGLIST}" write_line email "${USER_EMAIL}" write_line reviewers "${REVIEWERS}" write_line cc "${CCLIST}" echo '--F00BAR' echo 'Content-Disposition: form-data; name="topic_file"; filename="nofilename.tmp"' echo 'Content-Type: text/plain' echo 'Content-Transfer-Encoding: binary' echo echo "${DIFF}" echo '--F00BAR--' ) | sed -e 's/$/\r/g')" let SIZE="$(echo -n "${OUTPUT}" | wc -c)" HEADERS="$( ( echo "POST ${PATH} HTTP/1.0" echo "Content-Type: multipart/form-data; boundary=F00BAR" echo "Content-Length: ${SIZE}" ) | sed -e 's/$/\r/g' )" ( echo -n -e "${HEADERS}\n" echo -n -e '\r\n' echo -n "${OUTPUT}" ) | nc ${HOST} 80 } main() { read_user_config do_svn_stat read_review_info get_diff show_review_preview FEEDBACK=$(post_review) if echo "$FEEDBACK" | grep 'class="feedback"' > /dev/null 2>&1 then echo "ERROR" echo "$FEEDBACK" | grep 'class="feedback"' | sed -e 's/
/\n/g' -e 's/.*feedback">\(.*\)<.*/\1/' | grep -v 'For security reasons' else echo "REVIEW POSTED" echo "$FEEDBACK" | grep 'URL' | sed -e 's/.*">\(.*\)<.*/\1/' fi } main