Include the original HEAD in the porcelain output
[tools.git] / release-tools / stage-release.sh
1 #! /bin/bash -e
2 # Copyright 2020-2023 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 # Force C locale because some commands (like date +%b) relies
13 # on the current locale.
14 export LC_ALL=C
15
16 usage () {
17     cat <<EOF
18 Usage: stage-release.sh [ options ... ]
19
20 --alpha         Start or increase the "alpha" pre-release tag.
21 --next-beta     Switch to the "beta" pre-release tag after alpha release.
22                 It can only be given with --alpha.
23 --beta          Start or increase the "beta" pre-release tag.
24 --final         Get out of "alpha" or "beta" and make a final release.
25                 Implies --branch.
26
27 --branch        Create a release branch 'openssl-{major}.{minor}',
28                 where '{major}' and '{minor}' are the major and minor
29                 version numbers.
30
31 --clean-worktree
32                 Expect the current worktree to be clean, and uses it directly.
33                 This implies the current branch of the worktree will be updated.
34
35 --branch-fmt=<fmt>
36                 Format for branch names.
37                 Default is "%b" for the release branch.
38 --tag-fmt=<fmt> Format for tag names.
39                 Default is "%t" for the release tag.
40
41 --reviewer=<id> The reviewer of the commits.
42 --local-user=<keyid>
43                 For the purpose of signing tags and tar files, use this
44                 key (default: use the default e-mail address’ key).
45 --unsigned      Do not sign anything.
46
47 --staging-address=<address>
48                 The staging location to upload release files to (default:
49                 upload@dev.openssl.org)
50 --no-upload     Don't upload the staging release files.
51 --no-update     Don't perform 'make update' and 'make update-fips-checksums'.
52 --quiet         Really quiet, only the final output will still be output.
53 --verbose       Verbose output.
54 --debug         Include debug output.  Implies --no-upload.
55 --porcelain     Give the output in an easy-to-parse format for scripts.
56
57 --force         Force execution
58
59 --help          This text
60 --manual        The manual
61
62 If none of --alpha, --beta, or --final are given, this script tries to
63 figure out the next step.
64 EOF
65     exit 0
66 }
67
68 # Set to one of 'major', 'minor', 'alpha', 'beta' or 'final'
69 next_method=
70 next_method2=
71
72 do_branch=false
73 warn_branch=false
74
75 do_upload=true
76 do_update=true
77
78 clean_worktree=false
79
80 default_branch_fmt='OSSL--%b--%v'
81 default_tag_fmt='%t'
82
83 ECHO=echo
84 DEBUG=:
85 VERBOSE=:
86 git_quiet=-q
87 do_porcelain=false
88
89 force=false
90
91 do_help=false
92 do_manual=false
93
94 do_signed=true
95 tagkey=' -s'
96 gpgkey=
97 reviewers=
98
99 staging_address=upload@dev.openssl.org
100
101 TEMP=$(getopt -l 'alpha,next-beta,beta,final' \
102               -l 'branch' \
103               -l 'clean-worktree' \
104               -l 'branch-fmt:,tag-fmt:' \
105               -l 'reviewer:' \
106               -l 'local-user:,unsigned' \
107               -l 'staging-address:' \
108               -l 'no-upload,no-update' \
109               -l 'quiet,verbose,debug' \
110               -l 'porcelain' \
111               -l 'force' \
112               -l 'help,manual' \
113               -n stage-release.sh -- - "$@")
114 eval set -- "$TEMP"
115 while true; do
116     case $1 in
117     --alpha | --beta | --final )
118         next_method=$(echo "x$1" | sed -e 's|^x--||')
119         if [ -z "$next_method2" ]; then
120             next_method2=$next_method
121         fi
122         shift
123         if [ "$next_method" = 'final' ]; then
124             do_branch=true
125         fi
126         ;;
127     --next-beta )
128         next_method2=$(echo "x$1" | sed -e 's|^x--next-||')
129         shift
130         ;;
131     --branch )
132         do_branch=true
133         warn_branch=true
134         shift
135         ;;
136     --clean-worktree )
137         clean_worktree=true
138         default_branch_fmt='%b'
139         default_tag_fmt='%t'
140         shift
141         ;;
142     --branch-fmt )
143         shift
144         branch_fmt="$1"
145         shift
146         ;;
147     --tag-fmt )
148         shift
149         tag_fmt="$1"
150         shift
151         ;;
152     --reviewer )
153         reviewers="$reviewers $1=$2"
154         shift
155         shift
156         ;;
157     --local-user )
158         shift
159         do_signed=true
160         tagkey=" -u $1"
161         gpgkey=" -u $1"
162         shift
163         ;;
164     --unsigned )
165         shift
166         do_signed=false
167         tagkey=" -a"
168         gpgkey=
169         ;;
170     --staging-address )
171         shift
172         staging_address="$1"
173         shift
174         ;;
175     --no-upload )
176         do_upload=false
177         shift
178         ;;
179     --no-update )
180         do_update=false
181         shift
182         ;;
183     --quiet )
184         ECHO=:
185         VERBOSE=:
186         shift
187         ;;
188     --verbose )
189         ECHO=echo
190         VERBOSE=echo
191         git_quiet=
192         shift
193         ;;
194     --debug )
195         DEBUG=echo
196         do_upload=false
197         shift
198         ;;
199     --porcelain )
200         do_porcelain=true
201         shift
202         ;;
203     --force )
204         force=true
205         shift
206         ;;
207     --help )
208         usage
209         exit 0
210         ;;
211     --manual )
212         sed -e '1,/^### BEGIN MANUAL/d' \
213             -e '/^### END MANUAL/,$d' \
214             < "$0" \
215             | pod2man \
216             | man -l -
217         exit 0
218         ;;
219     -- )
220         shift
221         break
222         ;;
223     * )
224         echo >&2 "Unknown option $1"
225         shift
226         exit 1
227         ;;
228     esac
229 done
230
231 if [ -z "$branch_fmt" ]; then branch_fmt="$default_branch_fmt"; fi
232 if [ -z "$tag_fmt" ]; then tag_fmt="$default_tag_fmt"; fi
233
234 $DEBUG >&2 "DEBUG: \$next_method=$next_method"
235 $DEBUG >&2 "DEBUG: \$next_method2=$next_method2"
236
237 $DEBUG >&2 "DEBUG: \$do_branch=$do_branch"
238
239 $DEBUG >&2 "DEBUG: \$do_upload=$do_upload"
240 $DEBUG >&2 "DEBUG: \$do_update=$do_update"
241 $DEBUG >&2 "DEBUG: \$DEBUG=$DEBUG"
242 $DEBUG >&2 "DEBUG: \$VERBOSE=$VERBOSE"
243 $DEBUG >&2 "DEBUG: \$git_quiet=$git_quiet"
244
245 case "$next_method+$next_method2" in
246     major+major | minor+minor )
247         # These are expected
248         ;;
249     alpha+alpha | alpha+beta | beta+beta | final+final | + | +beta )
250         # These are expected
251         ;;
252     * )
253         echo >&2 "Internal option error ($next_method, $next_method2)"
254         exit 1
255         ;;
256 esac
257
258 # Verbosity feed for certain commands
259 VERBOSITY_FIFO=/tmp/openssl-$$.fifo
260 mkfifo -m 600 $VERBOSITY_FIFO
261 ( cat $VERBOSITY_FIFO | while read L; do $VERBOSE "> $L"; done ) &
262 exec 42>$VERBOSITY_FIFO
263 trap "exec 42>&-; rm $VERBOSITY_FIFO" 0 2
264
265 # Setup ##############################################################
266
267 # Check that we have the scripts that define functions we use
268 RELEASE_AUX=$(dirname $(realpath $(type -p $0)))/release-aux
269 found=true
270 for fn in "$RELEASE_AUX/release-version-fn.sh" \
271           "$RELEASE_AUX/release-state-fn.sh" \
272           "$RELEASE_AUX/string-fn.sh" \
273           "$RELEASE_AUX/upload-fn.sh"; do
274     if ! [ -f "$fn" ]; then
275         echo >&2 "'$fn' is missing"
276         found=false
277     fi
278 done
279 if ! $found; then
280     exit 1
281 fi
282
283 # Load version functions
284 . $RELEASE_AUX/release-version-fn.sh
285 . $RELEASE_AUX/release-state-fn.sh
286 # Load string manipulation functions
287 . $RELEASE_AUX/string-fn.sh
288 # Load upload backend functions
289 . $RELEASE_AUX/upload-fn.sh
290
291 # Make sure we're in the work directory, and remember it
292 if HERE=$(git rev-parse --show-toplevel); then
293     :
294 else
295     echo >&2 "Not in a git worktree"
296     exit 1
297 fi
298
299 # Make sure that it's a plausible OpenSSL work tree, by checking
300 # that a version file is found
301 get_version
302
303 if [ -z "$VERSION_FILE" ]; then
304     echo >&2 "Couldn't find OpenSSL version data"
305     exit 1
306 fi
307
308 orig_HEAD=$(git rev-parse HEAD)
309 orig_branch=$(git rev-parse --abbrev-ref HEAD)
310 orig_remote=$(git for-each-ref --format='%(push:remotename)' \
311                   $(git symbolic-ref -q HEAD))
312 if ! orig_remote_url=$(git remote get-url $orig_remote 2>/dev/null); then
313     # If there is no registered remote, then $orig_remote is the URL
314     orig_remote_url="$orig_remote"
315 fi
316 orig_head=$(git rev-parse --abbrev-ref '@{u}' 2>/dev/null || git rev-parse HEAD)
317
318 # Make sure it's a branch we recognise
319 if (echo "$orig_branch" \
320         | grep -E -q \
321                -e '^master$' \
322                -e '^OpenSSL_[0-9]+_[0-9]+_[0-9]+[a-z]*-stable$' \
323                -e '^openssl-[0-9]+\.[0-9]+$'); then
324     :
325 elif $force; then
326     :
327 else
328     echo >&2 "Not in master or any recognised release branch"
329     echo >&2 "Please 'git checkout' an appropriate branch"
330     exit 1
331 fi
332
333 # Make sure that we have fixup scripts for all the files that need
334 # to be modified for a release.  We trust this, because we're not
335 # going to change versioning scheme in the middle of a release.
336 save_IFS=$IFS
337 IFS=';'
338 found=true
339 for fn in $RELEASE_FILES; do
340     for file in "$RELEASE_AUX/fixup-$fn-release.pl" \
341                 "$RELEASE_AUX/fixup-$fn-postrelease.pl"; do
342         if ! [ -f "$file" ]; then
343             echo >&2 "'$file' is missing"
344             found=false
345         fi
346     done
347 done
348 IFS=$save_IFS
349 if ! $found; then
350     exit 1
351 fi
352
353 # We turn staging_address into a few variables, which can be used
354 # by backends that must understand a subset of the SFTP commands
355 staging_directory=
356 staging_backend=
357 case "$staging_address" in
358     *:* )
359         # Something with a colon is interpreted as the typical SCP
360         # location.  We reinterpret that in our terms
361         staging_directory="${staging_address#*:}"
362         staging_address="${staging_address%%:*}"
363         staging_backend=sftp
364         ;;
365     *@* )
366         staging_backend=sftp
367         ;;
368     sftp://?*/* | sftp://?* )
369         # First, remove the URI scheme
370         staging_address="${staging_address#sftp://}"
371         # Now we know that we have a host, followed by a slash, followed by
372         # a directory spec.  If there is no slash, there's no directory.
373         staging_directory="${staging_address#*/}"
374         if [ "$staging_directory" = "$staging_address" ]; then
375             # There was nothing with a slash to remove, so no directory.
376             staging_directory=
377         fi
378         staging_address="${staging_address%%/*}"
379         staging_backend=sftp
380         ;;
381     sftp:* )
382         echo >&2 "Invalid staging address $staging_address"
383         exit 1
384         ;;
385     * )
386         if $do_upload && ! [ -d "$staging_address" ]; then
387            echo >&2 "Not an existing directory: $staging_address"
388            exit 1
389         fi
390         staging_backend=file
391         ;;
392 esac
393
394 # Initialize #########################################################
395
396 $ECHO "== Initializing work tree"
397
398 release_clone=
399 if $clean_worktree; then
400     if [ -n "$(git status -s)" ]; then
401         echo >&2 "You've specified --clean-worktree, but your worktree is unclean"
402         exit 1
403     fi
404 else
405     # Generate a cloned directory name
406     release_clone="$orig_branch-release-tmp"
407
408     $ECHO "== Work tree will be in $release_clone"
409
410     # Make a clone in a subdirectory and move there
411     if ! [ -d "$release_clone" ]; then
412         $VERBOSE "== Cloning to $release_clone"
413         git clone $git_quiet -b "$orig_branch" -o parent . "$release_clone"
414     fi
415     cd "$release_clone"
416 fi
417
418 get_version
419
420 # Branches to start from.  The release branch is where the changes for the
421 # release are made, and the update branch is where the post-release changes are
422 # made.  If --branch was given and is relevant, they should be different (and
423 # the update branch should be 'master'), otherwise they should be the same.
424 orig_update_branch="$orig_branch"
425 orig_release_branch="$(std_branch_name)"
426
427 # among others, we only create a release branch if the patch number is zero
428 if [ "$orig_update_branch" = "$orig_release_branch" ] \
429        || [ -n "$PATCH" -a "$PATCH" != 0 ]; then
430     if $do_branch && $warn_branch; then
431         echo >&2 "Warning! We're already in a release branch; --branch ignored"
432     fi
433     do_branch=false
434 fi
435
436 if $do_branch; then
437     if [ "$orig_update_branch" != "master" ]; then
438         echo >&2 "--branch is invalid unless the current branch is 'master'"
439         exit 1
440     fi
441     # No need to check if $orig_update_branch and $orig_release_branch differ,
442     # 'cause the code a few lines up guarantee that if they are the same,
443     # $do_branch becomes false
444 else
445     # In this case, the computed release branch may differ from the update branch,
446     # even if it shouldn't...  this is the case when alpha or beta releases are
447     # made in the master branch, which is perfectly ok.  Therefore, simply reset
448     # the release branch to be the same as the update branch and carry on.
449     orig_release_branch="$orig_update_branch"
450 fi
451
452 # Check that the current branch is still on the same branch as our parent repo,
453 # or on a release branch
454 current_branch=$(git rev-parse --abbrev-ref HEAD)
455 if [ "$current_branch" = "$orig_update_branch" ]; then
456     :
457 elif [ "$current_branch" = "$orig_release_branch" ]; then
458     :
459 else
460     # It is an error to end up here.  Let's try to figure out what went wrong
461
462     if $clean_worktree; then
463         # We should never get here.  If we do, something is incorrect in
464         # the code above.
465         echo >&2 "Unexpected current branch: $current_branch"
466     else
467         echo >&2 "The cloned sub-directory '$release_clone' is on a branch"
468         if [ "$orig_update_branch" = "$orig_release_branch" ]; then
469             echo >&2 "other than '$orig_update_branch'."
470         else
471             echo >&2 "other than '$orig_update_branch' or '$orig_release_branch'."
472         fi
473         echo >&2 "Please 'cd \"$(pwd)\"; git checkout $orig_update_branch'"
474     fi
475     exit 1
476 fi
477
478 SOURCEDIR=$(pwd)
479 $DEBUG >&2 "DEBUG: Source directory is $SOURCEDIR"
480
481 # Release ############################################################
482
483 # We always expect to start from a state of development
484 if [ "$TYPE" != 'dev' ]; then
485     if $clean_worktree; then
486         cat >&2 <<EOF
487 Not in a development branch.
488
489 Have a look at the git log, it may be that a previous crash left it in
490 an intermediate state and that need to drop the top commit:
491
492 git reset --hard $orig_head
493 # WARNING! LOOK BEFORE YOU ACT, KNOW WHAT YOU DO
494 EOF
495     else
496         cat >&2 <<EOF
497 Not in a development branch.
498
499 Have a look at the git log in $release_clone, it may be that
500 a previous crash left it in an intermediate state and that need to drop
501 the top commit:
502
503 (cd $release_clone; git reset --hard $upstream)
504 # WARNING! LOOK BEFORE YOU ACT, KNOW WHAT YOU DO
505 EOF
506     fi
507     exit 1
508 fi
509
510 # Make the update branch name according to our current data
511 update_branch=$(format_string "$branch_fmt" \
512                               "b=$orig_update_branch" \
513                               "t=" \
514                               "v=$FULL_VERSION")
515     
516 # Update the version information.  This won't save anything anywhere, yet,
517 # but does check for possible next_method errors before we do bigger work.
518 next_release_state "$next_method"
519
520 # Make the release tag and branch name according to our current data
521 tag=$(format_string "$tag_fmt" \
522                     "b=$orig_release_branch" \
523                     "t=$(std_tag_name)" \
524                     "v=$FULL_VERSION")
525 release_branch=$(format_string "$branch_fmt" \
526                                "b=$orig_release_branch" \
527                                "t=$(std_tag_name)" \
528                                "v=$FULL_VERSION")
529     
530 # Create a update branch, unless it's the same as our current branch
531 if [ "$update_branch" != "$orig_update_branch" ]; then
532     $VERBOSE "== Creating a local update branch and switch to it: $update_branch"
533     git checkout $git_quiet -b "$update_branch"
534 fi
535
536 $ECHO "== Configuring OpenSSL for update and release.  This may take a bit of time"
537
538 ./Configure cc >&42
539
540 $VERBOSE "== Checking source file updates and fips checksums"
541
542 make update >&42
543 # As long as we're doing an alpha release, we can have symbols without specific
544 # numbers assigned. In a beta or final release, all symbols MUST have an
545 # assigned number.
546 if [ "$next_method" != 'alpha' ] && grep -q '^renumber *:' Makefile; then
547     make renumber >&42
548 fi
549 if grep -q '^update-fips-checksums *:' Makefile; then
550     make update-fips-checksums >&42
551 fi
552
553 if [ -n "$(git status --porcelain --untracked-files=no --ignore-submodules=all)" ]; then
554     $VERBOSE "== Committing updates"
555     git add -u
556     git commit $git_quiet -m $'make update\n\nRelease: yes'
557     if [ -n "$reviewers" ]; then
558         addrev --release --nopr $reviewers
559     fi
560 fi
561
562 # Create a update branch, unless it's the same as the update branch
563 if [ "$release_branch" != "$update_branch" ]; then
564     $VERBOSE "== Creating a local release branch and switch to it: $release_branch"
565     git checkout $git_quiet -b "$release_branch"
566 fi
567
568 # Write the version information we updated
569 set_version
570
571 release="$FULL_VERSION"
572 if [ -n "$PRE_LABEL" ]; then
573     release_text="$SERIES$_BUILD_METADATA $PRE_LABEL $PRE_NUM"
574     announce_template=openssl-announce-pre-release.tmpl
575 else
576     release_text="$release"
577     announce_template=openssl-announce-release.tmpl
578 fi
579 $VERBOSE "== Updated version information to $release"
580
581 $VERBOSE "== Updating files with release date for $release : $RELEASE_DATE"
582 (
583     IFS=';'
584     for file in $RELEASE_FILES; do
585         fixup="$RELEASE_AUX/fixup-$(basename "$file")-release.pl"
586         $VERBOSE "> $file"
587         RELEASE="$release" RELEASE_TEXT="$release_text" RELEASE_DATE="$RELEASE_DATE" \
588                perl -pi $fixup $file
589     done
590 )
591
592 $VERBOSE "== Committing updates and tagging"
593 git add -u
594 git commit $git_quiet -m "Prepare for release of $release_text"$'\n\nRelease: yes'
595 if [ -n "$reviewers" ]; then
596     addrev --release --nopr $reviewers
597 fi
598 $ECHO "Tagging release with tag $tag.  You may need to enter a pass phrase"
599 git tag$tagkey "$tag" -m "OpenSSL $release release tag"
600
601 tarfile=openssl-$release.tar
602 tgzfile=$tarfile.gz
603 metadata=openssl-$release.dat
604 announce=openssl-$release.txt
605
606 $ECHO "== Generating tar, hash, announcement and metadata files."
607 $ECHO "== This make take a bit of time..."
608
609 $VERBOSE "== Making tarfile: $tgzfile"
610
611 # Unfortunately, some tarball generators do verbose output on STDERR...  for
612 # good reason, but it means we don't display errors unless --verbose
613 (
614     if [ -f ./util/mktar.sh ]; then
615         ./util/mktar.sh --tarfile="../$tarfile" 2>&1
616     else
617         make DISTTARVARS=TARFILE="../$tarfile" dist 2>&1
618     fi
619 ) | while read L; do $VERBOSE "> $L"; done
620
621 if ! [ -f "../$tgzfile" ]; then
622     echo >&2 "Where did the tarball end up? (../$tgzfile)"
623     exit 1
624 fi
625
626 $VERBOSE "== Generating checksums: $tgzfile.sha1 $tgzfile.sha256"
627 openssl sha1 < "../$tgzfile" | \
628     (IFS='='; while read X H; do echo $H; done) > "../$tgzfile.sha1"
629 openssl sha256 < "../$tgzfile" | \
630     (IFS='='; while read X H; do echo $H; done) > "../$tgzfile.sha256"
631 length=$(wc -c < "../$tgzfile")
632 sha1hash=$(cat "../$tgzfile.sha1")
633 sha256hash=$(cat "../$tgzfile.sha256")
634
635 $VERBOSE "== Generating announcement text: $announce"
636 # Hack the announcement template
637 cat "$RELEASE_AUX/$announce_template" \
638     | sed -e "s|\\\$release_text|$release_text|g" \
639           -e "s|\\\$release|$release|g" \
640           -e "s|\\\$series|$SERIES|g" \
641           -e "s|\\\$label|$PRE_LABEL|g" \
642           -e "s|\\\$tarfile|$tgzfile|" \
643           -e "s|\\\$length|$length|" \
644           -e "s|\\\$sha1hash|$sha1hash|" \
645           -e "s|\\\$sha256hash|$sha256hash|" \
646     | perl -p "$RELEASE_AUX/fix-title.pl" \
647     > "../$announce"
648
649 $VERBOSE "== Generating signatures: $tgzfile.asc $announce.asc"
650 rm -f "../$tgzfile.asc" "../$announce.asc"
651 $ECHO "Signing the release files.  You may need to enter a pass phrase"
652 if $do_signed; then
653     gpg$gpgkey --use-agent -sba "../$tgzfile"
654     gpg$gpgkey --use-agent -sta --clearsign "../$announce"
655 fi
656
657 if ! $clean_worktree; then
658     # Push everything to the parent repo
659     $VERBOSE "== Push what we have to the parent repository"
660     git push --follow-tags parent HEAD
661 fi
662
663 if $do_signed; then
664     staging_files=( "$tgzfile" "$tgzfile.sha1" "$tgzfile.sha256"
665                     "$tgzfile.asc" "$announce.asc" )
666 else
667     staging_files=( "$tgzfile" "$tgzfile.sha1" "$tgzfile.sha256" "$announce" )
668 fi
669
670 $VERBOSE "== Generating metadata file: $metadata"
671
672 (
673     if [ "$update_branch" != "$orig_update_branch" ]; then
674         echo "staging_update_branch='$orig_update_branch'"
675     fi
676     echo "update_branch='$orig_update_branch'"
677     if [ "$release_branch" != "$update_branch" ]; then
678         if [ "$release_branch" != "$orig_release_branch" ]; then
679             echo "staging_release_branch='$release_branch'"
680         fi
681         echo "release_branch='$orig_release_branch'"
682     fi
683     echo "release_tag='$tag'"
684     echo "upload_files='${staging_files[@]}'"
685     echo "source_repo='$orig_remote_url'"
686 ) > ../$metadata
687
688 if $do_upload; then
689     $ECHO "== Upload tar, hash, announcement and metadata files to staging location"
690 fi
691
692 (
693     # With sftp, the progress meter is enabled by default,
694     # so we turn it off unless --verbose was given
695     if [ "$VERBOSE" == ':' ]; then
696         echo "progress"
697     fi
698     if [ -n "$staging_directory" ]; then
699         echo "cd $staging_directory"
700     fi
701     for uf in "${staging_files[@]}" "$metadata"; do
702         echo "put ../$uf"
703     done
704 ) | upload_backend_$staging_backend "$staging_address" $do_upload
705
706 # Post-release #######################################################
707
708 # Reset the files to their pre-release contents.  This doesn't affect
709 # HEAD, but simply set all the files in a state that 'git revert -n HEAD'
710 # would have given, but without the artifacts that 'git revert' adds.
711 #
712 # This allows all the post-release fixup scripts to perform from the
713 # same point as the release fixup scripts, hopefully making them easier
714 # to write.  This also makes the same post-release fixup scripts easier
715 # to run when --branch has been used, as they will be run both on the
716 # release branch and on the update branch, essentially from the same
717 # state for affected files.
718 $VERBOSE "== Reset all files to their pre-release contents"
719 git reset $git_quiet HEAD^ -- .
720 git checkout -- .
721
722 prev_release_text="$release_text"
723 prev_release_date="$RELEASE_DATE"
724
725 next_release_state "$next_method2"
726 set_version
727
728 release="$FULL_VERSION"
729 release_text="$VERSION$_BUILD_METADATA"
730 if [ -n "$PRE_LABEL" ]; then
731     release_text="$SERIES$_BUILD_METADATA $PRE_LABEL $PRE_NUM"
732 fi
733 $VERBOSE "== Updated version information to $release"
734
735 $VERBOSE "== Updating files for $release :"
736 (
737     IFS=';'
738     for file in $RELEASE_FILES; do
739         fixup="$RELEASE_AUX/fixup-$(basename "$file")-postrelease.pl"
740         $VERBOSE "> $file"
741         RELEASE="$release" RELEASE_TEXT="$release_text" \
742                PREV_RELEASE_TEXT="$prev_release_text" \
743                PREV_RELEASE_DATE="$prev_release_date" \
744                perl -pi $fixup $file
745     done
746 )
747
748 $VERBOSE "== Committing updates"
749 git add -u
750 git commit $git_quiet -m "Prepare for $release_text"$'\n\nRelease: yes'
751 if [ -n "$reviewers" ]; then
752     addrev --release --nopr $reviewers
753 fi
754
755 if ! $clean_worktree; then
756     # Push everything to the parent repo
757     $VERBOSE "== Push what we have to the parent repository"
758     git push parent HEAD
759 fi
760
761 if [ "$release_branch" != "$update_branch" ]; then
762     $VERBOSE "== Going back to the update branch $update_branch"
763     git checkout $git_quiet "$update_branch"
764
765     get_version
766     next_release_state "minor"
767     set_version
768
769     release="$FULL_VERSION"
770     release_text="$SERIES$_BUILD_METADATA"
771     $VERBOSE "== Updated version information to $release"
772
773     $VERBOSE "== Updating files for $release :"
774     (
775         IFS=';'
776         for file in $RELEASE_FILES; do
777             fixup="$RELEASE_AUX/fixup-$(basename "$file")-postrelease.pl"
778             $VERBOSE "> $file"
779             RELEASE="$release" RELEASE_TEXT="$release_text" \
780                    perl -pi $fixup $file
781         done
782     )
783
784     $VERBOSE "== Committing updates"
785     git add -u
786     git commit $git_quiet -m "Prepare for $release_text"$'\n\nRelease: yes'
787     if [ -n "$reviewers" ]; then
788         addrev --release --nopr $reviewers
789     fi
790 fi
791
792 if ! $clean_worktree; then
793     # Push everything to the parent repo
794     $VERBOSE "== Push what we have to the parent repository"
795     git push parent HEAD
796 fi
797
798 # Done ###############################################################
799
800 $VERBOSE "== Done"
801
802 cd $HERE
803 if $do_porcelain; then
804     if [ -n "$release_clone" ]; then
805         echo "clone_directory='$release_clone'"
806     fi
807     echo "orig_head='$orig_head'"
808     echo "metadata='$metadata'"
809 else
810     cat <<EOF
811
812 ======================================================================
813 The release is done, and involves a few files and commits for you to
814 deal with.  Everything you need has been pushed to your repository,
815 please see instructions that follow.
816 ======================================================================
817
818 EOF
819
820     if $do_upload; then
821         cat <<EOF
822 The following files were uploaded to $staging_address, please ensure they
823 are dealt with appropriately:
824
825 EOF
826     else
827         cat <<EOF
828 The following files were generated for upload, please deal with them
829 appropriately:
830
831 EOF
832     fi
833     for uf in "${staging_files[@]}"; do
834         echo "    $uf"
835     done
836     cat <<EOF
837
838 ----------------------------------------------------------------------
839
840 EOF
841
842     if [ "$release_branch" != "$update_branch" ]; then
843         cat <<EOF
844 You need to prepare the main repository with a new branch, '$release_branch'.
845 That is done directly in the server's bare repository like this:
846
847     git branch $release_branch $orig_HEAD
848
849 EOF
850     fi
851     if [ "$update_branch" != "$orig_update_branch" ] \
852        && [ "$release_branch" != "$update_branch" ]; then
853         # "Normal" scenario with --branch
854         cat <<EOF
855 A release tag and two branches have been added to your local repository.
856 Push them to github, make PRs from them and have them approved.
857
858     Update branch: $update_branch
859     Release branch: $release_branch
860     Tag: $tag
861
862 When merging everything into the main repository, do it like this:
863
864     git push git@github.openssl.org:openssl/openssl.git \\
865         $release_branch:$orig_release_branch
866     git push git@github.openssl.org:openssl/openssl.git \\
867         $update_branch:$orig_update_branch
868     git push git@github.openssl.org:openssl/openssl.git \\
869         $tag
870 EOF
871     elif [ "$update_branch" != "$orig_update_branch" ]; then
872         # "Normal" scenario without --branch
873         cat <<EOF
874 A release tag and a release/update branch have been added to your local
875 repository.  Push them to github, make PRs from them and have them
876 approved.
877
878     Release/update branch: $update_branch
879     Tag: $tag
880
881 When merging everything into the main repository, do it like this:
882
883     git push git@github.openssl.org:openssl/openssl.git \\
884         $update_branch:$orig_update_branch
885     git push git@github.openssl.org:openssl/openssl.git \\
886         $tag
887 EOF
888     elif [ "$release_branch" != "$update_branch" ]; then
889         # --clean-worktree and --branch scenario
890         cat <<EOF
891 A release tag and a release branch has been added to your repository,
892 and the current branch has been updated.  Push them to github, make
893 PRs from them and have them approved:
894
895     Updated branch: $update_branch
896     Release branch: $release_branch
897     Tag: $tag
898
899 When merging everything into the main repository, do it like this:
900
901     git push git@github.openssl.org:openssl/openssl.git \\
902         $release_branch:$orig_release_branch
903     git push git@github.openssl.org:openssl/openssl.git \\
904         $update_branch
905     git push git@github.openssl.org:openssl/openssl.git \\
906         $tag
907 EOF
908     else
909         # --clean-worktree without --branch scenario
910         cat <<EOF
911 A release tag has been added to your local repository, and the current
912 branch has been updated.  Push them to github, make PRs from them and
913 have them approved.
914
915     Release/update branch: $update_branch
916     Tag: $tag
917
918 When merging everything into the main repository, do it like this:
919
920     git push git@github.openssl.org:openssl/openssl.git \\
921         $update_branch
922     git push git@github.openssl.org:openssl/openssl.git \\
923         $tag
924 EOF
925     fi
926
927     cat <<EOF
928
929 ----------------------------------------------------------------------
930 EOF
931
932     cat <<EOF
933
934 When everything is done, or if something went wrong and you want to start
935 over, simply clean away temporary things left behind:
936 EOF
937     if [ -n "$release_clone" ]; then
938         cat <<EOF
939 The release worktree:
940
941     rm -rf $release_clone
942 EOF
943     fi
944     cat <<EOF
945
946 Additional branches:
947
948 EOF
949     if [ "$release_branch" != "$update_branch" ]; then
950         cat <<EOF
951     git branch -D $release_branch
952 EOF
953     fi
954     if [ "$update_branch" != "$orig_update_branch" ]; then
955         cat <<EOF
956     git branch -D $update_branch
957 EOF
958     fi
959 fi
960
961 exit 0
962
963 # cat is inconsequential, it's only there to fend off zealous shell parsers
964 # that parse all the way here.
965 cat <<EOF
966 ### BEGIN MANUAL
967 =pod
968
969 =head1 NAME
970
971 stage-release.sh - OpenSSL release staging script
972
973 =head1 SYNOPSIS
974
975 B<stage-release.sh>
976 [
977 B<--alpha> |
978 B<--next-beta> |
979 B<--beta> |
980 B<--final> |
981 B<--branch> |
982 B<--clean-worktree> |
983 B<--branch-fmt>=I<fmt> |
984 B<--tag-fmt>=I<fmt> |
985 B<--local-user>=I<keyid> |
986 B<--unsigned> |
987 B<--reviewer>=I<id> |
988 B<--staging-address>=I<address> |
989 B<--no-upload> |
990 B<--no-update> |
991 B<--quiet> |
992 B<--verbose> |
993 B<--debug> |
994 B<--porcelain> |
995 B<--help> |
996 B<--manual>
997 ]
998
999 =head1 DESCRIPTION
1000
1001 B<stage-release.sh> creates an OpenSSL release, given current worktree
1002 conditions.  It will refuse to work unless the current branch is C<master>
1003 or a release branch (see L</RELEASE BRANCHES AND TAGS> below for a
1004 discussion on those).
1005
1006 B<stage-release.sh> tries to be smart and figure out the next release if no
1007 hints are given through options, and will exit with an error in ambiguous
1008 cases.
1009
1010 B<stage-release.sh> normally finishes off with instructions on what to do
1011 next.  When B<--porcelain> is given, it finishes off with script friendly
1012 data instead, see the description of that option.  When finishing commands
1013 are given, they must be followed exactly.
1014
1015 B<stage-release.sh> normally leaves behind a clone of the local repository,
1016 as a subdirectory in the current worktree, as well as an extra branch with
1017 the results of running this script in the local repository.  This extra
1018 branch is useful to create a pull request from, which will also be mentioned
1019 at the end of the run of B<stage-release.sh>.  This local clone subdirectory
1020 as well as this extra branch can safely be removed after all instructions
1021 have been successfully followed.
1022
1023 When the option B<--clean-worktree> is given, B<stage-release.sh> has a
1024 different behaviour.  In this case, it doesn't create that clone or any
1025 extra branch, and it will update the current branch of the worktree
1026 directly.  This is useful when it's desirable to push the changes directly
1027 to a remote repository without having to go through a pull request and
1028 approval process.
1029
1030 =head1 OPTIONS
1031
1032 =over 4
1033
1034 =item B<--alpha>, B<--beta>
1035
1036 Set the state of this branch to indicate that alpha or beta releases are
1037 to be done.
1038
1039 B<--alpha> is only acceptable if the I<PATCH> version number is zero and
1040 the current state is "in development" or that alpha releases are ongoing.
1041
1042 B<--beta> is only acceptable if the I<PATCH> version number is zero and
1043 that alpha or beta releases are ongoing.
1044
1045 =item B<--next-beta>
1046
1047 Use together with B<--alpha> to switch to beta releases after the current
1048 release is done.
1049
1050 =item B<--final>
1051
1052 Set the state of this branch to indicate that regular releases are to be
1053 done.  This is only valid if alpha or beta releases are currently ongoing.
1054
1055 This implies B<--branch>.
1056
1057 =item B<--branch>
1058
1059 Create a branch specific for the I<SERIES> release series, if it doesn't
1060 already exist, and switch to it when making the release files.  The exact
1061 branch name will be C<< openssl-I<SERIES> >>.
1062
1063 =item B<--clean-worktree>
1064
1065 This indicates that the current worktree is clean and can be acted on
1066 directly, instead of creating a clone of the local repository or creating
1067 any extra branch.
1068
1069 =item B<--branch-fmt>=I<fmt>
1070
1071 =item B<--tag-fmt>=I<fmt>
1072
1073 Format for branch and tag names.  This can be used to tune the names of
1074 branches and tags that are updated or added by this script.
1075
1076 I<fmt> can include printf-like formating directives:
1077
1078 =over 4
1079
1080 =item %b
1081
1082 is replaced with a branch name.  This branch name is usually the current
1083 branch of the current repository, but may also be the default release
1084 branch name that is generated when B<--branch> is given.
1085
1086 =item %t
1087
1088 is replaced with the generated release tag name.
1089
1090 =item %v
1091
1092 is replaced with the version number.  The exact version number varies
1093 through the process of this script.
1094
1095 =back
1096
1097 This script uses the following defaults:
1098
1099 =over 4
1100
1101 =item * Without B<--clean-worktree>
1102
1103 For branches: C<OSSL--%b--%v>
1104
1105 For tags: C<%t>
1106
1107 =item * With B<--clean-worktree>
1108
1109 For branches: C<%b>
1110
1111 For tags: C<%t>
1112
1113 =back
1114
1115 =item B<--reviewer>=I<id>
1116
1117 Add I<id> to the set of reviewers for the commits performed by this script.
1118 Multiple reviewers are allowed.
1119
1120 If no reviewer is given, you will have to run C<addrev> manually, which
1121 means retagging a release commit manually as well.
1122
1123 =item B<--local-user>=I<keyid>
1124
1125 Use I<keyid> as the local user for C<git tag> and for signing with C<gpg>.
1126
1127 If not given, then the default e-mail address' key is used.
1128
1129 =item B<--unsigned>
1130
1131 Do not sign the tarball or announcement file.  This leaves it for other
1132 scripts to sign the files later.
1133
1134 =item B<--staging-address>=I<address>
1135
1136 The staging location that the release files are to be uploaded to.
1137 Supported values are:
1138
1139 =over 4
1140
1141 =item -
1142
1143 an existing local directory
1144
1145 =item -
1146
1147 something that can be interpreted as an SCP/SFTP address.  In this case,
1148 SFTP will always be used.  Typical SCP remote file specs will be translated
1149 into something that makes sense for SFTP.
1150
1151 =back
1152
1153 The default staging address is C<upload@dev.openssl.org>.
1154
1155 =item B<--no-upload>
1156
1157 Don't upload the release files to the staging location.
1158
1159 =item B<--no-update>
1160
1161 Don't run C<make update> and C<make update-fips-checksums>.
1162
1163 =item B<--quiet>
1164
1165 Really quiet, only bare necessity output, which is the final instructions,
1166 or should the B<--porcelain> option be used, only that output.
1167
1168 messages appearing on standard error will still be shown, but should be
1169 fairly minimal.
1170
1171 =item B<--verbose>
1172
1173 Verbose output.
1174
1175 =item B<--debug>
1176
1177 Display extra debug output.  Implies B<--no-upload>
1178
1179 =item B<--porcelain>
1180
1181 Give final output in an easy-to-parse format for scripts.  The output comes
1182 in a form reminicent of shell variable assignments.  Currently supported are:
1183
1184 =over 4
1185
1186 =item B<clone_directory>=I<dir>
1187
1188 The directory for the clone that this script creates.  This is not given when
1189 the option B<--clean-worktree> is used.
1190
1191 =item B<metadata>=I<file>
1192
1193 The metadata file.  See L</FILES> for a description of all generated files
1194 as well as the contents of the metadata file.
1195
1196 =back
1197
1198 =item B<--force>
1199
1200 Force execution.  Precisely, the check that the current branch is C<master>
1201 or a release branch is not done.
1202
1203 =item B<--help>
1204
1205 Display a quick help text and exit.
1206
1207 =item B<--manual>
1208
1209 Display this manual and exit.
1210
1211 =back
1212
1213 =head1 RELEASE BRANCHES AND TAGS
1214
1215 Prior to OpenSSL 3.0, the release branches were named
1216 C<< OpenSSL_I<SERIES>-stable >>, and the release tags were named
1217 C<< OpenSSL_I<VERSION> >> for regular releases, or
1218 C<< OpenSSL_I<VERSION>-preI<n> >> for pre-releases.
1219
1220 From OpenSSL 3.0 ongoing, the release branches are named
1221 C<< openssl-I<SERIES> >>, and the release tags are named
1222 C<< openssl-I<VERSION> >> for regular releases, or
1223 C<< openssl-I<VERSION>-alphaI<n> >> for alpha releases
1224 and C<< openssl-I<VERSION>-betaI<n> >> for beta releases.
1225
1226 B<stage-release.sh> recognises both forms.
1227
1228 =head1 VERSION AND STATE
1229
1230 With OpenSSL 3.0, all the version and state information is in the file
1231 F<VERSION.dat>, where the following variables are used and changed:
1232
1233 =over 4
1234
1235 =item B<MAJOR>, B<MINOR>, B<PATCH>
1236
1237 The three part of the version number.
1238
1239 =item B<PRE_RELEASE_TAG>
1240
1241 The indicator of the current state of the branch.  The value may be one pf:
1242
1243 =over 4
1244
1245 =item C<dev>
1246
1247 This branch is "in development".  This is typical for the C<master> branch
1248 unless there are ongoing alpha or beta releases.
1249
1250 =item C<< alphaI<n> >> or C<< alphaI<n>-dev >>
1251
1252 This branch has alpha releases going on.  C<< alphaI<n>-dev >> is what
1253 should normally be seen in the git workspace, indicating that
1254 C<< alphaI<n> >> is in development.  C<< alphaI<n> >> is what should be
1255 found in the alpha release tar file.
1256
1257 =item C<< alphaI<n> >> or C<< alphaI<n>-dev >>
1258
1259 This branch has beta releases going on.  The details are otherwise exactly
1260 as for alpha.
1261
1262 =item I<no value>
1263
1264 This is normally not seen in the git workspace, but should always be what's
1265 found in the tar file of a regular release.
1266
1267 =back
1268
1269 =item B<BUILD_METADATA>
1270
1271 Extra build metadata to be used by anyone for their own purposes.
1272
1273 =item B<RELEASE_DATE>
1274
1275 This is normally empty in the git workspace, but should always have the
1276 release date in the tar file of any release.
1277
1278 =back
1279
1280 =head1 FILES
1281
1282 The following files are produced and normally uploaded to the staging
1283 address:
1284
1285 =over 4
1286
1287 =item F<openssl-{VERSION}.tar.gz>
1288
1289 The source tarball itself.
1290
1291 =item F<openssl-{VERSION}.tar.gz.sha1>, F<openssl-{VERSION}.tar.gz.sha256>
1292
1293 The SHA1 and SHA256 checksums for F<openssl-{VERSION}.tar.gz>.
1294
1295 =item F<openssl-{VERSION}.tar.gz.asc>
1296
1297 The detached PGP signature for F<openssl-{VERSION}.tar.gz>.
1298
1299 =item F<openssl-{VERSION}.txt.asc>
1300
1301 The announcement text, clear signed with PGP.
1302
1303 =item F<openssl-{VERSION}.dat>
1304
1305 The metadata file for F<openssl-{VERSION}.tar.gz>.  It contains shell
1306 variable assignments with data that may be of interest for other scripts,
1307 such as a script to promote this release to an actual release:
1308
1309 =over 4
1310
1311 =item B<update_branch>=I<branch>
1312
1313 The update branch.  This is always given.
1314
1315 =item B<staging_update_branch>=I<branch>
1316
1317 If a staging update branch was used (because B<--clean-worktree> wasn't
1318 given or because B<--branch-fmt> was used), it's given here.
1319
1320 =item B<release_branch>=I<branch>
1321
1322 The release branch, if it differs from the update branch (i.e. B<--branch>
1323 was given or implied).
1324
1325 =item B<staging_release_branch>=I<branch>
1326
1327 If a staging release branch was used (because B<--clean-worktree> wasn't
1328 given or because B<--branch-fmt> was used), it's given here.
1329
1330 =item B<release_tag>=I<tag>
1331
1332 The release tag.  This is always given.
1333
1334 =item B<upload_files>='I<files>'
1335
1336 The space separated list of files that were or would have been uploaded
1337 to the staging location (depending on the presence of B<--no-upload>).  This
1338 list doesn't include the metadata file itself.
1339
1340 =item B<source_repo>='I<URL>'
1341
1342 The URL of the source repository that this release was generated from.
1343
1344 =back
1345
1346 =back
1347
1348 =head1 COPYRIGHT
1349
1350 Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved.
1351
1352 Licensed under the Apache License 2.0 (the "License").  You may not use
1353 this file except in compliance with the License.  You can obtain a copy
1354 in the file LICENSE in the source distribution or at
1355 L<https://www.openssl.org/source/license.html>.
1356
1357 =cut
1358 ### END MANUAL
1359 EOF