2 # Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
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
9 # This is the most shell agnostic way to specify that POSIX rules.
12 # Force C locale because some commands (like date +%b) relies
13 # on the current locale.
18 Usage: release.sh [ options ... ]
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.
27 --branch Create a release branch 'openssl-{major}.{minor}',
28 where '{major}' and '{minor}' are the major and minor
31 --reviewer=<id> The reviewer of the commits.
33 For the purpose of signing tags and tar files, use this
34 key (default: use the default e-mail address’ key).
36 --no-upload Don't upload to upload@dev.openssl.org.
37 --no-update Don't perform 'make update' and 'make update-fips-checksums'.
38 --verbose Verbose output.
39 --debug Include debug output. Implies --no-upload.
41 --force Force execution
46 If none of --alpha, --beta, or --final are given, this script tries to
47 figure out the next step.
52 # Set to one of 'major', 'minor', 'alpha', 'beta' or 'final'
75 upload_address=upload@dev.openssl.org
77 TEMP=$(getopt -l 'alpha,next-beta,beta,final' \
79 -l 'no-upload,no-update' \
85 -n release.sh -- - "$@")
89 --alpha | --beta | --final )
90 next_method=$(echo "x$1" | sed -e 's|^x--||')
91 if [ -z "$next_method2" ]; then
92 next_method2=$next_method
95 if [ "$next_method" = 'final' ]; then
100 next_method2=$(echo "x$1" | sed -e 's|^x--next-||')
133 reviewers="$reviewers $1=$2"
146 sed -e '1,/^### BEGIN MANUAL/d' \
147 -e '/^### END MANUAL/,$d' \
158 echo >&2 "Unknown option $1"
165 $DEBUG >&2 "DEBUG: \$next_method=$next_method"
166 $DEBUG >&2 "DEBUG: \$next_method2=$next_method2"
168 $DEBUG >&2 "DEBUG: \$do_branch=$do_branch"
170 $DEBUG >&2 "DEBUG: \$do_upload=$do_upload"
171 $DEBUG >&2 "DEBUG: \$do_update=$do_update"
172 $DEBUG >&2 "DEBUG: \$DEBUG=$DEBUG"
173 $DEBUG >&2 "DEBUG: \$VERBOSE=$VERBOSE"
174 $DEBUG >&2 "DEBUG: \$git_quiet=$git_quiet"
176 case "$next_method+$next_method2" in
177 major+major | minor+minor )
180 alpha+alpha | alpha+beta | beta+beta | final+final | + | +beta )
184 echo >&2 "Internal option error ($next_method, $next_method2)"
189 # Verbosity feed for certain commands
190 VERBOSITY_FIFO=/tmp/openssl-$$.fifo
191 mkfifo -m 600 $VERBOSITY_FIFO
192 ( cat $VERBOSITY_FIFO | while read L; do $VERBOSE "> $L"; done ) &
193 exec 42>$VERBOSITY_FIFO
194 trap "exec 42>&-; rm $VERBOSITY_FIFO" 0 2
196 # Setup ##############################################################
198 # Check that we have the scripts that define functions we use
199 RELEASE_AUX=$(cd $(dirname $0)/release-aux; pwd)
201 for fn in "$RELEASE_AUX/release-version-fn.sh" \
202 "$RELEASE_AUX/release-state-fn.sh"; do
203 if ! [ -f "$fn" ]; then
204 echo >&2 "'$fn' is missing"
212 # Load version functions
213 . $RELEASE_AUX/release-version-fn.sh
214 . $RELEASE_AUX/release-state-fn.sh
216 # Make sure we're in the work directory, and remember it
217 if HERE=$(git rev-parse --show-toplevel); then
220 echo >&2 "Not in a git worktree"
224 # Make sure that it's a plausible OpenSSL work tree, by checking
225 # that a version file is found
228 if [ -z "$VERSION_FILE" ]; then
229 echo >&2 "Couldn't find OpenSSL version data"
233 # Make sure it's a branch we recognise
234 orig_branch=$(git rev-parse --abbrev-ref HEAD)
235 if (echo "$orig_branch" \
238 -e '^OpenSSL_[0-9]+_[0-9]+_[0-9]+[a-z]*-stable$' \
239 -e '^openssl-[0-9]+\.[0-9]+$'); then
244 echo >&2 "Not in master or any recognised release branch"
245 echo >&2 "Please 'git checkout' an appropriate branch"
248 orig_HEAD=$(git rev-parse HEAD)
250 # Initialize #########################################################
252 echo "== Initializing work tree"
254 # Generate a cloned directory name
255 release_clone="$orig_branch-release-tmp"
257 echo "== Work tree will be in $release_clone"
259 # Make a clone in a subdirectory and move there
260 if ! [ -d "$release_clone" ]; then
261 $VERBOSE "== Cloning to $release_clone"
262 git clone $git_quiet -b "$orig_branch" -o parent . "$release_clone"
268 # Branches we will work with. The release branch is where we make the
269 # changes for the release, the update branch is where we make the post-
271 update_branch="$orig_branch"
272 release_branch="$(std_branch_name)"
274 # among others, we only create a release branch if the patch number is zero
275 if [ "$update_branch" = "$release_branch" ] || [ $PATCH -ne 0 ]; then
276 if $do_branch && $warn_branch; then
277 echo >&2 "Warning! We're already in a release branch; --branch ignored"
282 if ! $do_branch; then
283 release_branch="$update_branch"
286 # Branches we create for PRs
287 branch_version="$VERSION${PRE_LABEL:+-$PRE_LABEL$PRE_NUM}"
288 tmp_update_branch="OSSL--$update_branch--$branch_version"
289 tmp_release_branch="OSSL--$release_branch--$branch_version"
291 # Check that we're still on the same branch as our parent repo, or on a
293 current_branch=$(git rev-parse --abbrev-ref HEAD)
294 if [ "$current_branch" = "$update_branch" ]; then
296 elif [ "$current_branch" = "$release_branch" ]; then
299 echo >&2 "The cloned sub-directory '$release_clone' is on a branch"
300 if [ "$update_branch" = "$release_branch" ]; then
301 echo >&2 "other than '$update_branch'."
303 echo >&2 "other than '$update_branch' or '$release_branch'."
305 echo >&2 "Please 'cd \"$(pwd)\"; git checkout $update_branch'"
310 $DEBUG >&2 "DEBUG: Source directory is $SOURCEDIR"
312 # Release ############################################################
314 # We always expect to start from a state of development
315 if [ "$TYPE" != 'dev' ]; then
316 echo >&2 "Not in a development branch"
317 echo >&2 "Have a look at the git log in $release_clone, it may be that"
318 echo >&2 "a previous crash left it in an intermediate state and that"
319 echo >&2 "need to drop the top commit:"
321 echo >&2 "(cd $release_clone; git reset --hard HEAD^)"
322 echo >&2 "# WARNING! LOOK BEFORE YOU ACT"
326 # Update the version information. This won't save anything anywhere, yet,
327 # but does check for possible next_method errors before we do bigger work.
328 next_release_state "$next_method"
330 # Create our temporary release branch
331 $VERBOSE "== Creating a local release branch: $tmp_release_branch"
332 git checkout $git_quiet -b "$tmp_release_branch"
334 echo "== Configuring OpenSSL for update and release. This may take a bit of time"
338 $VERBOSE "== Checking source file updates and fips checksums"
341 # As long as we're doing an alpha release, we can have symbols without specific
342 # numbers assigned. In a beta or final release, all symbols MUST have an
344 if [ "$next_method" != 'alpha' ]; then
347 make update-fips-checksums >&42
349 if [ -n "$(git status --porcelain)" ]; then
350 $VERBOSE "== Committing updates"
352 git commit $git_quiet -m $'make update\n\nRelease: yes'
353 if [ -n "$reviewers" ]; then
354 addrev --release --nopr $reviewers
358 # Create our temporary update branch, if it's not the release branch.
359 # This is used in post-release below
361 $VERBOSE "== Creating a local update branch: $tmp_update_branch"
362 git branch $git_quiet "$tmp_update_branch"
365 # Write the version information we updated
368 if [ -n "$PRE_LABEL" ]; then
369 release="$VERSION$_PRE_RELEASE_TAG$_BUILD_METADATA"
370 release_text="$SERIES$_BUILD_METADATA $PRE_LABEL $PRE_NUM"
371 announce_template=openssl-announce-pre-release.tmpl
373 release="$VERSION$_BUILD_METADATA"
374 release_text="$release"
375 announce_template=openssl-announce-release.tmpl
377 tag="$(std_tag_name)"
378 $VERBOSE "== Updated version information to $release"
380 $VERBOSE "== Updating files with release date for $release : $RELEASE_DATE"
381 for fixup in "$RELEASE_AUX"/fixup-*-release.pl; do
382 file="$(basename "$fixup" | sed -e 's|^fixup-||' -e 's|-release\.pl$||')"
384 RELEASE="$release" RELEASE_TEXT="$release_text" RELEASE_DATE="$RELEASE_DATE" \
385 perl -pi $fixup $file
388 $VERBOSE "== Committing updates and tagging"
390 git commit $git_quiet -m "Prepare for release of $release_text"$'\n\nRelease: yes'
391 if [ -n "$reviewers" ]; then
392 addrev --release --nopr $reviewers
394 echo "Tagging release with tag $tag. You may need to enter a pass phrase"
395 git tag$tagkey "$tag" -m "OpenSSL $release release tag"
397 tarfile=openssl-$release.tar
399 announce=openssl-$release.txt
401 echo "== Generating tar, hash and announcement files. This make take a bit of time"
403 $VERBOSE "== Making tarfile: $tgzfile"
404 # Unfortunately, util/mktar.sh does verbose output on STDERR... for good
405 # reason, but it means we don't display errors unless --verbose
406 ./util/mktar.sh --tarfile="../$tarfile" 2>&1 \
407 | while read L; do $VERBOSE "> $L"; done
409 if ! [ -f "../$tgzfile" ]; then
410 echo >&2 "Where did the tarball end up? (../$tgzfile)"
414 $VERBOSE "== Generating checksums: $tgzfile.sha1 $tgzfile.sha256"
415 openssl sha1 < "../$tgzfile" | \
416 (IFS='='; while read X H; do echo $H; done) > "../$tgzfile.sha1"
417 openssl sha256 < "../$tgzfile" | \
418 (IFS='='; while read X H; do echo $H; done) > "../$tgzfile.sha256"
419 length=$(wc -c < "../$tgzfile")
420 sha1hash=$(cat "../$tgzfile.sha1")
421 sha256hash=$(cat "../$tgzfile.sha256")
423 $VERBOSE "== Generating announcement text: $announce"
424 # Hack the announcement template
425 cat "$RELEASE_AUX/$announce_template" \
426 | sed -e "s|\\\$release_text|$release_text|g" \
427 -e "s|\\\$release|$release|g" \
428 -e "s|\\\$series|$SERIES|g" \
429 -e "s|\\\$label|$PRE_LABEL|g" \
430 -e "s|\\\$tarfile|$tgzfile|" \
431 -e "s|\\\$length|$length|" \
432 -e "s|\\\$sha1hash|$sha1hash|" \
433 -e "s|\\\$sha256hash|$sha256hash|" \
434 | perl -p "$RELEASE_AUX/fix-title.pl" \
437 $VERBOSE "== Generating signatures: $tgzfile.asc $announce.asc"
438 rm -f "../$tgzfile.asc" "../$announce.asc"
439 echo "Signing the release files. You may need to enter a pass phrase"
440 gpg$gpgkey --use-agent -sba "../$tgzfile"
441 gpg$gpgkey --use-agent -sta --clearsign "../$announce"
443 # Push everything to the parent repo
444 $VERBOSE "== Push what we have to the parent repository"
445 git push --follow-tags parent HEAD
449 if [ "$VERBOSE" != ':' ]; then
452 echo "put ../$tgzfile"
453 echo "put ../$tgzfile.sha1"
454 echo "put ../$tgzfile.sha256"
455 echo "put ../$tgzfile.asc"
456 echo "put ../$announce.asc"
458 | sftp "$upload_address"
461 # Post-release #######################################################
463 $VERBOSE "== Reset all files to their pre-release contents"
464 git reset $git_quiet HEAD^ -- .
467 prev_release_text="$release_text"
468 prev_release_date="$RELEASE_DATE"
470 next_release_state "$next_method2"
473 release="$VERSION$_PRE_RELEASE_TAG$_BUILD_METADATA"
474 release_text="$VERSION$_BUILD_METADATA"
475 if [ -n "$PRE_LABEL" ]; then
476 release_text="$SERIES$_BUILD_METADATA $PRE_LABEL $PRE_NUM"
478 $VERBOSE "== Updated version information to $release"
480 $VERBOSE "== Updating files for $release :"
481 for fixup in "$RELEASE_AUX"/fixup-*-postrelease.pl; do
482 file="$(basename "$fixup" | sed -e 's|^fixup-||' -e 's|-postrelease\.pl$||')"
484 RELEASE="$release" RELEASE_TEXT="$release_text" \
485 PREV_RELEASE_TEXT="$prev_release_text" \
486 PREV_RELEASE_DATE="$prev_release_date" \
487 perl -pi $fixup $file
490 $VERBOSE "== Committing updates"
492 git commit $git_quiet -m "Prepare for $release_text"$'\n\nRelease: yes'
493 if [ -n "$reviewers" ]; then
494 addrev --release --nopr $reviewers
497 # Push everything to the parent repo
498 $VERBOSE "== Push what we have to the parent repository"
502 $VERBOSE "== Going back to the update branch $tmp_update_branch"
503 git checkout $git_quiet "$tmp_update_branch"
506 next_release_state "minor"
509 release="$VERSION$_PRE_RELEASE_TAG$_BUILD_METADATA"
510 release_text="$SERIES$_BUILD_METADATA"
511 $VERBOSE "== Updated version information to $release"
513 $VERBOSE "== Updating files for $release :"
514 for fixup in "$RELEASE_AUX"/fixup-*-postrelease.pl; do
515 file="$(basename "$fixup" | sed -e 's|^fixup-||' -e 's|-postrelease\.pl$||')"
517 RELEASE="$release" RELEASE_TEXT="$release_text" \
518 perl -pi $fixup $file
521 $VERBOSE "== Committing updates"
523 git commit $git_quiet -m "Prepare for $release_text"$'\n\nRelease: yes'
524 if [ -n "$reviewers" ]; then
525 addrev --release --nopr $reviewers
529 # Push everything to the parent repo
530 $VERBOSE "== Push what we have to the parent repository"
533 # Done ###############################################################
540 ======================================================================
541 The release is done, and involves a few files and commits for you to
542 deal with. Everything you need has been pushed to your repository,
543 please see instructions that follow.
544 ======================================================================
551 The following files were uploaded to $upload_address, please ensure they
552 are dealt with appropriately:
564 ----------------------------------------------------------------------
569 You need to prepare the main repository with a new branch, '$release_branch'.
570 That is done directly in the server's bare repository like this:
572 git branch $release_branch $orig_HEAD
574 Two additional release branches have been added to your repository.
575 Push them to github, make PRs from them and have them approved:
580 When merging them into the main repository, do it like this:
582 git push git@github.openssl.org:openssl/openssl.git \\
583 $tmp_release_branch:$release_branch
584 git push git@github.openssl.org:openssl/openssl.git \\
585 $tmp_update_branch:$update_branch
586 git push git@github.openssl.org:openssl/openssl.git \\
591 One additional release branch has been added to your repository.
592 Push it to github, make a PR from it and have it approved:
596 When merging it into the main repository, do it like this:
598 git push git@github.openssl.org:openssl/openssl.git \\
599 $tmp_release_branch:$release_branch
600 git push git@github.openssl.org:openssl/openssl.git \\
607 ----------------------------------------------------------------------
612 When everything is done, or if something went wrong and you want to start
613 over, simply clean away temporary things left behind:
615 The release worktree:
617 rm -rf $release_clone
623 The additional release branches:
625 git branch -D $tmp_release_branch
626 git branch -D $tmp_update_branch
631 The temporary release branch:
633 git branch -D $tmp_release_branch
639 # cat is inconsequential, it's only there to fend off zealous shell parsers
640 # that parse all the way here.
647 release.sh - OpenSSL release script
658 B<--local-user>=I<keyid> |
659 B<--reviewer>=I<id> |
670 B<release.sh> creates an OpenSSL release, given current worktree conditions.
671 It will refuse to work unless the current branch is C<master> or a release
672 branch (see L</RELEASE BRANCHES AND TAGS> below for a discussion on those).
674 B<release.sh> tries to be smart and figure out the next release if no hints
675 are given through options, and will exit with an error in ambiguous cases.
677 B<release.sh> finishes off with instructions on what to do next. When
678 finishing commands are given, they must be followed exactly.
680 B<release.sh> leaves behind a clone of the local workspace, as well as one
681 or two branches in the local repository. These will be mentioned and can
682 safely be removed after all instructions have been successfully followed.
688 =item B<--alpha>, B<--beta>
690 Set the state of this branch to indicate that alpha or beta releases are
693 B<--alpha> is only acceptable if the I<PATCH> version number is zero and
694 the current state is "in development" or that alpha releases are ongoing.
696 B<--beta> is only acceptable if the I<PATCH> version number is zero and
697 that alpha or beta releases are ongoing.
701 Use together with B<--alpha> to switch to beta releases after the current
706 Set the state of this branch to indicate that regular releases are to be
707 done. This is only valid if alpha or beta releases are currently ongoing.
709 This implies B<--branch>.
713 Create a branch specific for the I<SERIES> release series, if it doesn't
714 already exist, and switch to it. The exact branch name will be
715 C<< openssl-I<SERIES> >>.
719 Don't upload the produced files.
723 Don't run C<make update> and C<make update-fips-checksums>.
731 Display extra debug output. Implies B<--no-upload>
733 =item B<--local-user>=I<keyid>
735 Use I<keyid> as the local user for C<git tag> and for signing with C<gpg>.
737 If not given, then the default e-mail address' key is used.
739 =item B<--reviewer>=I<id>
741 Add I<id> to the set of reviewers for the commits performed by this script.
742 Multiple reviewers are allowed.
744 If no reviewer is given, you will have to run C<addrev> manually, which
745 means retagging a release commit manually as well.
749 Force execution. Precisely, the check that the current branch is C<master>
750 or a release branch is not done.
754 Display a quick help text and exit.
758 Display this manual and exit.
762 =head1 RELEASE BRANCHES AND TAGS
764 Prior to OpenSSL 3.0, the release branches were named
765 C<< OpenSSL_I<SERIES>-stable >>, and the release tags were named
766 C<< OpenSSL_I<VERSION> >> for regular releases, or
767 C<< OpenSSL_I<VERSION>-preI<n> >> for pre-releases.
769 From OpenSSL 3.0 ongoing, the release branches are named
770 C<< openssl-I<SERIES> >>, and the release tags are named
771 C<< openssl-I<VERSION> >> for regular releases, or
772 C<< openssl-I<VERSION>-alphaI<n> >> for alpha releases
773 and C<< openssl-I<VERSION>-betaI<n> >> for beta releases.
775 B<release.sh> recognises both forms.
777 =head1 VERSION AND STATE
779 With OpenSSL 3.0, all the version and state information is in the file
780 F<VERSION.dat>, where the following variables are used and changed:
784 =item B<MAJOR>, B<MINOR>, B<PATCH>
786 The three part of the version number.
788 =item B<PRE_RELEASE_TAG>
790 The indicator of the current state of the branch. The value may be one pf:
796 This branch is "in development". This is typical for the C<master> branch
797 unless there are ongoing alpha or beta releases.
799 =item C<< alphaI<n> >> or C<< alphaI<n>-dev >>
801 This branch has alpha releases going on. C<< alphaI<n>-dev >> is what
802 should normally be seen in the git workspace, indicating that
803 C<< alphaI<n> >> is in development. C<< alphaI<n> >> is what should be
804 found in the alpha release tar file.
806 =item C<< alphaI<n> >> or C<< alphaI<n>-dev >>
808 This branch has beta releases going on. The details are otherwise exactly
813 This is normally not seen in the git workspace, but should always be what's
814 found in the tar file of a regular release.
818 =item B<BUILD_METADATA>
820 Extra build metadata to be used by anyone for their own purposes.
822 =item B<RELEASE_DATE>
824 This is normally empty in the git workspace, but should always have the
825 release date in the tar file of any release.
831 Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved.
833 Licensed under the Apache License 2.0 (the "License"). You may not use
834 this file except in compliance with the License. You can obtain a copy
835 in the file LICENSE in the source distribution or at
836 L<https://www.openssl.org/source/license.html>.