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 --upload-address=<address>
37 The location to upload release files to (default:
38 upload@dev.openssl.org)
39 --no-upload Don't upload the release files.
40 --no-update Don't perform 'make update' and 'make update-fips-checksums'.
41 --verbose Verbose output.
42 --debug Include debug output. Implies --no-upload.
44 --force Force execution
49 If none of --alpha, --beta, or --final are given, this script tries to
50 figure out the next step.
55 # Set to one of 'major', 'minor', 'alpha', 'beta' or 'final'
78 upload_address=upload@dev.openssl.org
80 TEMP=$(getopt -l 'alpha,next-beta,beta,final' \
82 -l 'upload-address:' \
83 -l 'no-upload,no-update' \
89 -n release.sh -- - "$@")
93 --alpha | --beta | --final )
94 next_method=$(echo "x$1" | sed -e 's|^x--||')
95 if [ -z "$next_method2" ]; then
96 next_method2=$next_method
99 if [ "$next_method" = 'final' ]; then
104 next_method2=$(echo "x$1" | sed -e 's|^x--next-||')
142 reviewers="$reviewers $1=$2"
155 sed -e '1,/^### BEGIN MANUAL/d' \
156 -e '/^### END MANUAL/,$d' \
167 echo >&2 "Unknown option $1"
174 $DEBUG >&2 "DEBUG: \$next_method=$next_method"
175 $DEBUG >&2 "DEBUG: \$next_method2=$next_method2"
177 $DEBUG >&2 "DEBUG: \$do_branch=$do_branch"
179 $DEBUG >&2 "DEBUG: \$do_upload=$do_upload"
180 $DEBUG >&2 "DEBUG: \$do_update=$do_update"
181 $DEBUG >&2 "DEBUG: \$DEBUG=$DEBUG"
182 $DEBUG >&2 "DEBUG: \$VERBOSE=$VERBOSE"
183 $DEBUG >&2 "DEBUG: \$git_quiet=$git_quiet"
185 case "$next_method+$next_method2" in
186 major+major | minor+minor )
189 alpha+alpha | alpha+beta | beta+beta | final+final | + | +beta )
193 echo >&2 "Internal option error ($next_method, $next_method2)"
198 # Verbosity feed for certain commands
199 VERBOSITY_FIFO=/tmp/openssl-$$.fifo
200 mkfifo -m 600 $VERBOSITY_FIFO
201 ( cat $VERBOSITY_FIFO | while read L; do $VERBOSE "> $L"; done ) &
202 exec 42>$VERBOSITY_FIFO
203 trap "exec 42>&-; rm $VERBOSITY_FIFO" 0 2
205 # Setup ##############################################################
207 # Check that we have the scripts that define functions we use
208 RELEASE_AUX=$(cd $(dirname $0)/release-aux; pwd)
210 for fn in "$RELEASE_AUX/release-version-fn.sh" \
211 "$RELEASE_AUX/release-state-fn.sh" \
212 "$RELEASE_AUX/upload-fn.sh"; do
213 if ! [ -f "$fn" ]; then
214 echo >&2 "'$fn' is missing"
222 # Load version functions
223 . $RELEASE_AUX/release-version-fn.sh
224 . $RELEASE_AUX/release-state-fn.sh
225 # Load upload backend functions
226 . $RELEASE_AUX/upload-fn.sh
228 # Make sure we're in the work directory, and remember it
229 if HERE=$(git rev-parse --show-toplevel); then
232 echo >&2 "Not in a git worktree"
236 # Make sure that it's a plausible OpenSSL work tree, by checking
237 # that a version file is found
240 if [ -z "$VERSION_FILE" ]; then
241 echo >&2 "Couldn't find OpenSSL version data"
245 # Make sure it's a branch we recognise
246 orig_branch=$(git rev-parse --abbrev-ref HEAD)
247 if (echo "$orig_branch" \
250 -e '^OpenSSL_[0-9]+_[0-9]+_[0-9]+[a-z]*-stable$' \
251 -e '^openssl-[0-9]+\.[0-9]+$'); then
256 echo >&2 "Not in master or any recognised release branch"
257 echo >&2 "Please 'git checkout' an appropriate branch"
260 orig_HEAD=$(git rev-parse HEAD)
262 # Make sure that we have fixup scripts for all the files that need
263 # to be modified for a release. We trust this, because we're not
264 # going to change versioning scheme in the middle of a release.
268 for fn in $RELEASE_FILES; do
269 for file in "$RELEASE_AUX/fixup-$fn-release.pl" \
270 "$RELEASE_AUX/fixup-$fn-postrelease.pl"; do
271 if ! [ -f "$file" ]; then
272 echo >&2 "'$file' is missing"
282 # We turn upload_address into a few variables, which can be used
283 # by backends that must understand a subset of the SFTP commands
286 case "$upload_address" in
288 # Something with a colon is interpreted as the typical SCP
289 # location. We reinterpret that in our terms
290 upload_directory="${upload_address#*:}"
291 upload_address="${upload_address%%:*}"
297 sftp://?*/* | sftp://?* )
298 # First, remove the URI scheme
299 upload_address="${upload_address#sftp://}"
300 # Now we know that we have a host, followed by a slash, followed by
301 # a directory spec. If there is no slash, there's no directory.
302 upload_directory="${upload_address#*/}"
303 if [ "$upload_directory" = "$upload_address" ]; then
304 # There was nothing with a slash to remove, so no directory.
307 upload_address="${upload_address%%/*}"
311 echo >&2 "Invalid upload address $upload_address"
315 if $do_upload && ! [ -d "$upload_address" ]; then
316 echo >&2 "Not an existing directory: $upload_address"
323 # Initialize #########################################################
325 echo "== Initializing work tree"
327 # Generate a cloned directory name
328 release_clone="$orig_branch-release-tmp"
330 echo "== Work tree will be in $release_clone"
332 # Make a clone in a subdirectory and move there
333 if ! [ -d "$release_clone" ]; then
334 $VERBOSE "== Cloning to $release_clone"
335 git clone $git_quiet -b "$orig_branch" -o parent . "$release_clone"
341 # Branches we will work with. The release branch is where we make the
342 # changes for the release, the update branch is where we make the post-
344 update_branch="$orig_branch"
345 release_branch="$(std_branch_name)"
347 # among others, we only create a release branch if the patch number is zero
348 if [ "$update_branch" = "$release_branch" ] \
350 || [ $PATCH -ne 0 ]; then
351 if $do_branch && $warn_branch; then
352 echo >&2 "Warning! We're already in a release branch; --branch ignored"
357 if ! $do_branch; then
358 release_branch="$update_branch"
361 # Branches we create for PRs
362 branch_version="$VERSION${PRE_LABEL:+-$PRE_LABEL$PRE_NUM}"
363 tmp_update_branch="OSSL--$update_branch--$branch_version"
364 tmp_release_branch="OSSL--$release_branch--$branch_version"
366 # Check that we're still on the same branch as our parent repo, or on a
368 current_branch=$(git rev-parse --abbrev-ref HEAD)
369 if [ "$current_branch" = "$update_branch" ]; then
371 elif [ "$current_branch" = "$release_branch" ]; then
374 echo >&2 "The cloned sub-directory '$release_clone' is on a branch"
375 if [ "$update_branch" = "$release_branch" ]; then
376 echo >&2 "other than '$update_branch'."
378 echo >&2 "other than '$update_branch' or '$release_branch'."
380 echo >&2 "Please 'cd \"$(pwd)\"; git checkout $update_branch'"
385 $DEBUG >&2 "DEBUG: Source directory is $SOURCEDIR"
387 # Release ############################################################
389 # We always expect to start from a state of development
390 if [ "$TYPE" != 'dev' ]; then
391 echo >&2 "Not in a development branch"
392 echo >&2 "Have a look at the git log in $release_clone, it may be that"
393 echo >&2 "a previous crash left it in an intermediate state and that"
394 echo >&2 "need to drop the top commit:"
396 echo >&2 "(cd $release_clone; git reset --hard HEAD^)"
397 echo >&2 "# WARNING! LOOK BEFORE YOU ACT"
401 # Update the version information. This won't save anything anywhere, yet,
402 # but does check for possible next_method errors before we do bigger work.
403 next_release_state "$next_method"
405 # Create our temporary release branch
406 $VERBOSE "== Creating a local release branch: $tmp_release_branch"
407 git checkout $git_quiet -b "$tmp_release_branch"
409 echo "== Configuring OpenSSL for update and release. This may take a bit of time"
413 $VERBOSE "== Checking source file updates and fips checksums"
416 # As long as we're doing an alpha release, we can have symbols without specific
417 # numbers assigned. In a beta or final release, all symbols MUST have an
419 if [ "$next_method" != 'alpha' ] && grep -q '^renumber *:' Makefile; then
422 if grep -q '^update-fips-checksums *:' Makefile; then
423 make update-fips-checksums >&42
426 if [ -n "$(git status --porcelain --untracked-files=no --ignore-submodules=all)" ]; then
427 $VERBOSE "== Committing updates"
429 git commit $git_quiet -m $'make update\n\nRelease: yes'
430 if [ -n "$reviewers" ]; then
431 addrev --release --nopr $reviewers
435 # Create our temporary update branch, if it's not the release branch.
436 # This is used in post-release below
438 $VERBOSE "== Creating a local update branch: $tmp_update_branch"
439 git branch $git_quiet "$tmp_update_branch"
442 # Write the version information we updated
445 release="$FULL_VERSION"
446 if [ -n "$PRE_LABEL" ]; then
447 release_text="$SERIES$_BUILD_METADATA $PRE_LABEL $PRE_NUM"
448 announce_template=openssl-announce-pre-release.tmpl
450 release_text="$release"
451 announce_template=openssl-announce-release.tmpl
453 tag="$(std_tag_name)"
454 $VERBOSE "== Updated version information to $release"
456 $VERBOSE "== Updating files with release date for $release : $RELEASE_DATE"
459 for file in $RELEASE_FILES; do
460 fixup="$RELEASE_AUX/fixup-$(basename "$file")-release.pl"
462 RELEASE="$release" RELEASE_TEXT="$release_text" RELEASE_DATE="$RELEASE_DATE" \
463 perl -pi $fixup $file
467 $VERBOSE "== Committing updates and tagging"
469 git commit $git_quiet -m "Prepare for release of $release_text"$'\n\nRelease: yes'
470 if [ -n "$reviewers" ]; then
471 addrev --release --nopr $reviewers
473 echo "Tagging release with tag $tag. You may need to enter a pass phrase"
474 git tag$tagkey "$tag" -m "OpenSSL $release release tag"
476 tarfile=openssl-$release.tar
478 announce=openssl-$release.txt
480 echo "== Generating tar, hash and announcement files. This make take a bit of time"
482 $VERBOSE "== Making tarfile: $tgzfile"
484 # Unfortunately, some tarball generators do verbose output on STDERR... for
485 # good reason, but it means we don't display errors unless --verbose
487 if [ -f ./util/mktar.sh ]; then
488 ./util/mktar.sh --tarfile="../$tarfile" 2>&1
490 make DISTTARVARS=TARFILE="../$tarfile" dist 2>&1
492 ) | while read L; do $VERBOSE "> $L"; done
494 if ! [ -f "../$tgzfile" ]; then
495 echo >&2 "Where did the tarball end up? (../$tgzfile)"
499 $VERBOSE "== Generating checksums: $tgzfile.sha1 $tgzfile.sha256"
500 openssl sha1 < "../$tgzfile" | \
501 (IFS='='; while read X H; do echo $H; done) > "../$tgzfile.sha1"
502 openssl sha256 < "../$tgzfile" | \
503 (IFS='='; while read X H; do echo $H; done) > "../$tgzfile.sha256"
504 length=$(wc -c < "../$tgzfile")
505 sha1hash=$(cat "../$tgzfile.sha1")
506 sha256hash=$(cat "../$tgzfile.sha256")
508 $VERBOSE "== Generating announcement text: $announce"
509 # Hack the announcement template
510 cat "$RELEASE_AUX/$announce_template" \
511 | sed -e "s|\\\$release_text|$release_text|g" \
512 -e "s|\\\$release|$release|g" \
513 -e "s|\\\$series|$SERIES|g" \
514 -e "s|\\\$label|$PRE_LABEL|g" \
515 -e "s|\\\$tarfile|$tgzfile|" \
516 -e "s|\\\$length|$length|" \
517 -e "s|\\\$sha1hash|$sha1hash|" \
518 -e "s|\\\$sha256hash|$sha256hash|" \
519 | perl -p "$RELEASE_AUX/fix-title.pl" \
522 $VERBOSE "== Generating signatures: $tgzfile.asc $announce.asc"
523 rm -f "../$tgzfile.asc" "../$announce.asc"
524 echo "Signing the release files. You may need to enter a pass phrase"
525 gpg$gpgkey --use-agent -sba "../$tgzfile"
526 gpg$gpgkey --use-agent -sta --clearsign "../$announce"
528 # Push everything to the parent repo
529 $VERBOSE "== Push what we have to the parent repository"
530 git push --follow-tags parent HEAD
533 echo "== Upload tar, hash and announcement files"
537 # With sftp, the progress meter is enabled by default,
538 # so we turn it off unless --verbose was given
539 if [ "$VERBOSE" == ':' ]; then
542 if [ -n "$upload_directory" ]; then
543 echo "cd $upload_directory"
545 echo "put ../$tgzfile"
546 echo "put ../$tgzfile.sha1"
547 echo "put ../$tgzfile.sha256"
548 echo "put ../$tgzfile.asc"
549 echo "put ../$announce.asc"
550 ) | upload_backend_$upload_backend "$upload_address" $do_upload
552 # Post-release #######################################################
554 # Reset the files to their pre-release contents. This doesn't affect
555 # HEAD, but simply set all the files in a state that 'git revert -n HEAD'
556 # would have given, but without the artifacts that 'git revert' adds.
558 # This allows all the post-release fixup scripts to perform from the
559 # same point as the release fixup scripts, hopefully making them easier
560 # to write. This also makes the same post-release fixup scripts easier
561 # to run when --branch has been used, as they will be run both on the
562 # release branch and on the update branch, essentially from the same
563 # state for affected files.
564 $VERBOSE "== Reset all files to their pre-release contents"
565 git reset $git_quiet HEAD^ -- .
568 prev_release_text="$release_text"
569 prev_release_date="$RELEASE_DATE"
571 next_release_state "$next_method2"
574 release="$FULL_VERSION"
575 release_text="$VERSION$_BUILD_METADATA"
576 if [ -n "$PRE_LABEL" ]; then
577 release_text="$SERIES$_BUILD_METADATA $PRE_LABEL $PRE_NUM"
579 $VERBOSE "== Updated version information to $release"
581 $VERBOSE "== Updating files for $release :"
584 for file in $RELEASE_FILES; do
585 fixup="$RELEASE_AUX/fixup-$(basename "$file")-postrelease.pl"
587 RELEASE="$release" RELEASE_TEXT="$release_text" \
588 PREV_RELEASE_TEXT="$prev_release_text" \
589 PREV_RELEASE_DATE="$prev_release_date" \
590 perl -pi $fixup $file
594 $VERBOSE "== Committing updates"
596 git commit $git_quiet -m "Prepare for $release_text"$'\n\nRelease: yes'
597 if [ -n "$reviewers" ]; then
598 addrev --release --nopr $reviewers
601 # Push everything to the parent repo
602 $VERBOSE "== Push what we have to the parent repository"
606 $VERBOSE "== Going back to the update branch $tmp_update_branch"
607 git checkout $git_quiet "$tmp_update_branch"
610 next_release_state "minor"
613 release="$FULL_VERSION"
614 release_text="$SERIES$_BUILD_METADATA"
615 $VERBOSE "== Updated version information to $release"
617 $VERBOSE "== Updating files for $release :"
620 for file in $RELEASE_FILES; do
621 fixup="$RELEASE_AUX/fixup-$(basename "$file")-postrelease.pl"
623 RELEASE="$release" RELEASE_TEXT="$release_text" \
624 perl -pi $fixup $file
628 $VERBOSE "== Committing updates"
630 git commit $git_quiet -m "Prepare for $release_text"$'\n\nRelease: yes'
631 if [ -n "$reviewers" ]; then
632 addrev --release --nopr $reviewers
636 # Push everything to the parent repo
637 $VERBOSE "== Push what we have to the parent repository"
640 # Done ###############################################################
647 ======================================================================
648 The release is done, and involves a few files and commits for you to
649 deal with. Everything you need has been pushed to your repository,
650 please see instructions that follow.
651 ======================================================================
658 The following files were uploaded to $upload_address, please ensure they
659 are dealt with appropriately:
671 ----------------------------------------------------------------------
676 You need to prepare the main repository with a new branch, '$release_branch'.
677 That is done directly in the server's bare repository like this:
679 git branch $release_branch $orig_HEAD
681 Two additional release branches have been added to your repository.
682 Push them to github, make PRs from them and have them approved:
687 When merging them into the main repository, do it like this:
689 git push git@github.openssl.org:openssl/openssl.git \\
690 $tmp_release_branch:$release_branch
691 git push git@github.openssl.org:openssl/openssl.git \\
692 $tmp_update_branch:$update_branch
693 git push git@github.openssl.org:openssl/openssl.git \\
698 One additional release branch has been added to your repository.
699 Push it to github, make a PR from it and have it approved:
703 When merging it into the main repository, do it like this:
705 git push git@github.openssl.org:openssl/openssl.git \\
706 $tmp_release_branch:$release_branch
707 git push git@github.openssl.org:openssl/openssl.git \\
714 ----------------------------------------------------------------------
719 When everything is done, or if something went wrong and you want to start
720 over, simply clean away temporary things left behind:
722 The release worktree:
724 rm -rf $release_clone
730 The additional release branches:
732 git branch -D $tmp_release_branch
733 git branch -D $tmp_update_branch
738 The temporary release branch:
740 git branch -D $tmp_release_branch
746 # cat is inconsequential, it's only there to fend off zealous shell parsers
747 # that parse all the way here.
754 release.sh - OpenSSL release script
765 B<--local-user>=I<keyid> |
766 B<--reviewer>=I<id> |
767 B<--upload-address>=I<address> |
778 B<release.sh> creates an OpenSSL release, given current worktree conditions.
779 It will refuse to work unless the current branch is C<master> or a release
780 branch (see L</RELEASE BRANCHES AND TAGS> below for a discussion on those).
782 B<release.sh> tries to be smart and figure out the next release if no hints
783 are given through options, and will exit with an error in ambiguous cases.
785 B<release.sh> finishes off with instructions on what to do next. When
786 finishing commands are given, they must be followed exactly.
788 B<release.sh> leaves behind a clone of the local workspace, as well as one
789 or two branches in the local repository. These will be mentioned and can
790 safely be removed after all instructions have been successfully followed.
796 =item B<--alpha>, B<--beta>
798 Set the state of this branch to indicate that alpha or beta releases are
801 B<--alpha> is only acceptable if the I<PATCH> version number is zero and
802 the current state is "in development" or that alpha releases are ongoing.
804 B<--beta> is only acceptable if the I<PATCH> version number is zero and
805 that alpha or beta releases are ongoing.
809 Use together with B<--alpha> to switch to beta releases after the current
814 Set the state of this branch to indicate that regular releases are to be
815 done. This is only valid if alpha or beta releases are currently ongoing.
817 This implies B<--branch>.
821 Create a branch specific for the I<SERIES> release series, if it doesn't
822 already exist, and switch to it. The exact branch name will be
823 C<< openssl-I<SERIES> >>.
825 =item B<--upload-address>=I<address>
827 The location that the release files are to be uploaded to. Supported values
834 an existing local directory
838 something that can be interpreted as an SCP/SFTP address. In this case,
839 SFTP will always be used. Typical SCP remote file specs will be translated
840 into something that makes sense for SFTP.
844 The default upload address is C<upload@dev.openssl.org>.
848 Don't upload the release files.
852 Don't run C<make update> and C<make update-fips-checksums>.
860 Display extra debug output. Implies B<--no-upload>
862 =item B<--local-user>=I<keyid>
864 Use I<keyid> as the local user for C<git tag> and for signing with C<gpg>.
866 If not given, then the default e-mail address' key is used.
868 =item B<--reviewer>=I<id>
870 Add I<id> to the set of reviewers for the commits performed by this script.
871 Multiple reviewers are allowed.
873 If no reviewer is given, you will have to run C<addrev> manually, which
874 means retagging a release commit manually as well.
878 Force execution. Precisely, the check that the current branch is C<master>
879 or a release branch is not done.
883 Display a quick help text and exit.
887 Display this manual and exit.
891 =head1 RELEASE BRANCHES AND TAGS
893 Prior to OpenSSL 3.0, the release branches were named
894 C<< OpenSSL_I<SERIES>-stable >>, and the release tags were named
895 C<< OpenSSL_I<VERSION> >> for regular releases, or
896 C<< OpenSSL_I<VERSION>-preI<n> >> for pre-releases.
898 From OpenSSL 3.0 ongoing, the release branches are named
899 C<< openssl-I<SERIES> >>, and the release tags are named
900 C<< openssl-I<VERSION> >> for regular releases, or
901 C<< openssl-I<VERSION>-alphaI<n> >> for alpha releases
902 and C<< openssl-I<VERSION>-betaI<n> >> for beta releases.
904 B<release.sh> recognises both forms.
906 =head1 VERSION AND STATE
908 With OpenSSL 3.0, all the version and state information is in the file
909 F<VERSION.dat>, where the following variables are used and changed:
913 =item B<MAJOR>, B<MINOR>, B<PATCH>
915 The three part of the version number.
917 =item B<PRE_RELEASE_TAG>
919 The indicator of the current state of the branch. The value may be one pf:
925 This branch is "in development". This is typical for the C<master> branch
926 unless there are ongoing alpha or beta releases.
928 =item C<< alphaI<n> >> or C<< alphaI<n>-dev >>
930 This branch has alpha releases going on. C<< alphaI<n>-dev >> is what
931 should normally be seen in the git workspace, indicating that
932 C<< alphaI<n> >> is in development. C<< alphaI<n> >> is what should be
933 found in the alpha release tar file.
935 =item C<< alphaI<n> >> or C<< alphaI<n>-dev >>
937 This branch has beta releases going on. The details are otherwise exactly
942 This is normally not seen in the git workspace, but should always be what's
943 found in the tar file of a regular release.
947 =item B<BUILD_METADATA>
949 Extra build metadata to be used by anyone for their own purposes.
951 =item B<RELEASE_DATE>
953 This is normally empty in the git workspace, but should always have the
954 release date in the tar file of any release.
960 Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved.
962 Licensed under the Apache License 2.0 (the "License"). You may not use
963 this file except in compliance with the License. You can obtain a copy
964 in the file LICENSE in the source distribution or at
965 L<https://www.openssl.org/source/license.html>.