]> git.sur5r.net Git - openocd/commitdiff
Add script to automate most of the release process.
authorzwelch <zwelch@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Mon, 6 Jul 2009 11:21:28 +0000 (11:21 +0000)
committerzwelch <zwelch@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Mon, 6 Jul 2009 11:21:28 +0000 (11:21 +0000)
git-svn-id: svn://svn.berlios.de/openocd/trunk@2473 b42882b7-edfa-0310-969c-e2dbd0fdcd60

tools/release.sh [new file with mode: 0755]

diff --git a/tools/release.sh b/tools/release.sh
new file mode 100755 (executable)
index 0000000..583cd20
--- /dev/null
@@ -0,0 +1,569 @@
+#!/bin/sh -e
+# release.sh: openocd release process automation
+# Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net>
+# Release under the GNU GPL v2 (or later versions).
+
+## set these to control the build process
+#CONFIG_OPTS=""
+#MAKE_OPTS=""
+
+## DO NOT PERFORM LIVE RELEASES UNLESS YOU ARE THE RELEASE MANAGER!!!
+RELEASE_DRY_RUN=1
+## set this to perform individual steps on past releases
+RELEASE_VERSION=
+
+die() {
+       echo "$@" >&2
+       exit 1
+}
+
+svn_info_get() {
+       svn info | grep "$1" | cut -d':' -f2- | cut -c2-
+}
+
+svn_setup_load() {
+       SVN_ROOT="$(svn_info_get 'Repository Root')"
+       SVN_URL="$(svn_info_get 'URL')"
+
+       SVN_TRUNK="${SVN_ROOT}/trunk"
+
+       SVN_BRANCHES="${SVN_ROOT}/branches"
+       PACKAGE_BRANCH="${SVN_BRANCHES}/${PACKAGE_RELEASE}"
+
+       SVN_TAGS="${SVN_ROOT}/tags"
+       PACKAGE_TAG="${SVN_TAGS}/${PACKAGE_RELEASE}"
+
+       if [ "${SVN_URL}" = "${SVN_TRUNK}" ]; then
+               RELEASE_TYPE=minor
+       elif [ "${SVN_URL/${SVN_BRANCHES}/}" != "${SVN_URL}" ]; then
+               RELEASE_TYPE=micro
+       else
+               echo "error: bad URL: ${SVN_URL}" >&2
+               die "unable to branch from the current location"
+       fi
+}
+svn_setup_show() {
+       cat <<INFO
+Release Type: ${RELEASE_TYPE}
+  Branch URL: ${PACKAGE_BRANCH}
+     Tag URL: ${PACKAGE_TAG}
+INFO
+}
+
+do_svn_echo_msg() { echo "svn: $1: $3"; }
+do_svn_echo() {
+       case "$1" in
+       commit)
+               do_svn_echo_msg "$@"
+               shift 3
+               [ "$*" ] && echo "Files: $@"
+               ;;
+       copy|move)
+               do_svn_echo_msg "$@"
+               echo "From: ${4:-$2}"
+               echo "  To: ${5:-$3}"
+               ;;
+       *)
+               local ACTION="$1"
+               shift
+               echo "svn: ${ACTION}: $@"
+               ;;
+       esac
+}
+do_svn() {
+       do_svn_echo "$@"
+       [ "${RELEASE_DRY_RUN}" ] || svn "$@"
+}
+
+
+package_info_load_name() {
+       grep AC_INIT configure.in | perl -ne 's/^.+\(\[([-\w]*)\],.+$/$1/ and print'
+}
+package_info_load_version() {
+       grep AC_INIT configure.in | perl -ne 's/^.+\[([-\w\.]*)\],$/$1/ and print'
+}
+
+package_info_load() {
+       [ -f "configure.in" ] || \
+               die "package_info_load: configure.in is missing"
+
+       PACKAGE_NAME="$(package_info_load_name)"
+       # todo: fix this
+       PACKAGE_TARNAME="${PACKAGE_NAME}"
+
+       PACKAGE_VERSION="$(package_info_load_version)"
+       [ "${RELEASE_VERSION}" ] || \
+               RELEASE_VERSION=${PACKAGE_VERSION/-in-development/}
+
+       [ "${PACKAGE_NAME}" -a "${PACKAGE_VERSION}" ] || \
+               die "package information is missing from configure script"
+
+       PACKAGE_VERSION_TAGS=
+       [ "${PACKAGE_VERSION/-/}" = "${PACKAGE_VERSION}" ] || \
+               PACKAGE_VERSION_TAGS="-${PACKAGE_VERSION#*-}"
+       PACKAGE_VERSION_BASE="${PACKAGE_VERSION%%-*}"
+       PACKAGE_MICRO="${PACKAGE_VERSION_BASE##*.}"
+       PACKAGE_MAJOR_AND_MINOR="${PACKAGE_VERSION_BASE%.*}"
+       PACKAGE_MAJOR="${PACKAGE_MAJOR_AND_MINOR%.*}"
+       PACKAGE_MINOR="${PACKAGE_MAJOR_AND_MINOR#*.}"
+
+       PACKAGE_STRING="${PACKAGE_NAME} ${PACKAGE_VERSION}"
+       if [ "${RELEASE_DRY_RUN}" ]; then
+               PACKAGE_RELEASE="${PACKAGE_TARNAME}-${PACKAGE_VERSION}"
+       else
+               PACKAGE_RELEASE="${PACKAGE_TARNAME}-${RELEASE_VERSION}"
+       fi
+}
+
+package_info_show() {
+       cat <<INFO
+Name: ${PACKAGE_TARNAME}
+Release: ${RELEASE_VERSION}
+Version: ${PACKAGE_VERSION}
+   Number: ${PACKAGE_VERSION_BASE}
+   Series: ${PACKAGE_MAJOR_AND_MINOR}
+    Major: ${PACKAGE_MAJOR}
+    Minor: ${PACKAGE_MINOR}
+    Micro: ${PACKAGE_MICRO}
+     Tags: ${PACKAGE_VERSION_TAGS}
+ Branch: ${PACKAGE_RELEASE}
+Release: ${PACKAGE_TARNAME}-${PACKAGE_VERSION_BASE}${PACKAGE_VERSION_TAGS}
+INFO
+}
+
+usage() {
+       cat << USAGE
+usage: $0 <command>
+
+Main Commands:
+  info          Show a summary of the next pending release.
+  release       Release the current tree as an archive.
+  upload        Upload archives to berliOS project site
+
+Build Commands:
+  bootstrap     Prepare the working copy for configuration and building.
+  configure     Configures the package; runs bootstrap, if needed.
+  build         Compiles the project; runs configure, if needed.
+
+Packaging Commands:
+  changelog     Generate a new ChangeLog using svn2cl.
+  package       Produce new distributable source archives.
+  stage         Move archives to staging area for upload.
+
+Repository Commands:
+  commit        Perform branch and tag, as appropriate for the version.
+  branch        Create a release branch from the project trunk.
+  tag           Create a tag for the current release branch.
+
+Other Commands:
+  version ...   Perform version number and tag manipulations.
+  maryslamb     Mary had a little lamb, but no one noticed.
+  clean         Forces regeneration of results.
+  clean_all     Removes all traces of the release process.
+  help          Provides this list of commands.
+  
+For more information about this script, see the Release Processes page
+in the OpenOCD Developer's Manual (doc/manual/release.txt).
+
+WARNING: This script should be used by the Release Manager ONLY.
+USAGE
+       exit 0
+}
+do_usage() { usage; }
+do_help()  { usage; }
+
+do_info_show() {
+       echo "Current Release Analysis:"
+       package_info_show
+       svn_setup_show
+}
+
+do_info() {
+       package_info_load
+       svn_setup_load
+       do_info_show
+}
+
+do_bootstrap() {
+       echo -n "Bootstrapping..."
+       ./bootstrap 2>&1 | perl tools/logger.pl > "release-bootstrap.log"
+}
+maybe_bootstrap() { [ -f "configure" ] || do_bootstrap; }
+
+do_configure() {
+       maybe_bootstrap
+       echo -n "Configuring..."
+       ./configure ${CONFIG_OPTS} 2>&1 | perl tools/logger.pl > "release-config.log"
+}
+maybe_configure() { [ -f "Makefile" ] || do_configure; }
+
+do_build() {
+       maybe_configure
+       echo -n "Compiling OpenOCD ${PACKAGE_VERSION}"
+       make ${MAKE_OPTS} -C doc stamp-vti 2>&1 \
+               | perl tools/logger.pl > "release-version.log"
+       make ${MAKE_OPTS} 2>&1 \
+               | perl tools/logger.pl > "release-make.log"
+}
+maybe_build() { [ -f "src/openocd" ] || do_build; }
+do_build_clean() { [ -f Makefile ] && make maintainer-clean >/dev/null; }
+
+maybe_rebuild() {
+       if [ -f "configure" ]; then
+               echo "Re-running autoconf..."
+               autoconf
+               echo "Re-running automake..."
+               automake
+       fi
+       if [ -f "Makefile" ]; then
+               do_configure
+               do_build
+       fi
+}
+
+do_changelog() {
+       echo "Updating working copy to HEAD..."
+       do_svn update
+       echo "Creating ChangeLog..."
+       svn2cl -i --authors AUTHORS.ChangeLog
+}
+maybe_changelog() {
+       if [ -z "${RELEASE_DRY_RUN}" ] \
+               || [ ! -f ChangeLog ] \
+               || [ "$(cat ChangeLog | wc -l)" -lt 2 ]
+       then
+               do_changelog
+       fi
+}
+do_changelog_clean() {
+       do_svn revert ChangeLog
+}
+
+do_package() {
+       package_info_load
+       maybe_changelog
+       maybe_build
+       echo "Building distribution packages..."
+       make ${MAKE_OPTS} distcheck 2>&1 | perl tools/logger.pl > "release-pkg.log"
+}
+maybe_package() { [ -f "${PACKAGE_RELEASE}.zip" ] || do_package; }
+do_package_clean() {
+       for EXT in tar.gz tar.bz2 zip; do
+               rm -v -f *.${EXT}
+       done
+}
+
+do_stage() {
+       maybe_package
+       echo "Staging package archives:"
+       mkdir -p archives
+       for EXT in tar.gz tar.bz2 zip; do
+               mv -v "${PACKAGE_RELEASE}.${EXT}" archives/
+       done
+       cp -a NEWS archives/
+       cp -a ChangeLog archives/
+}
+do_stage_clean() { rm -v -f -r archives; }
+
+do_clean() {
+       do_build_clean
+       do_package_clean
+       rm -v -f configure
+
+       svn revert configure.in
+       rm -v -f release-*.log
+}
+do_clean_all() {
+       do_clean
+       do_changelog_clean
+       do_stage_clean
+}
+
+do_version_usage() {
+       cat << USAGE
+usage: $0 version <command>
+Version Commands:
+  tag {add|remove} <label>     Add or remove the specified tag.
+  bump {major|minor|micro|rc}  Bump the specified version number;
+                               resets less-significant numbers to zero.
+                              All but 'rc' releases drop that tag.
+USAGE
+}
+
+do_version_sed() {
+       local OLD_VERSION="${PACKAGE_VERSION}"
+       local NEW_VERSION="$1"
+       local MSG="$2"
+
+       sed -i -e "/AC_INIT/ s|${OLD_VERSION}|${NEW_VERSION}|" configure.in
+       package_info_load
+       echo "${MSG}: ${OLD_VERSION} -> ${NEW_VERSION}"
+}
+do_version_bump_sed() {
+       local NEW_VERSION="$1"
+       [ -z "${PACKAGE_VERSION_TAGS}" ] || \
+               NEW_VERSION="${NEW_VERSION}${PACKAGE_VERSION_TAGS}"
+
+       do_version_sed "${NEW_VERSION}" \
+               "Bump ${CMD} package version number"
+}
+do_version_bump_major() {
+       has_version_tag 'rc\d' do_version_
+       do_version_bump_sed "$((PACKAGE_MAJOR + 1)).0.0"
+}
+do_version_bump_minor() {
+       do_version_bump_sed "${PACKAGE_MAJOR}.$((PACKAGE_MINOR + 1)).0"
+}
+do_version_bump_micro() {
+       do_version_bump_sed "${PACKAGE_MAJOR_AND_MINOR}.$((PACKAGE_MICRO + 1))"
+}
+do_version_bump_rc() {
+       die "patch missing: -rc support is not implemented"
+}
+do_version_bump() {
+       CMD="$1"
+       shift
+       case "${CMD}" in
+       major|minor|micro|rc)
+               eval "do_version_bump_${CMD}"
+               ;;
+       *)
+               do_version_usage
+               ;;
+       esac
+}
+
+has_version_tag() {
+       test "${PACKAGE_VERSION/-${TAG}/}" != "${PACKAGE_VERSION}"
+}
+
+do_version_tag_add() {
+       local TAG="$1"
+       has_version_tag && die "error: tag '-${TAG}' exists in '${PACKAGE_VERSION}'"
+       do_version_sed "${PACKAGE_VERSION}-${TAG}" \
+               "Add '-${TAG}' version tag"
+}
+do_version_tag_remove() {
+       local TAG="$1"
+       has_version_tag || die "error: tag '-${TAG}' missing from '${PACKAGE_VERSION}'"
+       do_version_sed "${PACKAGE_VERSION/-${TAG}/}" \
+               "Remove '-${TAG}' version tag"
+}
+do_version_tag() {
+       CMD="$1"
+       shift
+       case "${CMD}" in
+       add|remove)
+               local i=
+               for i in "$@"; do 
+                       eval "do_version_tag_${CMD}" "${i}"
+               done
+               ;;
+       *)
+               do_version_usage
+               ;;
+       esac
+}
+
+do_version_commit() {
+       [ "$(svn diff configure.in | wc -l)" -gt 0 ] || \
+               die "error: no version changes to commit"
+       do_svn commit -m "$1" configure.in
+}
+
+do_version() {
+       package_info_load
+       CMD="$1"
+       shift
+       case "${CMD}" in
+       tag|bump)
+               do_version_commit "$(eval "do_version_${CMD}" "$@")"
+               maybe_rebuild
+               ;;
+       commit)
+               local MSG="$1"
+               [ "${MSG}" ] || die "usage: $0 version commit <message>"
+               do_version_commit "${MSG}"
+               maybe_rebuild
+               ;;
+       *)
+               do_version_usage
+               ;;
+       esac
+}
+
+
+do_branch() {
+       package_info_load
+       svn_setup_load
+       do_svn copy -m "Branching version ${PACKAGE_VERSION}" \
+               "${SVN_TRUNK}" "${PACKAGE_BRANCH}"
+}
+do_tag() {
+       package_info_load
+       svn_setup_load
+       do_svn copy -m "Tagging version ${PACKAGE_VERSION}" \
+               "${PACKAGE_BRANCH}" "${PACKAGE_TAG}"
+}
+do_commit() {
+       package_info_load
+       svn_setup_load
+
+       [ "${PACKAGE_VERSION/in-development/}" = "${PACKAGE_VERSION}" ] || \
+               die "'${PACKAGE_NAME}-${PACKAGE_VERSION}' cannot be released"
+
+       [ "${PACKAGE_VERSION%.0}" = "${PACKAGE_VERSION}" ] || \
+               do_branch
+       do_tag
+}
+
+
+do_release_step_prep() {
+       do_version tag remove in-development
+       # reset RELEASE_VERSION now to allow release version to be detected
+       export RELEASE_VERSION=
+}
+do_release_step_commit() { do_commit; }
+
+do_release_step_branch_bump() {
+       local TYPE="$1"
+       echo "Bump ${TYPE} version and add tag:"
+       do_version_bump ${TYPE}
+       do_version_tag_add in-development
+}
+do_release_step_branch() {
+       do_svn switch "${PACKAGE_BRANCH}"
+       package_info_load
+       do_version_commit "$(do_release_step_branch_bump micro)"
+       do_svn switch "${SVN_URL}"
+       package_info_load
+}
+do_release_step_bump() {
+       # major and minor releases require branch version update too
+       [ "${RELEASE_TYPE}" = "micro" ] || do_release_step_branch
+       # bump the current tree version as required.
+       do_version_commit "$(do_release_step_branch_bump "${RELEASE_TYPE}")"
+
+       # archive NEWS and create new one from template
+       do_svn move "NEWS" "NEWS-${RELEASE_VERSION}"
+
+       [ "${RELEASE_DRY_RUN}" ] || cat >NEWS <<NEWS
+This file should include items worth mentioning in the
+OpenOCD ${PACKAGE_RELEASE} source archive release.
+
+The following areas of OpenOCD functionality changed in this release:
+
+JTAG Layer:
+Target Layer:
+Flash Layer:
+Board, Target, and Interface Configuration Scripts:
+Documentation:
+Build and Release:
+
+For more details about what has changed since the last release,
+see the ChangeLog associated with this source archive.  For older NEWS,
+see the NEWS files associated with each release (i.e. NEWS-<version>).
+
+For more information about contributing test reports, bug fixes, or new
+features and device support, please read the new Developer Manual (or
+the BUGS and PATCHES files in the source archive).
+NEWS
+
+       MSG=<<MSG
+Archive released NEWS file: NEWS -> NEWS-${RELEASE_VERSION}
+Create new NEWS file from relesse script template.
+MSG
+       do_svn commit -m "${MSG}" NEWS NEWS-${RELEASE_VERSION}
+}
+do_release_step_package() {
+       local A=${PACKAGE_TAG}
+       local B=${A/https/http}
+       local PACKAGE_BUILD=${B/${USER}@/}
+       do_svn switch "${PACKAGE_BUILD}"
+       do_stage
+       do_clean
+}
+
+do_release_step_1() { do_release_step_prep; }
+do_release_step_2() { do_release_step_commit; }
+do_release_step_3() { do_release_step_bump; }
+do_release_step_4() { do_release_step_package; }
+
+do_release_check() {
+       echo -n "Are you sure you want to release '${PACKAGE_RELEASE}'?"
+       read ANSWER
+       if [ "${ANSWER}" != 'y' ]; then
+               echo "Live release aborted!"
+               exit 0
+       fi
+}
+do_countdown() {
+       echo -n "$1 in "
+       for i in $(seq 5 -1 1); do
+               echo -n "$i, "
+       done
+       echo "go!"
+}
+
+do_release() {
+       package_info_load
+       package_info_show
+
+       if [ -z "${RELEASE_DRY_RUN}" ]; then
+               do_release_check
+               do_countdown "Starting live release"
+       fi
+
+       local i=
+       for i in $(seq 1 4); do
+               eval "do_release_step_${i}"
+       done
+}
+do_all() { do_release "$@"; }
+
+do_reset() {
+       maybe_bootstrap
+       maybe_configure
+       do_clean_all
+       svn revert configure.in
+}
+
+OPTIONS=$(getopt -o V --long live -n $0 -- "$@")
+if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
+eval set -- "${OPTIONS}"
+while true; do
+       case "$1" in
+       --live)
+               export RELEASE_DRY_RUN=
+               shift
+               ;;
+       -V)
+               exec $0 info
+               ;;
+       --)
+               shift
+               break
+               ;;
+       *)
+               echo "Internal error"
+               exit 1
+               ;;
+       esac
+done
+
+CMD=$1
+[ "${CMD}" ] || usage
+shift
+
+ACTION_CMDS="bootstrap|configure|build|changelog|package|stage|clean"
+MISC_CMDS="all|info|version|tag|branch|commit|release|reset|help|usage"
+CLEAN_CMDS="build_clean|changelog_clean|package_clean|stage_clean|clean_all"
+CMDS="|${ACTION_CMDS}|${CLEAN_CMDS}|${MISC_CMDS}|"
+is_command() { echo "${CMDS}" | grep "|$1|" >/dev/null; }
+
+if is_command "${CMD}"; then
+       eval "do_${CMD}" "$@"
+else
+       echo "error: unknown command: '${CMD}'"
+       usage
+fi