Add script to automate most of the release process.
[openocd.git] / tools / release.sh
blob583cd20c075828c628f0ef7cc09ee31390121460
1 #!/bin/sh -e
2 # release.sh: openocd release process automation
3 # Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net>
4 # Release under the GNU GPL v2 (or later versions).
6 ## set these to control the build process
7 #CONFIG_OPTS=""
8 #MAKE_OPTS=""
10 ## DO NOT PERFORM LIVE RELEASES UNLESS YOU ARE THE RELEASE MANAGER!!!
11 RELEASE_DRY_RUN=1
12 ## set this to perform individual steps on past releases
13 RELEASE_VERSION=
15 die() {
16 echo "$@" >&2
17 exit 1
20 svn_info_get() {
21 svn info | grep "$1" | cut -d':' -f2- | cut -c2-
24 svn_setup_load() {
25 SVN_ROOT="$(svn_info_get 'Repository Root')"
26 SVN_URL="$(svn_info_get 'URL')"
28 SVN_TRUNK="${SVN_ROOT}/trunk"
30 SVN_BRANCHES="${SVN_ROOT}/branches"
31 PACKAGE_BRANCH="${SVN_BRANCHES}/${PACKAGE_RELEASE}"
33 SVN_TAGS="${SVN_ROOT}/tags"
34 PACKAGE_TAG="${SVN_TAGS}/${PACKAGE_RELEASE}"
36 if [ "${SVN_URL}" = "${SVN_TRUNK}" ]; then
37 RELEASE_TYPE=minor
38 elif [ "${SVN_URL/${SVN_BRANCHES}/}" != "${SVN_URL}" ]; then
39 RELEASE_TYPE=micro
40 else
41 echo "error: bad URL: ${SVN_URL}" >&2
42 die "unable to branch from the current location"
45 svn_setup_show() {
46 cat <<INFO
47 Release Type: ${RELEASE_TYPE}
48 Branch URL: ${PACKAGE_BRANCH}
49 Tag URL: ${PACKAGE_TAG}
50 INFO
53 do_svn_echo_msg() { echo "svn: $1: $3"; }
54 do_svn_echo() {
55 case "$1" in
56 commit)
57 do_svn_echo_msg "$@"
58 shift 3
59 [ "$*" ] && echo "Files: $@"
61 copy|move)
62 do_svn_echo_msg "$@"
63 echo "From: ${4:-$2}"
64 echo " To: ${5:-$3}"
67 local ACTION="$1"
68 shift
69 echo "svn: ${ACTION}: $@"
71 esac
73 do_svn() {
74 do_svn_echo "$@"
75 [ "${RELEASE_DRY_RUN}" ] || svn "$@"
79 package_info_load_name() {
80 grep AC_INIT configure.in | perl -ne 's/^.+\(\[([-\w]*)\],.+$/$1/ and print'
82 package_info_load_version() {
83 grep AC_INIT configure.in | perl -ne 's/^.+\[([-\w\.]*)\],$/$1/ and print'
86 package_info_load() {
87 [ -f "configure.in" ] || \
88 die "package_info_load: configure.in is missing"
90 PACKAGE_NAME="$(package_info_load_name)"
91 # todo: fix this
92 PACKAGE_TARNAME="${PACKAGE_NAME}"
94 PACKAGE_VERSION="$(package_info_load_version)"
95 [ "${RELEASE_VERSION}" ] || \
96 RELEASE_VERSION=${PACKAGE_VERSION/-in-development/}
98 [ "${PACKAGE_NAME}" -a "${PACKAGE_VERSION}" ] || \
99 die "package information is missing from configure script"
101 PACKAGE_VERSION_TAGS=
102 [ "${PACKAGE_VERSION/-/}" = "${PACKAGE_VERSION}" ] || \
103 PACKAGE_VERSION_TAGS="-${PACKAGE_VERSION#*-}"
104 PACKAGE_VERSION_BASE="${PACKAGE_VERSION%%-*}"
105 PACKAGE_MICRO="${PACKAGE_VERSION_BASE##*.}"
106 PACKAGE_MAJOR_AND_MINOR="${PACKAGE_VERSION_BASE%.*}"
107 PACKAGE_MAJOR="${PACKAGE_MAJOR_AND_MINOR%.*}"
108 PACKAGE_MINOR="${PACKAGE_MAJOR_AND_MINOR#*.}"
110 PACKAGE_STRING="${PACKAGE_NAME} ${PACKAGE_VERSION}"
111 if [ "${RELEASE_DRY_RUN}" ]; then
112 PACKAGE_RELEASE="${PACKAGE_TARNAME}-${PACKAGE_VERSION}"
113 else
114 PACKAGE_RELEASE="${PACKAGE_TARNAME}-${RELEASE_VERSION}"
118 package_info_show() {
119 cat <<INFO
120 Name: ${PACKAGE_TARNAME}
121 Release: ${RELEASE_VERSION}
122 Version: ${PACKAGE_VERSION}
123 Number: ${PACKAGE_VERSION_BASE}
124 Series: ${PACKAGE_MAJOR_AND_MINOR}
125 Major: ${PACKAGE_MAJOR}
126 Minor: ${PACKAGE_MINOR}
127 Micro: ${PACKAGE_MICRO}
128 Tags: ${PACKAGE_VERSION_TAGS}
129 Branch: ${PACKAGE_RELEASE}
130 Release: ${PACKAGE_TARNAME}-${PACKAGE_VERSION_BASE}${PACKAGE_VERSION_TAGS}
131 INFO
134 usage() {
135 cat << USAGE
136 usage: $0 <command>
138 Main Commands:
139 info Show a summary of the next pending release.
140 release Release the current tree as an archive.
141 upload Upload archives to berliOS project site
143 Build Commands:
144 bootstrap Prepare the working copy for configuration and building.
145 configure Configures the package; runs bootstrap, if needed.
146 build Compiles the project; runs configure, if needed.
148 Packaging Commands:
149 changelog Generate a new ChangeLog using svn2cl.
150 package Produce new distributable source archives.
151 stage Move archives to staging area for upload.
153 Repository Commands:
154 commit Perform branch and tag, as appropriate for the version.
155 branch Create a release branch from the project trunk.
156 tag Create a tag for the current release branch.
158 Other Commands:
159 version ... Perform version number and tag manipulations.
160 maryslamb Mary had a little lamb, but no one noticed.
161 clean Forces regeneration of results.
162 clean_all Removes all traces of the release process.
163 help Provides this list of commands.
165 For more information about this script, see the Release Processes page
166 in the OpenOCD Developer's Manual (doc/manual/release.txt).
168 WARNING: This script should be used by the Release Manager ONLY.
169 USAGE
170 exit 0
172 do_usage() { usage; }
173 do_help() { usage; }
175 do_info_show() {
176 echo "Current Release Analysis:"
177 package_info_show
178 svn_setup_show
181 do_info() {
182 package_info_load
183 svn_setup_load
184 do_info_show
187 do_bootstrap() {
188 echo -n "Bootstrapping..."
189 ./bootstrap 2>&1 | perl tools/logger.pl > "release-bootstrap.log"
191 maybe_bootstrap() { [ -f "configure" ] || do_bootstrap; }
193 do_configure() {
194 maybe_bootstrap
195 echo -n "Configuring..."
196 ./configure ${CONFIG_OPTS} 2>&1 | perl tools/logger.pl > "release-config.log"
198 maybe_configure() { [ -f "Makefile" ] || do_configure; }
200 do_build() {
201 maybe_configure
202 echo -n "Compiling OpenOCD ${PACKAGE_VERSION}"
203 make ${MAKE_OPTS} -C doc stamp-vti 2>&1 \
204 | perl tools/logger.pl > "release-version.log"
205 make ${MAKE_OPTS} 2>&1 \
206 | perl tools/logger.pl > "release-make.log"
208 maybe_build() { [ -f "src/openocd" ] || do_build; }
209 do_build_clean() { [ -f Makefile ] && make maintainer-clean >/dev/null; }
211 maybe_rebuild() {
212 if [ -f "configure" ]; then
213 echo "Re-running autoconf..."
214 autoconf
215 echo "Re-running automake..."
216 automake
218 if [ -f "Makefile" ]; then
219 do_configure
220 do_build
224 do_changelog() {
225 echo "Updating working copy to HEAD..."
226 do_svn update
227 echo "Creating ChangeLog..."
228 svn2cl -i --authors AUTHORS.ChangeLog
230 maybe_changelog() {
231 if [ -z "${RELEASE_DRY_RUN}" ] \
232 || [ ! -f ChangeLog ] \
233 || [ "$(cat ChangeLog | wc -l)" -lt 2 ]
234 then
235 do_changelog
238 do_changelog_clean() {
239 do_svn revert ChangeLog
242 do_package() {
243 package_info_load
244 maybe_changelog
245 maybe_build
246 echo "Building distribution packages..."
247 make ${MAKE_OPTS} distcheck 2>&1 | perl tools/logger.pl > "release-pkg.log"
249 maybe_package() { [ -f "${PACKAGE_RELEASE}.zip" ] || do_package; }
250 do_package_clean() {
251 for EXT in tar.gz tar.bz2 zip; do
252 rm -v -f *.${EXT}
253 done
256 do_stage() {
257 maybe_package
258 echo "Staging package archives:"
259 mkdir -p archives
260 for EXT in tar.gz tar.bz2 zip; do
261 mv -v "${PACKAGE_RELEASE}.${EXT}" archives/
262 done
263 cp -a NEWS archives/
264 cp -a ChangeLog archives/
266 do_stage_clean() { rm -v -f -r archives; }
268 do_clean() {
269 do_build_clean
270 do_package_clean
271 rm -v -f configure
273 svn revert configure.in
274 rm -v -f release-*.log
276 do_clean_all() {
277 do_clean
278 do_changelog_clean
279 do_stage_clean
282 do_version_usage() {
283 cat << USAGE
284 usage: $0 version <command>
285 Version Commands:
286 tag {add|remove} <label> Add or remove the specified tag.
287 bump {major|minor|micro|rc} Bump the specified version number;
288 resets less-significant numbers to zero.
289 All but 'rc' releases drop that tag.
290 USAGE
293 do_version_sed() {
294 local OLD_VERSION="${PACKAGE_VERSION}"
295 local NEW_VERSION="$1"
296 local MSG="$2"
298 sed -i -e "/AC_INIT/ s|${OLD_VERSION}|${NEW_VERSION}|" configure.in
299 package_info_load
300 echo "${MSG}: ${OLD_VERSION} -> ${NEW_VERSION}"
302 do_version_bump_sed() {
303 local NEW_VERSION="$1"
304 [ -z "${PACKAGE_VERSION_TAGS}" ] || \
305 NEW_VERSION="${NEW_VERSION}${PACKAGE_VERSION_TAGS}"
307 do_version_sed "${NEW_VERSION}" \
308 "Bump ${CMD} package version number"
310 do_version_bump_major() {
311 has_version_tag 'rc\d' do_version_
312 do_version_bump_sed "$((PACKAGE_MAJOR + 1)).0.0"
314 do_version_bump_minor() {
315 do_version_bump_sed "${PACKAGE_MAJOR}.$((PACKAGE_MINOR + 1)).0"
317 do_version_bump_micro() {
318 do_version_bump_sed "${PACKAGE_MAJOR_AND_MINOR}.$((PACKAGE_MICRO + 1))"
320 do_version_bump_rc() {
321 die "patch missing: -rc support is not implemented"
323 do_version_bump() {
324 CMD="$1"
325 shift
326 case "${CMD}" in
327 major|minor|micro|rc)
328 eval "do_version_bump_${CMD}"
331 do_version_usage
333 esac
336 has_version_tag() {
337 test "${PACKAGE_VERSION/-${TAG}/}" != "${PACKAGE_VERSION}"
340 do_version_tag_add() {
341 local TAG="$1"
342 has_version_tag && die "error: tag '-${TAG}' exists in '${PACKAGE_VERSION}'"
343 do_version_sed "${PACKAGE_VERSION}-${TAG}" \
344 "Add '-${TAG}' version tag"
346 do_version_tag_remove() {
347 local TAG="$1"
348 has_version_tag || die "error: tag '-${TAG}' missing from '${PACKAGE_VERSION}'"
349 do_version_sed "${PACKAGE_VERSION/-${TAG}/}" \
350 "Remove '-${TAG}' version tag"
352 do_version_tag() {
353 CMD="$1"
354 shift
355 case "${CMD}" in
356 add|remove)
357 local i=
358 for i in "$@"; do
359 eval "do_version_tag_${CMD}" "${i}"
360 done
363 do_version_usage
365 esac
368 do_version_commit() {
369 [ "$(svn diff configure.in | wc -l)" -gt 0 ] || \
370 die "error: no version changes to commit"
371 do_svn commit -m "$1" configure.in
374 do_version() {
375 package_info_load
376 CMD="$1"
377 shift
378 case "${CMD}" in
379 tag|bump)
380 do_version_commit "$(eval "do_version_${CMD}" "$@")"
381 maybe_rebuild
383 commit)
384 local MSG="$1"
385 [ "${MSG}" ] || die "usage: $0 version commit <message>"
386 do_version_commit "${MSG}"
387 maybe_rebuild
390 do_version_usage
392 esac
396 do_branch() {
397 package_info_load
398 svn_setup_load
399 do_svn copy -m "Branching version ${PACKAGE_VERSION}" \
400 "${SVN_TRUNK}" "${PACKAGE_BRANCH}"
402 do_tag() {
403 package_info_load
404 svn_setup_load
405 do_svn copy -m "Tagging version ${PACKAGE_VERSION}" \
406 "${PACKAGE_BRANCH}" "${PACKAGE_TAG}"
408 do_commit() {
409 package_info_load
410 svn_setup_load
412 [ "${PACKAGE_VERSION/in-development/}" = "${PACKAGE_VERSION}" ] || \
413 die "'${PACKAGE_NAME}-${PACKAGE_VERSION}' cannot be released"
415 [ "${PACKAGE_VERSION%.0}" = "${PACKAGE_VERSION}" ] || \
416 do_branch
417 do_tag
421 do_release_step_prep() {
422 do_version tag remove in-development
423 # reset RELEASE_VERSION now to allow release version to be detected
424 export RELEASE_VERSION=
426 do_release_step_commit() { do_commit; }
428 do_release_step_branch_bump() {
429 local TYPE="$1"
430 echo "Bump ${TYPE} version and add tag:"
431 do_version_bump ${TYPE}
432 do_version_tag_add in-development
434 do_release_step_branch() {
435 do_svn switch "${PACKAGE_BRANCH}"
436 package_info_load
437 do_version_commit "$(do_release_step_branch_bump micro)"
438 do_svn switch "${SVN_URL}"
439 package_info_load
441 do_release_step_bump() {
442 # major and minor releases require branch version update too
443 [ "${RELEASE_TYPE}" = "micro" ] || do_release_step_branch
444 # bump the current tree version as required.
445 do_version_commit "$(do_release_step_branch_bump "${RELEASE_TYPE}")"
447 # archive NEWS and create new one from template
448 do_svn move "NEWS" "NEWS-${RELEASE_VERSION}"
450 [ "${RELEASE_DRY_RUN}" ] || cat >NEWS <<NEWS
451 This file should include items worth mentioning in the
452 OpenOCD ${PACKAGE_RELEASE} source archive release.
454 The following areas of OpenOCD functionality changed in this release:
456 JTAG Layer:
457 Target Layer:
458 Flash Layer:
459 Board, Target, and Interface Configuration Scripts:
460 Documentation:
461 Build and Release:
463 For more details about what has changed since the last release,
464 see the ChangeLog associated with this source archive. For older NEWS,
465 see the NEWS files associated with each release (i.e. NEWS-<version>).
467 For more information about contributing test reports, bug fixes, or new
468 features and device support, please read the new Developer Manual (or
469 the BUGS and PATCHES files in the source archive).
470 NEWS
472 MSG=<<MSG
473 Archive released NEWS file: NEWS -> NEWS-${RELEASE_VERSION}
474 Create new NEWS file from relesse script template.
476 do_svn commit -m "${MSG}" NEWS NEWS-${RELEASE_VERSION}
478 do_release_step_package() {
479 local A=${PACKAGE_TAG}
480 local B=${A/https/http}
481 local PACKAGE_BUILD=${B/${USER}@/}
482 do_svn switch "${PACKAGE_BUILD}"
483 do_stage
484 do_clean
487 do_release_step_1() { do_release_step_prep; }
488 do_release_step_2() { do_release_step_commit; }
489 do_release_step_3() { do_release_step_bump; }
490 do_release_step_4() { do_release_step_package; }
492 do_release_check() {
493 echo -n "Are you sure you want to release '${PACKAGE_RELEASE}'?"
494 read ANSWER
495 if [ "${ANSWER}" != 'y' ]; then
496 echo "Live release aborted!"
497 exit 0
500 do_countdown() {
501 echo -n "$1 in "
502 for i in $(seq 5 -1 1); do
503 echo -n "$i, "
504 done
505 echo "go!"
508 do_release() {
509 package_info_load
510 package_info_show
512 if [ -z "${RELEASE_DRY_RUN}" ]; then
513 do_release_check
514 do_countdown "Starting live release"
517 local i=
518 for i in $(seq 1 4); do
519 eval "do_release_step_${i}"
520 done
522 do_all() { do_release "$@"; }
524 do_reset() {
525 maybe_bootstrap
526 maybe_configure
527 do_clean_all
528 svn revert configure.in
531 OPTIONS=$(getopt -o V --long live -n $0 -- "$@")
532 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
533 eval set -- "${OPTIONS}"
534 while true; do
535 case "$1" in
536 --live)
537 export RELEASE_DRY_RUN=
538 shift
541 exec $0 info
544 shift
545 break
548 echo "Internal error"
549 exit 1
551 esac
552 done
554 CMD=$1
555 [ "${CMD}" ] || usage
556 shift
558 ACTION_CMDS="bootstrap|configure|build|changelog|package|stage|clean"
559 MISC_CMDS="all|info|version|tag|branch|commit|release|reset|help|usage"
560 CLEAN_CMDS="build_clean|changelog_clean|package_clean|stage_clean|clean_all"
561 CMDS="|${ACTION_CMDS}|${CLEAN_CMDS}|${MISC_CMDS}|"
562 is_command() { echo "${CMDS}" | grep "|$1|" >/dev/null; }
564 if is_command "${CMD}"; then
565 eval "do_${CMD}" "$@"
566 else
567 echo "error: unknown command: '${CMD}'"
568 usage