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