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". ## A few days in advance 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). ## 0: release environment setup ``` rm -f /tmp/env-$USER.sh cat >/tmp/env-$USER.sh < 4.07.0+dev9-2018-06-26 # for production releases: check and change the Changes header # (remove "next version" and add a date) make -B configure git commit -a -m "last commit before tagging $VERSION" # update VERSION with the new release; for example, # 4.07.0+dev9-2018-06-26 => 4.07.0+rc2 # Update ocaml-variants.opam with new version. # Update \year in manual/manual/macros.hva make -B configure # 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" $VERSION # for production releases, change the VERSION 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. make -B configure git commit -m "increment version number after tagging $VERSION" VERSION configure ocaml-variants.opam git push git push --tags ``` ## 5-bis: Alternative for branching This needs to be more tested, tread with care. ``` # at this point, the VERSION 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" make -B configure git commit -a -m "last commit before branching $BRANCH" git branch $BRANCH # update VERSION 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. make -B configure # 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 make -B configure 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) ## 5.1: create the release on github (only for a production release) open https://github.com/ocaml/ocaml/releases # and click "Draft a new release" # for a minor release, the description is: Bug fixes. See [detailed list of changes](https://github.com/ocaml/ocaml/blob/$MAJOR.$MINOR/Changes). ## 5.3: Inria CI (for a new release branch) Add the new release branch to the Inria CI list. Remove the oldest branch from this list. ## 5.4 new badge in README.adoc (for a new release branch) Add a badge for the new branch in README.adoc. Remove the oldest badge. ## 6: create OPAM packages Clone the opam-repository ``` git clone https://github.com/ocaml/opam-repository ``` Create a branch for the new release ``` git checkout -b OCaml_$VERSION ``` Create ocaml-variants packages for the new version, copying the particular switch configuration choices from the previous version. 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. ## 6.1 Update OPAM dev packages after branching 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(,...)". ## 7: build the release archives ``` cd $WORKTREE TMPDIR=/tmp/ocaml-release git checkout $VERSION git checkout-index -a -f --prefix=$TMPDIR/ocaml-$VERSION/ cd $TMPDIR $TAR -c --owner 0 --group 0 -f ocaml-$VERSION.tar ocaml-$VERSION gzip -9 ocaml-$VERSION.tar.gz xz ocaml-$VERSION.tar.xz ``` ## 8: upload the archives and compute checksums 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 ``` ## 9: update note files (technical documentation) ``` ssh $ARCHIVE_HOST "mkdir -p $DIST/notes" cd ocaml-$VERSION scp INSTALL.adoc LICENSE README.adoc README.win32.adoc Changes \ $ARCHIVE_HOST:$DIST/notes/ ``` ## 10: upload the reference manual 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 make install export PATH="$INSTDIR/bin:$PATH" 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 ``` ## 11: prepare web announce for the release For production releases, you should get in touch with ocaml.org to organize the webpage for the new release. See ## 13: announce the release on caml-list, caml-announce, and discuss.ocaml.org See the email announce templates in the `templates/` directory. # Appendix ## Announce templates See - templates/beta.md for alpha and beta releases - templates/rc.md for release candidate - templates/production.md for the production release ## Changelog template for a new version 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: ``` ## Changes curation 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.) ### Synchronizing the trunk Changes with release branches 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. ### Ensure each entry is in the appropriate section (of course) ### Fill more details in unclear Changes entries 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). ### Ordering of Changes entries 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. ### Extract release highlights to News From time to time, synchronize the `News` file with the release highlights of each version.