Fix some man page typos
[oweals/openssl.git] / dev / release.sh
1 #! /bin/bash -e
2 # Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the Apache License 2.0 (the "License").  You may not use
5 # this file except in compliance with the License.  You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
8
9 # This is the most shell agnostic way to specify that POSIX rules.
10 POSIXLY_CORRECT=1
11
12 usage () {
13     cat <<EOF
14 Usage: release.sh [ options ... ]
15
16 --alpha         Start or increase the "alpha" pre-release tag.
17 --next-beta     Switch to the "beta" pre-release tag after alpha release.
18                 It can only be given with --alpha.
19 --beta          Start or increase the "beta" pre-release tag.
20 --final         Get out of "alpha" or "beta" and make a final release.
21                 Implies --branch.
22
23 --branch        Create a release branch 'openssl-{major}.{minor}.x',
24                 where '{major}' and '{minor}' are the major and minor
25                 version numbers.
26
27 --reviewer=<id> The reviewer of the commits.
28 --local-user=<keyid>
29                 For the purpose of signing tags and tar files, use this
30                 key (default: use the default e-mail address’ key).
31
32 --no-upload     Don't upload to upload@dev.openssl.org.
33 --no-update     Don't perform 'make update'.
34 --verbose       Verbose output.
35 --debug         Include debug output.  Implies --no-upload.
36
37 --force         Force execution
38
39 --help          This text
40 --manual        The manual
41
42 If none of --alpha, --beta, or --final are given, this script tries to
43 figure out the next step.
44 EOF
45     exit 0
46 }
47
48 # Set to one of 'major', 'minor', 'alpha', 'beta' or 'final'
49 next_method=
50 next_method2=
51
52 do_branch=false
53 warn_branch=false
54
55 do_clean=true
56 do_upload=true
57 do_update=true
58 DEBUG=:
59 VERBOSE=:
60 git_quiet=-q
61
62 force=false
63
64 do_help=false
65 do_manual=false
66
67 tagkey=' -s'
68 gpgkey=
69 reviewers=
70
71 upload_address=upload@dev.openssl.org
72
73 TEMP=$(getopt -l 'alpha,next-beta,beta,final' \
74               -l 'branch' \
75               -l 'no-upload,no-update' \
76               -l 'verbose,debug' \
77               -l 'local-user:' \
78               -l 'reviewer:' \
79               -l 'force' \
80               -l 'help,manual' \
81               -n release.sh -- - "$@")
82 eval set -- "$TEMP"
83 while true; do
84     case $1 in
85     --alpha | --beta | --final )
86         next_method=$(echo "x$1" | sed -e 's|^x--||')
87         if [ -z "$next_method2" ]; then
88             next_method2=$next_method
89         fi
90         shift
91         if [ "$next_method" = 'final' ]; then
92             do_branch=true
93         fi
94         ;;
95     --next-beta )
96         next_method2=$(echo "x$1" | sed -e 's|^x--next-||')
97         shift
98         ;;
99     --branch )
100         do_branch=true
101         warn_branch=true
102         shift
103         ;;
104     --no-upload )
105         do_upload=false
106         shift
107         ;;
108     --no-update )
109         do_update=false
110         shift
111         ;;
112     --verbose )
113         VERBOSE=echo
114         git_quiet=
115         shift
116         ;;
117     --debug )
118         DEBUG=echo
119         do_upload=false
120         shift
121         ;;
122     --local-user )
123         shift
124         tagley=" -u $1"
125         gpgkey=" -u $1"
126         shift
127         ;;
128     --reviewer )
129         reviewers="$reviewers $1=$2"
130         shift
131         shift
132         ;;
133     --force )
134         force=true
135         shift
136         ;;
137     --help )
138         usage
139         exit 0
140         ;;
141     --manual )
142         sed -e '1,/^### BEGIN MANUAL/d' \
143             -e '/^### END MANUAL/,$d' \
144             < "$0" \
145             | pod2man \
146             | man -l -
147         exit 0
148         ;;
149     -- )
150         shift
151         break
152         ;;
153     * )
154         echo >&2 "Unknown option $1"
155         shift
156         exit 1
157         ;;
158     esac
159 done
160
161 $DEBUG >&2 "DEBUG: \$next_method=$next_method"
162 $DEBUG >&2 "DEBUG: \$next_method2=$next_method2"
163
164 $DEBUG >&2 "DEBUG: \$do_branch=$do_branch"
165
166 $DEBUG >&2 "DEBUG: \$do_upload=$do_upload"
167 $DEBUG >&2 "DEBUG: \$do_update=$do_update"
168 $DEBUG >&2 "DEBUG: \$DEBUG=$DEBUG"
169 $DEBUG >&2 "DEBUG: \$VERBOSE=$VERBOSE"
170 $DEBUG >&2 "DEBUG: \$git_quiet=$git_quiet"
171
172 case "$next_method+$next_method2" in
173     major+major | minor+minor )
174         # These are expected
175         ;;
176     alpha+alpha | alpha+beta | beta+beta | final+final | + | +beta )
177         # These are expected
178         ;;
179     * )
180         echo >&2 "Internal option error ($next_method, $next_method2)"
181         exit 1
182         ;;
183 esac
184
185 # Verbosity feed for certain commands
186 VERBOSITY_FIFO=/tmp/openssl-$$.fifo
187 mkfifo -m 600 $VERBOSITY_FIFO
188 ( cat $VERBOSITY_FIFO | while read L; do $VERBOSE "> $L"; done ) &
189 exec 42>$VERBOSITY_FIFO
190 trap "exec 42>&-; rm $VERBOSITY_FIFO" 0 2
191
192 # Setup ##############################################################
193
194 # Make sure we're in the work directory
195 cd $(dirname $0)/..
196 HERE=$(pwd)
197
198 # Check that we have the scripts that define functions we use
199 found=true
200 for fn in "$HERE/dev/release-aux/release-version-fn.sh" \
201           "$HERE/dev/release-aux/release-state-fn.sh"; do
202     if ! [ -f "$fn" ]; then
203         echo >&2 "'$fn' is missing"
204         found=false
205     fi
206 done
207 if ! $found; then
208     exit 1
209 fi
210
211 # Load version functions
212 . $HERE/dev/release-aux/release-version-fn.sh
213 . $HERE/dev/release-aux/release-state-fn.sh
214
215 # Make sure it's a branch we recognise
216 orig_branch=$(git rev-parse --abbrev-ref HEAD)
217 if (echo "$orig_branch" \
218         | grep -E -q \
219                -e '^master$' \
220                -e '^OpenSSL_[0-9]+_[0-9]+_[0-9]+[a-z]*-stable$' \
221                -e '^openssl-[0-9]+\.[0-9]+\.x$'); then
222     :
223 elif $force; then
224     :
225 else
226     echo >&2 "Not in master or any recognised release branch"
227     echo >&2 "Please 'git checkout' an approprite branch"
228     exit 1
229 fi
230
231 # Initialize #########################################################
232
233 echo "== Initializing work tree"
234
235 get_version
236
237 # Generate a cloned directory name
238 clone_branch="openssl-$SERIES.x"
239 release_clone="$clone_branch-release-tmp"
240
241 echo "== Work tree will be in $release_clone"
242
243 # Make a clone in a subdirectory and move there
244 if ! [ -d "$release_clone" ]; then
245     $VERBOSE "== Cloning to $release_clone"
246     git clone $git_quiet -b "$orig_branch" . "$release_clone"
247 fi
248 cd "$release_clone"
249
250 get_version
251
252 current_branch="$(git rev-parse --abbrev-ref HEAD)"
253 new_branch="openssl-$SERIES.x"
254
255 # Check that we're still on the same branch, or on a release branch
256 if [ "$current_branch" = "$orig_branch" ]; then
257     :
258 elif [ "$current_branch" = "$new_branch" ]; then
259     :
260 else
261    echo >&2 "The cloned sub-directory '$release_clone' is on a branch"
262    echo >&2 "other than '$current_branch' or '$new_branch'"
263    echo >&2 "Please 'cd \"$(pwd)\"; git checkout $current_branch'"
264    exit 1
265 fi
266
267 if $do_branch; then
268     if [ "$current_branch" = "$new_branch" ]; then
269         do_branch=false
270     fi
271     if ! $do_branch && $warn_branch; then
272         echo >&2 "Warning: --branch ignored, we're already in a release branch"
273     fi
274 fi
275
276 SOURCEDIR=$(pwd)
277 $DEBUG >&2 "DEBUG: Source directory is $SOURCEDIR"
278
279 # Release ############################################################
280
281 # We always expect to start from a state of development
282 if [ "$TYPE" != 'dev' ]; then
283     echo >&2 "Not in a development branch"
284     echo >&2 "Have a look at the git log in $release_clone, it may be that"
285     echo >&2 "a previous crash left it in an intermediate state and that"
286     echo >&2 "need to drop the top commit:"
287     echo >&2 ""
288     echo >&2 "(cd $release_clone; git reset --hard HEAD^)"
289     echo >&2 "# WARNING! LOOK BEFORE YOU ACT"
290     exit 1
291 fi
292
293 # We only create a release branch if the patch number is zero
294 if [ $PATCH -ne 0 ]; then
295     if $do_branch; then
296         echo >&2 "Warning! We're already in a release branch; --branch ignored"
297     fi
298     do_branch=false
299 fi
300
301 # Update the version information.  This won't save anything anywhere, yet,
302 # but does check for possible next_method errors before we do bigger work.
303 next_release_state "$next_method"
304
305 if $do_branch; then
306     $VERBOSE "== Creating a release branch: $new_branch"
307     git checkout $git_quiet -b "$new_branch"
308 fi
309
310 echo "== Configuring OpenSSL for update and release.  This may take a bit of time"
311
312 ./Configure cc >&42
313
314 $VERBOSE "== Checking source file updates"
315
316 make update >&42
317
318 if [ -n "$(git status --porcelain)" ]; then
319     $VERBOSE "== Committing updates"
320     git add -u
321     git commit $git_quiet -m 'make update'
322     if [ -n "$reviewers" ]; then
323         addrev --nopr $reviewers
324     fi
325 fi
326
327 # Write the version information we updated
328 set_version
329
330 if [ -n "$PRE_LABEL" ]; then
331     release="$VERSION-$PRE_RELEASE_TAG$BUILD_METADATA"
332     release_text="$SERIES$BUILD_METADATA $PRE_LABEL $PRE_NUM"
333     announce_template=openssl-announce-pre-release.tmpl
334 else
335     release="$VERSION$BUILD_METADATA"
336     release_text="$release"
337     announce_template=openssl-announce-release.tmpl
338 fi
339 tag="openssl-$release"
340 $VERBOSE "== Updated version information to $release"
341
342 $VERBOSE "== Updating files with release date for $release : $RELEASE_DATE"
343 for fixup in "$HERE/dev/release-aux"/fixup-*-release.pl; do
344     file="$(basename "$fixup" | sed -e 's|^fixup-||' -e 's|-release\.pl$||')"
345     $VERBOSE "> $file"
346     RELEASE="$release" RELEASE_TEXT="$release_text" RELEASE_DATE="$RELEASE_DATE" \
347         perl -pi $fixup $file
348 done
349
350 $VERBOSE "== Comitting updates and tagging"
351 git add -u
352 git commit $git_quiet -m "Prepare for release of $release_text"
353 if [ -n "$reviewers" ]; then
354     addrev --nopr $reviewers
355 fi
356 echo "Tagging release with tag $tag.  You may need to enter a pass phrase"
357 git tag$tagkey "$tag" -m "OpenSSL $release release tag"
358
359 tarfile=openssl-$release.tar
360 tgzfile=$tarfile.gz
361 announce=openssl-$release.txt
362
363 echo "== Generating tar, hash and announcement files.  This make take a bit of time"
364
365 $VERBOSE "== Making tarfile: $tgzfile"
366 # Unfortunately, util/mktar.sh does verbose output on STDERR...  for good
367 # reason, but it means we don't display errors unless --verbose
368 ./util/mktar.sh --tarfile="../$tarfile" 2>&1 \
369     | while read L; do $VERBOSE "> $L"; done
370
371 if ! [ -f "../$tgzfile" ]; then
372     echo >&2 "Where did the tarball end up? (../$tgzfile)"
373     exit 1
374 fi
375
376 $VERBOSE "== Generating checksums: $tgzfile.sha1 $tgzfile.sha256"
377 openssl sha1 < "../$tgzfile" | \
378     (IFS='='; while read X H; do echo $H; done) > "../$tgzfile.sha1"
379 openssl sha256 < "../$tgzfile" | \
380     (IFS='='; while read X H; do echo $H; done) > "../$tgzfile.sha256"
381 length=$(wc -c < "../$tgzfile")
382 sha1hash=$(cat "../$tgzfile.sha1")
383 sha256hash=$(cat "../$tgzfile.sha256")
384
385 $VERBOSE "== Generating announcement text: $announce"
386 # Hack the announcement template
387 cat "$HERE/dev/release-aux/$announce_template" \
388     | sed -e "s|\\\$release_text|$release_text|g" \
389           -e "s|\\\$release|$release|g" \
390           -e "s|\\\$series|$SERIES|g" \
391           -e "s|\\\$label|$PRE_LABEL|g" \
392           -e "s|\\\$tarfile|$tgzfile|" \
393           -e "s|\\\$length|$length|" \
394           -e "s|\\\$sha1hash|$sha1hash|" \
395           -e "s|\\\$sha256hash|$sha256hash|" \
396     | perl -p "$HERE/dev/release-aux/fix-title.pl" \
397     > "../$announce"
398               
399 $VERBOSE "== Generating signatures: $tgzfile.asc $announce.asc"
400 rm -f "../$tgzfile.asc" "../$announce.asc"
401 echo "Signing the release files.  You may need to enter a pass phrase"
402 gpg$gpgkey --use-agent -sba "../$tgzfile"
403 gpg$gpgkey --use-agent -sta --clearsign "../$announce"
404
405 # We finish off by resetting all files, so we don't have to update
406 # files with release dates again
407 $VERBOSE "== Reset all files to their pre-commit contents"
408 git reset $git_quiet HEAD^ -- .
409 git checkout -- .
410
411 if $do_upload; then
412     (
413         if [ "$VERBOSE" != ':' ]; then
414             echo "progress"
415         fi
416         echo "put ../$tgzfile"
417         echo "put ../$tgzfile.sha1"
418         echo "put ../$tgzfile.sha256"
419         echo "put ../$tgzfile.asc"
420         echo "put ../$announce.asc"
421     ) \
422     | sftp "$upload_address"
423 fi
424
425 # Post-release #######################################################
426
427 prev_release_text="$release_text"
428 prev_release_date="$RELEASE_DATE"
429
430 next_release_state "$next_method2"
431 set_version
432
433 release="$VERSION-$PRE_RELEASE_TAG$BUILD_METADATA"
434 release_text="$VERSION$BUILD_METADATA"
435 if [ -n "$PRE_LABEL" ]; then
436     release_text="$SERIES$BUILD_METADATA $PRE_LABEL $PRE_NUM"
437 fi
438 $VERBOSE "== Updated version information to $release"
439
440 $VERBOSE "== Updating files for $release :"
441 for fixup in "$HERE/dev/release-aux"/fixup-*-postrelease.pl; do
442     file="$(basename "$fixup" | sed -e 's|^fixup-||' -e 's|-postrelease\.pl$||')"
443     $VERBOSE "> $file"
444     RELEASE="$release" RELEASE_TEXT="$release_text" \
445         PREV_RELEASE_TEXT="$prev_release_text" \
446         PREV_RELEASE_DATE="$prev_release_date" \
447         perl -pi $fixup $file
448 done
449
450 $VERBOSE "== Comitting updates"
451 git add -u
452 git commit $git_quiet -m "Prepare for $release_text"
453 if [ -n "$reviewers" ]; then
454     addrev --nopr $reviewers
455 fi
456
457 if $do_branch; then
458     $VERBOSE "== Going back to the main branch $current_branch"
459     git checkout $git_quiet "$current_branch"
460
461     get_version
462     next_release_state "minor"
463     set_version
464
465     release="$VERSION-$PRE_RELEASE_TAG$BUILD_METADATA"
466     release_text="$SERIES$BUILD_METADATA"
467     $VERBOSE "== Updated version information to $release"
468
469     $VERBOSE "== Updating files for $release :"
470     for fixup in "$HERE/dev/release-aux"/fixup-*-postrelease.pl; do
471         file="$(basename "$fixup" | sed -e 's|^fixup-||' -e 's|-postrelease\.pl$||')"
472         $VERBOSE "> $file"
473         RELEASE="$release" RELEASE_TEXT="$release_text" \
474             perl -pi $fixup $file
475     done
476
477     $VERBOSE "== Comitting updates"
478     git add -u
479     git commit $git_quiet -m "Prepare for $release_text"
480     if [ -n "$reviewers" ]; then
481         addrev --nopr $reviewers
482     fi
483 fi
484
485 # Done ###############################################################
486     
487 $VERBOSE "== Done"
488
489 cat <<EOF
490
491 ======================================================================
492 The release is done, and involves a few commits for you to deal with.
493 It has all been done in a clone of this workspace, see details below.
494 EOF
495 if $do_branch; then
496     cat <<EOF
497 Additionally, a release branch has been created for you, so you need
498 to look for new commits in two places.
499 EOF
500 fi
501
502 if $do_release; then
503     cat <<EOF
504
505 These files were uploaded to $upload_address:
506
507     ../$tgzfile
508     ../$tgzfile.sha1
509     ../$tgzfile.sha256
510     ../$tgzfile.asc
511     ../$announce.asc
512 EOF
513 fi
514
515 cat <<EOF
516
517 Release worktree:   $release_clone
518 EOF
519 if [ "$current_branch" != "$new_branch" ]; then
520     cat <<EOF
521 Current branch:     $current_branch
522 EOF
523 fi
524 if $do_branch; then
525     cat <<EOF
526 New release branch: $new_branch
527 EOF
528 fi
529
530 cat <<EOF
531 ======================================================================
532 EOF
533
534 cat <<EOF
535 If something went wrong and you want to start over, all you need is to
536 remove the release worktree:
537
538     rm -rf $release_clone
539
540 If a tarball was uploaded, you must also clean that away, or ask you
541 kind OpenSSL sysadmin to do so.
542 EOF
543
544 exit 0
545
546 # cat is inconsequential, it's only there to fend off zealous shell parsers
547 # that parse all the way here.
548 cat <<EOF
549 ### BEGIN MANUAL
550 =pod
551
552 =head1 NAME
553
554 release.sh - OpenSSL release script
555
556 =head1 SYNOPSIS
557
558 B<release.sh>
559 [
560 B<--alpha> |
561 B<--next-beta> |
562 B<--beta> |
563 B<--final> |
564 B<--branch> |
565 B<--local-user>=I<keyid> |
566 B<--reviewer>=I<id> |
567 B<--no-upload> |
568 B<--no-update> |
569 B<--verbose> |
570 B<--debug> |
571 B<--help> |
572 B<--manual>
573 ]
574
575 =head1 DESCRIPTION
576
577 B<release.sh> creates an OpenSSL release, given current worktree conditions.
578 It will refuse to work unless the current branch is C<master> or a release
579 branch (see L</RELEASE BRANCHES AND TAGS> below for a discussion on those).
580
581 B<release.sh> tries to be smart and figure out the next release if no hints
582 are given through options, and will exit with an error in ambiguous cases.
583
584 B<release.sh> always clones the current workspace into a sub-directory
585 named C<< openssl-I<SERIES>-tmp >>, where C<< I<SERIES> >> is taken from
586 the available version information in the source.
587
588 =head1 OPTIONS
589
590 =over 4
591
592 =item B<--alpha>, B<--beta>
593
594 Set the state of this branch to indicate that alpha or beta releases are
595 to be done.
596
597 B<--alpha> is only acceptable if the I<PATCH> version number is zero and
598 the current state is "in development" or that alpha releases are ongoing.
599
600 B<--beta> is only acceptable if the I<PATCH> version number is zero and
601 that alpha or beta releases are ongoing.
602
603 =item B<--next-beta>
604
605 Use together with B<--alpha> to switch to beta releases after the current
606 release is done.
607
608 =item B<--final>
609
610 Set the state of this branch to indicate that regular releases are to be
611 done.  This is only valid if alpha or beta releases are currently ongoing.
612
613 This implies B<--branch>.
614
615 =item B<--branch>
616
617 Create a branch specific for the I<SERIES>.x release series, if it doesn't
618 already exist, and switch to it.  The exact branch name will be
619 C<< openssl-I<SERIES>.x >>.
620
621 =item B<--no-upload>
622
623 Don't upload the produced files.
624
625 =item B<--no-update>
626
627 Don't run C<make update>.
628
629 =item B<--verbose>
630
631 Verbose output.
632
633 =item B<--debug>
634
635 Display extra debug output.  Implies B<--no-upload>
636
637 =item B<--local-user>=I<keyid>
638
639 Use I<keyid> as the local user for C<git tag> and for signing with C<gpg>.
640
641 If not given, then the default e-mail address' key is used.
642
643 =item B<--reviewer>=I<id>
644
645 Add I<id> to the set of reviewers for the commits performed by this script.
646 Multiple reviewers are allowed.
647
648 If no reviewer is given, you will have to run C<addrev> manually, which
649 means retagging a release commit manually as well.
650
651 =item B<--force>
652
653 Force execution.  Precisely, the check that the current branch is C<master>
654 or a release branch is not done.
655
656 =item B<--help>
657
658 Display a quick help text and exit.
659
660 =item B<--manual>
661
662 Display this manual and exit.
663
664 =back
665
666 =head1 RELEASE BRANCHES AND TAGS
667
668 Prior to OpenSSL 3.0, the release branches were named
669 C<< OpenSSL_I<SERIES>-stable >>, and the release tags were named
670 C<< OpenSSL_I<VERSION> >> for regular releases, or
671 C<< OpenSSL_I<VERSION>-preI<n> >> for pre-releases.
672
673 From OpenSSL 3.0 ongoing, the release branches are named
674 C<< openssl-I<SERIES>.x >>, and the release tags are named
675 C<< openssl-I<VERSION> >> for regular releases, or
676 C<< openssl-I<VERSION>-alphaI<n> >> for alpha releases
677 and C<< openssl-I<VERSION>-betaI<n> >> for beta releases.
678
679 B<release.sh> recognises both forms.
680
681 =head1 VERSION AND STATE
682
683 With OpenSSL 3.0, all the version and state information is in the file
684 F<VERSION>, where the following variables are used and changed:
685
686 =over 4
687
688 =item B<MAJOR>, B<MINOR>, B<PATCH>
689
690 The three part of the version number.
691
692 =item B<PRE_RELEASE_TAG>
693
694 The indicator of the current state of the branch.  The value may be one pf:
695
696 =over 4
697
698 =item C<dev>
699
700 This branch is "in development".  This is typical for the C<master> branch
701 unless there are ongoing alpha or beta releases.
702
703 =item C<< alphaI<n> >> or C<< alphaI<n>-dev >>
704
705 This branch has alpha releases going on.  C<< alphaI<n>-dev >> is what
706 should normally be seen in the git workspace, indicating that
707 C<< alphaI<n> >> is in development.  C<< alphaI<n> >> is what should be
708 found in the alpha release tar file.
709
710 =item C<< alphaI<n> >> or C<< alphaI<n>-dev >>
711
712 This branch has beta releases going on.  The details are otherwise exactly
713 as for alpha.
714
715 =item I<no value>
716
717 This is normally not seen in the git workspace, but should always be what's
718 found in the tar file of a regular release.
719
720 =back
721
722 =item B<RELEASE_DATE>
723
724 This is normally empty in the git workspace, but should always have the
725 release date in the tar file of any release.
726
727 =back
728
729 =head1 COPYRIGHT
730
731 Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
732
733 Licensed under the Apache License 2.0 (the "License").  You may not use
734 this file except in compliance with the License.  You can obtain a copy
735 in the file LICENSE in the source distribution or at
736 L<https://www.openssl.org/source/license.html>.
737
738 =cut
739 ### END MANUAL
740 EOF