Add script to automate most of the release process.
[openocd.git] / tools / release.sh
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).
5
6 ## set these to control the build process
7 #CONFIG_OPTS=""
8 #MAKE_OPTS=""
9
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=
14
15 die() {
16 echo "$@" >&2
17 exit 1
18 }
19
20 svn_info_get() {
21 svn info | grep "$1" | cut -d':' -f2- | cut -c2-
22 }
23
24 svn_setup_load() {
25 SVN_ROOT="$(svn_info_get 'Repository Root')"
26 SVN_URL="$(svn_info_get 'URL')"
27
28 SVN_TRUNK="${SVN_ROOT}/trunk"
29
30 SVN_BRANCHES="${SVN_ROOT}/branches"
31 PACKAGE_BRANCH="${SVN_BRANCHES}/${PACKAGE_RELEASE}"
32
33 SVN_TAGS="${SVN_ROOT}/tags"
34 PACKAGE_TAG="${SVN_TAGS}/${PACKAGE_RELEASE}"
35
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"
43 fi
44 }
45 svn_setup_show() {
46 cat <<INFO
47 Release Type: ${RELEASE_TYPE}
48 Branch URL: ${PACKAGE_BRANCH}
49 Tag URL: ${PACKAGE_TAG}
50 INFO
51 }
52
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: $@"
60 ;;
61 copy|move)
62 do_svn_echo_msg "$@"
63 echo "From: ${4:-$2}"
64 echo " To: ${5:-$3}"
65 ;;
66 *)
67 local ACTION="$1"
68 shift
69 echo "svn: ${ACTION}: $@"
70 ;;
71 esac
72 }
73 do_svn() {
74 do_svn_echo "$@"
75 [ "${RELEASE_DRY_RUN}" ] || svn "$@"
76 }
77
78
79 package_info_load_name() {
80 grep AC_INIT configure.in | perl -ne 's/^.+\(\[([-\w]*)\],.+$/$1/ and print'
81 }
82 package_info_load_version() {
83 grep AC_INIT configure.in | perl -ne 's/^.+\[([-\w\.]*)\],$/$1/ and print'
84 }
85
86 package_info_load() {
87 [ -f "configure.in" ] || \
88 die "package_info_load: configure.in is missing"
89
90 PACKAGE_NAME="$(package_info_load_name)"
91 # todo: fix this
92 PACKAGE_TARNAME="${PACKAGE_NAME}"
93
94 PACKAGE_VERSION="$(package_info_load_version)"
95 [ "${RELEASE_VERSION}" ] || \
96 RELEASE_VERSION=${PACKAGE_VERSION/-in-development/}
97
98 [ "${PACKAGE_NAME}" -a "${PACKAGE_VERSION}" ] || \
99 die "package information is missing from configure script"
100
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#*.}"
109
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}"
115 fi
116 }
117
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
132 }
133
134 usage() {
135 cat << USAGE
136 usage: $0 <command>
137
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
142
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.
147
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.
152
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.
157
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.
164
165 For more information about this script, see the Release Processes page
166 in the OpenOCD Developer's Manual (doc/manual/release.txt).
167
168 WARNING: This script should be used by the Release Manager ONLY.
169 USAGE
170 exit 0
171 }
172 do_usage() { usage; }
173 do_help() { usage; }
174
175 do_info_show() {
176 echo "Current Release Analysis:"
177 package_info_show
178 svn_setup_show
179 }
180
181 do_info() {
182 package_info_load
183 svn_setup_load
184 do_info_show
185 }
186
187 do_bootstrap() {
188 echo -n "Bootstrapping..."
189 ./bootstrap 2>&1 | perl tools/logger.pl > "release-bootstrap.log"
190 }
191 maybe_bootstrap() { [ -f "configure" ] || do_bootstrap; }
192
193 do_configure() {
194 maybe_bootstrap
195 echo -n "Configuring..."
196 ./configure ${CONFIG_OPTS} 2>&1 | perl tools/logger.pl > "release-config.log"
197 }
198 maybe_configure() { [ -f "Makefile" ] || do_configure; }
199
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"
207 }
208 maybe_build() { [ -f "src/openocd" ] || do_build; }
209 do_build_clean() { [ -f Makefile ] && make maintainer-clean >/dev/null; }
210
211 maybe_rebuild() {
212 if [ -f "configure" ]; then
213 echo "Re-running autoconf..."
214 autoconf
215 echo "Re-running automake..."
216 automake
217 fi
218 if [ -f "Makefile" ]; then
219 do_configure
220 do_build
221 fi
222 }
223
224 do_changelog() {
225 echo "Updating working copy to HEAD..."
226 do_svn update
227 echo "Creating ChangeLog..."
228 svn2cl -i --authors AUTHORS.ChangeLog
229 }
230 maybe_changelog() {
231 if [ -z "${RELEASE_DRY_RUN}" ] \
232 || [ ! -f ChangeLog ] \
233 || [ "$(cat ChangeLog | wc -l)" -lt 2 ]
234 then
235 do_changelog
236 fi
237 }
238 do_changelog_clean() {
239 do_svn revert ChangeLog
240 }
241
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"
248 }
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
254 }
255
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/
265 }
266 do_stage_clean() { rm -v -f -r archives; }
267
268 do_clean() {
269 do_build_clean
270 do_package_clean
271 rm -v -f configure
272
273 svn revert configure.in
274 rm -v -f release-*.log
275 }
276 do_clean_all() {
277 do_clean
278 do_changelog_clean
279 do_stage_clean
280 }
281
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
291 }
292
293 do_version_sed() {
294 local OLD_VERSION="${PACKAGE_VERSION}"
295 local NEW_VERSION="$1"
296 local MSG="$2"
297
298 sed -i -e "/AC_INIT/ s|${OLD_VERSION}|${NEW_VERSION}|" configure.in
299 package_info_load
300 echo "${MSG}: ${OLD_VERSION} -> ${NEW_VERSION}"
301 }
302 do_version_bump_sed() {
303 local NEW_VERSION="$1"
304 [ -z "${PACKAGE_VERSION_TAGS}" ] || \
305 NEW_VERSION="${NEW_VERSION}${PACKAGE_VERSION_TAGS}"
306
307 do_version_sed "${NEW_VERSION}" \
308 "Bump ${CMD} package version number"
309 }
310 do_version_bump_major() {
311 has_version_tag 'rc\d' do_version_
312 do_version_bump_sed "$((PACKAGE_MAJOR + 1)).0.0"
313 }
314 do_version_bump_minor() {
315 do_version_bump_sed "${PACKAGE_MAJOR}.$((PACKAGE_MINOR + 1)).0"
316 }
317 do_version_bump_micro() {
318 do_version_bump_sed "${PACKAGE_MAJOR_AND_MINOR}.$((PACKAGE_MICRO + 1))"
319 }
320 do_version_bump_rc() {
321 die "patch missing: -rc support is not implemented"
322 }
323 do_version_bump() {
324 CMD="$1"
325 shift
326 case "${CMD}" in
327 major|minor|micro|rc)
328 eval "do_version_bump_${CMD}"
329 ;;
330 *)
331 do_version_usage
332 ;;
333 esac
334 }
335
336 has_version_tag() {
337 test "${PACKAGE_VERSION/-${TAG}/}" != "${PACKAGE_VERSION}"
338 }
339
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"
345 }
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"
351 }
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
361 ;;
362 *)
363 do_version_usage
364 ;;
365 esac
366 }
367
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
372 }
373
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
382 ;;
383 commit)
384 local MSG="$1"
385 [ "${MSG}" ] || die "usage: $0 version commit <message>"
386 do_version_commit "${MSG}"
387 maybe_rebuild
388 ;;
389 *)
390 do_version_usage
391 ;;
392 esac
393 }
394
395
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}"
401 }
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}"
407 }
408 do_commit() {
409 package_info_load
410 svn_setup_load
411
412 [ "${PACKAGE_VERSION/in-development/}" = "${PACKAGE_VERSION}" ] || \
413 die "'${PACKAGE_NAME}-${PACKAGE_VERSION}' cannot be released"
414
415 [ "${PACKAGE_VERSION%.0}" = "${PACKAGE_VERSION}" ] || \
416 do_branch
417 do_tag
418 }
419
420
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=
425 }
426 do_release_step_commit() { do_commit; }
427
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
433 }
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
440 }
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}")"
446
447 # archive NEWS and create new one from template
448 do_svn move "NEWS" "NEWS-${RELEASE_VERSION}"
449
450 [ "${RELEASE_DRY_RUN}" ] || cat >NEWS <<NEWS
451 This file should include items worth mentioning in the
452 OpenOCD ${PACKAGE_RELEASE} source archive release.
453
454 The following areas of OpenOCD functionality changed in this release:
455
456 JTAG Layer:
457 Target Layer:
458 Flash Layer:
459 Board, Target, and Interface Configuration Scripts:
460 Documentation:
461 Build and Release:
462
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>).
466
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
471
472 MSG=<<MSG
473 Archive released NEWS file: NEWS -> NEWS-${RELEASE_VERSION}
474 Create new NEWS file from relesse script template.
475 MSG
476 do_svn commit -m "${MSG}" NEWS NEWS-${RELEASE_VERSION}
477 }
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
485 }
486
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; }
491
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
498 fi
499 }
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!"
506 }
507
508 do_release() {
509 package_info_load
510 package_info_show
511
512 if [ -z "${RELEASE_DRY_RUN}" ]; then
513 do_release_check
514 do_countdown "Starting live release"
515 fi
516
517 local i=
518 for i in $(seq 1 4); do
519 eval "do_release_step_${i}"
520 done
521 }
522 do_all() { do_release "$@"; }
523
524 do_reset() {
525 maybe_bootstrap
526 maybe_configure
527 do_clean_all
528 svn revert configure.in
529 }
530
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
539 ;;
540 -V)
541 exec $0 info
542 ;;
543 --)
544 shift
545 break
546 ;;
547 *)
548 echo "Internal error"
549 exit 1
550 ;;
551 esac
552 done
553
554 CMD=$1
555 [ "${CMD}" ] || usage
556 shift
557
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; }
563
564 if is_command "${CMD}"; then
565 eval "do_${CMD}" "$@"
566 else
567 echo "error: unknown command: '${CMD}'"
568 usage
569 fi

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)