diff --git a/release/prep_release.sh b/release/prep_release.sh new file mode 100644 index 00000000..2f32b400 --- /dev/null +++ b/release/prep_release.sh @@ -0,0 +1,198 @@ +#!/bin/sh +# +# Copyright (c) 2013 Conformal Systems LLC +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# +# Prepares for a release: +# - Bumps version according to specified level (major, minor, or patch) +# - Updates all version files and package control files with new version +# - Performs some basic validation on specified release notes +# - Updates project changes file with release notes +# + +PROJECT=btcd +PROJECT_UC=$(echo $PROJECT | tr '[:lower:]' '[:upper:]') +SCRIPT=$(basename $0) +VERFILE=../version.go +PROJ_CHANGES=../CHANGES + +# verify params +if [ $# -lt 2 ]; then + echo "usage: $SCRIPT {major | minor | patch} release-notes-file" + exit 1 +fi + +CUR_DIR=$(pwd) +cd "$(dirname $0)" + +# verify version file exists +if [ ! -f "$VERFILE" ]; then + echo "$SCRIPT: error: $VERFILE does not exist" 1>&2 + exit 1 +fi + +# verify changes file exists +if [ ! -f "$PROJ_CHANGES" ]; then + echo "$SCRIPT: error: $PROJ_CHANGES does not exist" 1>&2 + exit 1 +fi + +RTYPE="$1" +RELEASE_NOTES="$2" +if [ $(echo $RELEASE_NOTES | cut -c1) != "/" ]; then + RELEASE_NOTES="$CUR_DIR/$RELEASE_NOTES" +fi + +# verify valid release type +if [ "$RTYPE" != "major" -a "$RTYPE" != "minor" -a "$RTYPE" != "patch" ]; then + echo "$SCRIPT: error: release type must be major, minor, or patch" + exit 1 +fi + +# verify release notes +if [ ! -e "$RELEASE_NOTES" ]; then + echo "$SCRIPT: error: specified release notes file does not exist" + exit 1 +fi + +if [ ! -s "$RELEASE_NOTES" ]; then + echo "$SCRIPT: error: specified release notes file is empty" + exit 1 +fi + +# verify release notes format +while IFS='' read line; do + if [ -z "$line" ]; then + echo "$SCRIPT: error: release notes must not have blank lines" + exit 1 + fi + if [ ${#line} -gt 74 ]; then + echo -n "$SCRIPT: error: release notes must not contain lines " + echo "with more than 74 characters" + exit 1 + fi + if expr "$line" : ".*\.$" >/dev/null 2>&1 ; then + echo -n "$SCRIPT: error: release notes must not contain lines " + echo "that end in a period" + exit 1 + fi + if ! expr "$line" : "\-" >/dev/null 2>&1; then + if ! expr "$line" : " " >/dev/null 2>&1; then + echo -n "$SCRIPT: error: release notes must not contain lines " + echo "that do not begin with a dash and are not indented" + exit 1 + fi + fi +done <"$RELEASE_NOTES" + +# verify git is available +if ! type git >/dev/null 2>&1; then + echo -n "$SCRIPT: error: Unable to find 'git' in the system path." + exit 1 +fi + +# verify the git repository is on the master branch +BRANCH=$(git branch | grep '\*' | cut -c3-) +if [ "$BRANCH" != "master" ]; then + echo "$SCRIPT: error: git repository must be on the master branch." + exit 1 +fi + +# verify there are no uncommitted modifications prior to release modifications +NUM_MODIFIED=$(git diff 2>/dev/null | wc -l | sed 's/^[ \t]*//') +NUM_STAGED=$(git diff --cached 2>/dev/null | wc -l | sed 's/^[ \t]*//') +if [ "$NUM_MODIFIED" != "0" -o "$NUM_STAGED" != "0" ]; then + echo -n "$SCRIPT: error: the working directory contains uncommitted " + echo "modifications" + exit 1 +fi + +# get version +PAT_PREFIX="(^[[:space:]]+app" +PAT_SUFFIX='[[:space:]]+uint[[:space:]]+=[[:space:]]+)[0-9]+$' +MAJOR=$(egrep "${PAT_PREFIX}Major${PAT_SUFFIX}" $VERFILE | awk '{print $4}') +MINOR=$(egrep "${PAT_PREFIX}Minor${PAT_SUFFIX}" $VERFILE | awk '{print $4}') +PATCH=$(egrep "${PAT_PREFIX}Patch${PAT_SUFFIX}" $VERFILE | awk '{print $4}') +if [ -z "$MAJOR" -o -z "$MINOR" -o -z "$PATCH" ]; then + echo "$SCRIPT: error: unable to get version from $VERFILE" 1>&2 + exit 1 +fi + +# bump version according to level +if [ "$RTYPE" = "major" ]; then + MAJOR=$(expr $MAJOR + 1) + MINOR=0 + PATCH=0 +elif [ "$RTYPE" = "minor" ]; then + MINOR=$(expr $MINOR + 1) + PATCH=0 +elif [ "$RTYPE" = "patch" ]; then + PATCH=$(expr $PATCH + 1) +fi +PROJ_VER="$MAJOR.$MINOR.$PATCH" + +# update project changes with release notes +DATE=$(date "+%a %b %d %Y") +awk -v D="$DATE" -v VER="$PROJ_VER" ' +/=======/ && first_line==0 { + first_line=1 + print $0 + next +} +/=======/ && first_line==1 { + print $0 + print "" + print "Changes in "VER" ("D")" + exit +} +{ print $0 } +' <"$PROJ_CHANGES" >"${PROJ_CHANGES}.tmp" +cat "$RELEASE_NOTES" | sed 's/^/ /' >>"${PROJ_CHANGES}.tmp" +awk ' +/=======/ && first_line==0 { + first_line=1 + next +} +/=======/ && first_line==1 { + second_line=1 + next +} +second_line==1 { print $0 } +' <"$PROJ_CHANGES" >>"${PROJ_CHANGES}.tmp" + +# update version file with new version +sed -E " + s/${PAT_PREFIX}Major${PAT_SUFFIX}/\1${MAJOR}/; + s/${PAT_PREFIX}Minor${PAT_SUFFIX}/\1${MINOR}/; + s/${PAT_PREFIX}Patch${PAT_SUFFIX}/\1${PATCH}/; +" <"$VERFILE" >"${VERFILE}.tmp" + + +# Apply changes +mv "${PROJ_CHANGES}.tmp" "$PROJ_CHANGES" +mv "${VERFILE}.tmp" "$VERFILE" + +echo "All files have been prepared for release." +echo "Use the following commands to review the changes for accuracy:" +echo " git status" +echo " git diff" +echo "" +echo "If everything is accurate, use the following commands to commit, tag," +echo "and push the changes" +echo " git commit -am \"Prepare for release ${PROJ_VER}.\"" +echo -n " git tag -a \"${PROJECT_UC}_${MAJOR}_${MINOR}_${PATCH}\" -m " +echo "\"Release ${PROJ_VER}\"" +echo " git push" +echo " git push --tags"