These are informal notes on how to do an OCaml release.
Following these steps requires commit right in the OCaml repository, as well as SSH access to the inria.fr file servers hosting the distribution archives and manual.
We are not fully confident that those steps are correct, feel free to check with other release managers in case of doubt.
Note: we say that a new release is a "testing release" if it is a Beta version or Release Candidate. Otherwise, we call it a "production release".
Send a mail on caml-devel to warn Gabriel (to make a pass on Changes; see the "Changes curation" appendix for more details) and the OCamlLabs folks (for OPAM testing).
rm -f /tmp/env-$USER.sh
cat >/tmp/env-$USER.sh <<EOF
# Update the data below
export MAJOR=5
export MINOR=2
export BUGFIX=0
export PLUSEXT=
# names for the release announce
export HUMAN=
# do we need to use tar or gtar?
export TAR=tar
export WORKTREE=~/ocaml/\$MAJOR.\$MINOR
# must be the git worktree for the branch you are releasing
export BRANCH=\$MAJOR.\$MINOR
export VERSION=\$MAJOR.\$MINOR.\$BUGFIX\$PLUSEXT
export TAGVERSION=\`echo \$VERSION | sed s/\~/-/g\`
export REPO=https://github.com/ocaml/ocaml
# these values are specific to caml.inria's host setup
# they are defined in the release manager's .bashrc file
export ARCHIVE_HOST="$OCAML_RELEASE_ARCHIVE_HOST"
export ARCHIVE_PATH="$OCAML_RELEASE_ARCHIVE_PATH"
export WEB_HOST="$OCAML_RELEASE_WEB_HOST"
export WEB_PATH="$OCAML_RELEASE_WEB_PATH"
export DIST="\$ARCHIVE_PATH/ocaml/ocaml-\$MAJOR.\$MINOR"
export INSTDIR="/tmp/ocaml-\$VERSION"
EOF
source /tmp/env-$USER.sh
echo $VERSION
cd $WORKTREE
git checkout $MAJOR.$MINOR
git status # check that the local repo is in a clean state
git pull
If you are about to do a major release, you should check that the magic numbers have been updated since the last major release. It is preferable to do this just before the first testing release for this major version, typically the first beta.
See the utils/HACKING.adoc
file for documentation on how to bump the
magic numbers.
make distclean
git clean -n -d -f -x # Check that "make distclean" removed everything
rm -rf ${INSTDIR}
./configure --prefix=${INSTDIR}
make -j5
# Check that dependencies are up-to-date
make alldepend
git diff
# should have empty output
# check that .depend files have no absolute path in them
find . -name .depend | xargs grep ' /'
# must have empty output
# Run the check-typo script
./tools/check-typo
make install
./tools/check-symbol-names runtime/*.a
# must have empty output and return 0
make tests
# at this point, the build-aux/ocaml_version.m4 file contains N+devD
# increment it into N+dev(D+1); for example,
# 4.07.0+dev8-2018-06-19 => 4.07.0+dev9-2018-06-26
# for production releases: check and change the Changes header
# (remove "next version" and add a date)
tools/autogen
git commit -a -m "last commit before tagging $VERSION"
# update build-aux/ocaml_version.m4 with the new release; for example,
# 4.07.0+dev9-2018-06-26 => 4.07.0+rc2
# Update ocaml-variants.opam with new version.
tools/autogen
# For a production release
make coreboot -j5
make coreboot -j5 # must say "Fixpoint reached, bootstrap succeeded."
git commit -m "release $VERSION" -a
git tag -m "release $VERSION" $TAGVERSION
# for production releases, change the build-aux/ocaml_version.m4 file into (N+1)+dev0; for example,
# 4.08.0 => 4.08.1+dev0
# for testing candidates, use N+dev(D+2) instead; for example,
# 4.07.0+rc2 => 4.07.0+dev10-2018-06-26
# Revert ocaml-variants.opam to its "trunk" version.
tools/autogen
git commit -m "increment version number after tagging $VERSION" build-aux/ocaml_version.m4 VERSION configure ocaml-variants.opam
git push
git push --tags
This needs to be more tested, tread with care.
# at this point, the build-aux/ocaml_version.m4 file contains N+devD
# increment it into N+dev(D+1); for example,
# 4.07.0+dev0-2018-06-19 => 4.07.0+dev1-2018-06-26
# Rename the "Working version" header in Changes
# to "OCaml $BRANCH"
tools/autogen
git commit -a -m "last commit before branching $BRANCH"
git branch $BRANCH
# update build-aux/ocaml_version.m4 with the new future branch,
# 4.07.0+dev1-2018-06-26 => 4.08.0+dev0-2018-06-30
# Update ocaml-variants.opam with new version.
tools/autogen
# Add a "Working version" section" to Changes
# Add common subsections in Changes, see Changelog.
git commit -m "first commit after branching $BRANCH" -a
git push
# Switch to the new branch
git checkout $BRANCH
# increment VERSION, for instance
# 4.07.0+dev1-2018-06-26 => 4.07.0+dev2-2018-06-30
tools/autogen
git commit -m "first commit on branch $BRANCH" -a
git push --set-upstream origin $BRANCH
Adjust github branch settings:
Go to https://github.com/ocaml/ocaml/settings/branches and add a rule for protecting the new branch (copy the rights from the previous version)
open https://github.com/ocaml/ocaml/releases
Bug fixes. See detailed list of changes.
Add the new release branch to the Inria CI list. Remove the oldest branch from this list.
Add a badge for the new branch in README.adoc. Remove the oldest badge.
Clone the opam-repository
git clone https://github.com/ocaml/opam-repository
Create a branch for the new release
git checkout -b OCaml_$VERSION
The following opam packages are needed for all releases:
ocaml-base-compiler.$VERSION
ocaml-variants.$VERSION+options
For production release, the following packages need to be updated:
ocaml-system.$VERSION
ocaml-src.$VERSION
ocaml-src.$MAJOR.$MINOR.dev
ocaml-manual.$VERSION
ocaml.$NEXTVERSION
ocaml-variants.$NEXTVERSION+trunk
should be moved toocaml-variants.$NEXTNEXTVERSION+trunk
Note that the ocaml
virtual package needs to be updated to the next version.
Similarly, the ocurrent/ocaml-version
library should be updated.
Do not forget to add/update the checksum field for the tarballs in the "url" section of the opam files. Use opam-lint before sending the pull request.
You can test the new opam package before sending a PR to the main opam-repository by using the local repository:
opam repo add local /path/to/your/opam-repository
opam switch create --repo=local,beta=git+https://github.com/ocaml/ocaml-beta-repository.git ocaml-variants.$VERSION
The switch should build.
For a production release, you also need to create new opam files for the ocaml-manual and ocaml-src packages.
Create a new ocaml/ocaml.$NEXT/opam file. Copy the opam dev files from ocaml-variants/ocaml-variants.$VERSION+trunk* into ocaml-variants/ocaml-variants.$NEXT+trunk+* . Update the version in those opam files.
Update the synopsis and "src" field in the opam $VERSION packages. The "src" field should point to src: "https://github.com/ocaml/ocaml/archive/$VERSION.tar.gz" The synopsis should be "latest $VERSION development(,...)".
cd $WORKTREE
TMPDIR=/tmp/ocaml-release
git checkout $TAGVERSION
git checkout-index -a -f --prefix=$TMPDIR/ocaml-$VERSION/
git switch $BRANCH
cd $TMPDIR
$TAR -c --owner 0 --group 0 -f ocaml-$VERSION.tar ocaml-$VERSION
gzip -9 <ocaml-$VERSION.tar >ocaml-$VERSION.tar.gz
xz <ocaml-$VERSION.tar >ocaml-$VERSION.tar.xz
For the first beta of a major version, create the distribution directory on the server:
ssh $ARCHIVE_HOST "mkdir -p $DIST"
Upload the archives:
scp ocaml-$VERSION.tar.{xz,gz} $ARCHIVE_HOST:$DIST
To update the checksum files on the remote host, we first upload the release environment. (note: this assumes the user name is the same on the two machines)
scp /tmp/env-$USER.sh $ARCHIVE_HOST:/tmp/env-$USER.sh
and then login there to update the checksums (MD5SUM, SHA512SUM)
ssh $ARCHIVE_HOST
source /tmp/env-$USER.sh
cd $DIST
cp MD5SUM MD5SUM.old
md5sum ocaml-$VERSION.tar.{xz,gz} > new-md5s
# check new-md5s to ensure that they look right, and then
cat new-md5s >> MD5SUM
# if everything worked well,
rm MD5SUM.old new-md5s
# same thing for SHA512
cp SHA512SUM SHA512SUM.old
sha512sum ocaml-$VERSION.tar.{xz,gz} > new-sha512s
cat new-sha512s >> SHA512SUM
rm SHA512SUM.old new-sha512s
# clean up
rm /tmp/env-$USER.sh
exit
ssh $ARCHIVE_HOST "mkdir -p $DIST/notes"
cd ocaml-$VERSION
scp INSTALL.adoc LICENSE README.adoc README.win32.adoc Changes \
$ARCHIVE_HOST:$DIST/notes/
You don't need to do this if the previous release had the same $MAJOR.$MINOR ($BRANCH) value and the exact same manual -- this is frequent if it was a release candidate.
cd $WORKTREE
make
cd manual
make clean
make
rm -rf /tmp/release
mkdir -p /tmp/release
RELEASENAME="ocaml-$BRANCH-"
make -C manual release RELEASE=/tmp/release/$RELEASENAME
scp /tmp/release/* $ARCHIVE_HOST:$DIST/
# upload manual checksums
ssh $ARCHIVE_HOST "cd $DIST; md5sum ocaml-$BRANCH-refman* >>MD5SUM"
ssh $ARCHIVE_HOST "cd $DIST; sha512sum ocaml-$BRANCH-refman* >>SHA512SUM"
Releasing the manual online happens on another machine: Do this ONLY FOR A PRODUCTION RELEASE
scp /tmp/env-$USER.sh $ARCHIVE_HOST:/tmp/env-$USER.sh
ssh $ARCHIVE_HOST
source /tmp/env-$USER.sh
scp /tmp/env-$USER.sh $WEB_HOST:/tmp
ssh $WEB_HOST
source /tmp/env-$USER.sh
cd $WEB_PATH/caml/pub/docs
mkdir -p manual-ocaml-$BRANCH
cd manual-ocaml-$BRANCH
rm -fR htmlman ocaml-$BRANCH-refman-html.tar.gz
wget http://caml.inria.fr/pub/distrib/ocaml-$BRANCH/ocaml-$BRANCH-refman-html.tar.gz
tar -xzvf ocaml-$BRANCH-refman-html.tar.gz # this extracts into htmlman/
/bin/cp -r htmlman/* . # move HTML content to docs/manual-caml-$BRANCH
rm -fR htmlman ocaml-$BRANCH-refman-html.tar.gz
cd $WEB_PATH/caml/pub/docs
rm manual-ocaml
ln -sf manual-ocaml-$BRANCH manual-ocaml
For production releases, you should get in touch with ocaml.org to organize the webpage for the new release. See
See the email announce templates in the templates/
directory.
Try to propagate the new compiler to external open source tools
Godbold CE (https://godbolt.org)
- Send a PR to both https://github.com/compiler-explorer/infra and https://github.com/compiler-explorer/compiler-explorer
See compiler-explorer/compiler-explorer#6735 and compiler-explorer/infra#1359 as examples.
This should be expanded, once we have more experince with the process
See
- templates/beta.md for alpha and beta releases
- templates/rc.md for release candidate
- templates/production.md for the production release
A list of common subsection for the "Changes" file:
### Language features:
### Runtime system:
### Code generation and optimizations:
### Standard library:
### Other libraries:
### Tools:
### Manual and documentation:
### Compiler user-interface and warnings:
### Internal/compiler-libs changes:
### Build system:
### Bug fixes:
Here is the process that Gabriel uses to curate the Changes entries of a release in preparation. Feel free to take care of it if you wish.
(In theory it would be possible to maintain the Changes in excellent shape so that no curation would be necessary. In practice it is less work and less friction to tolerate imperfect Changes entries, and curate them before the release.)
The Changes entries of a release branch or past release should be exactly included in the trunk Changes, in the section of this release (or release branch). Use an interactive diffing tool (for example "meld") to compare and synchronize the Changes files of trunk and release branches.
Here are typical forms of divergence and their usual solutions:
-
A change entry is present in a different section in two branches. (Typically: in the XX.YY section of the XX.YY release branch, but in the trunk section of the trunk branch.)
This usually happens when the PR is written for a given branch first, and then cherry-picked in an older maintenance branch, but the cherry-picker forgets to move the Change entry in the first branch.
Fix: ensure that the entry is in the same section on all branches, by putting it in the "smallest" version -- assuming that all bigger versions also contain this change.
-
A change entry is present in a given section, but the change is not present in the corresponding release branch.
There are two common causes for this with radically different solutions:
-
If a PR is merged a long time after they were submitted, the merge may put their Changes entry in the section of an older release, while it should go in trunk.
Fix: in trunk, move the entry to the trunk section.
-
Sometimes the author of a PR against trunk intends it to be cherry-picked in an older release branch, and places it in the corresponding Changes entry, but we forget to cherry-pick.
Fix: cherry-pick the PR in the appropriate branch.
Reading the PR discussion is often enough to distinguish between the two cases, but one should be careful before cherry-picking in a branch (for an active release branch, check with the release manager(s)).
-
Figuring out the status of a given Changes entry often requires checking the git log for trunk and branches. Grepping for the PR number often suffices (note: when you cherry-pick a PR in a release branch, please target the merge commit to ensure the PR number is present in the log), or parts of the commit message text.
(of course)
Expert users want to learn about the changes in the new release. We want to avoid forcing them to read the tortuous PR discussion, by giving enough details in the Changes entry.
In particular, for language changes, showing a small example of concrete syntax of the new feature is very useful, and giving a few words of explanations helps.
Compare for example
- #8820: quoted string extensions
(Gabriel Radanne, Leo White and Gabriel Scherer,
request by Bikal Lem)
with
- #8820: quoted extensions: {%foo|...|} is lighter syntax for
[%foo {||}], and {%foo bar|...|bar} for [%foo {bar|...|bar}].
(Gabriel Radanne, Leo White and Gabriel Scherer,
request by Bikal Lem)
This is also important for changes that break compatibility; users will scrutinize them with more care, so please give clear information on what breaks and, possibly, recommended update methods.
Having enough details is also useful when you will grep the Changes later to know when a given change was introduced (knowing what to grep can be difficult).
In the past, we would order Changes entries numerically (this would also correspond to a chronological order). Since 4.09 Gabriel is trying to order them by importance (being an exciting/notable feature for a large number of users). What is the best ordering of sections, and the best entry ordering within a section, to put the most important changes first? This is guesswork of course, and we commonly have a long tail of "not so important PRs" in each section which don't need to be ordered with respect to each other -- one may break two lines just before this long tail.
The ordering of sections depends on the nature of the changes within the release; some releases have an exciting "Runtime" section, many release don't. Usually "Language features" is among the first, and "Bug fixes" is the very last (who cares about bugs, right?).
If some entries feel very anecdotal, consider moving them to the Bug Fixes section.
From time to time, synchronize the News
file with the release highlights
of each version.