.. _how-to-make-a-release: How to make a release ---------------------- The release manager makes the release, assisted by the release manager of the previous release, or if that person is not available, another previous release manager. Perform the steps listed below with two persons, to reduce the risk of error. .. note:: The previous release manager ensures the current release manager has the required administrative permissions to make the release. Consider the following services: `esmvalcore-feedstock `__ for making the conda-forge package, and `esmvaltool.dkrz.de `__ for uploading recipe runs for the ESMValTool release. Ask someone with administrative permissions to add you to the `@release-managers `_ team because only members of this team have permission to create tags in the GitHub repository. If the automation fails, you may need access to the following services: `PyPI `__, `DockerHub `__, `readthedocs `__. The release of ESMValCore is tied to the release of ESMValTool. The detailed steps can be found in the ESMValTool :ref:`documentation `. To start the procedure, ESMValCore gets released as a release candidate to test the recipes in ESMValTool. If bugs are found during the testing phase of the release candidate, make as many release candidates for ESMValCore as needed in order to fix them. .. figure:: /figures/release-timeline-doodle-esmvalcore.png :width: 95% :align: center Example of a release timeline for ESMValCore (in this case for 2.11.0) To make a new release of the package, be it a release candidate or the final release, follow these steps: 1. Check that all tests and builds work ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Check that the ``nightly`` `test run on CircleCI `__ was successful. - Check that the `GitHub Actions test runs `__ were successful. - Check that the documentation builds successfully on `readthedocs `__. - Check that the `Docker images `__ are building successfully. All tests should pass before making a release (branch). 2. Increase the version number ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The version number is automatically generated from the information provided by git using `setuptools-scm `__, but a static version number is stored in ``CITATION.cff``. Make sure to update the version number and release date in ``CITATION.cff``. See https://semver.org for more information on choosing a version number. Make a pull request and get it merged into ``main``. If updated after the release branch is created, cherry pick it into the release branch. 3. Add release notes ~~~~~~~~~~~~~~~~~~~~ Use the script :ref:`esmvaltool/utils/draft_release_notes.py ` to create create a draft of the release notes. This script uses the titles and labels of merged pull requests since the previous release date. Review the results, and if anything needs changing, change it on GitHub and re-run the script until the changelog looks acceptable. Copy the result to the file ``doc/changelog.rst``. Ensure that any pull request labelled as `issue introduced since last release `__ is listed on the same line as the pull request that introduced the issue. This label is intended for pull requests that fix a mistake that was introduced after the last release and therefore is not a bug that is present in any released version of the code. Open a discussion to allow members of the development team to nominate pull requests as highlights. Add the most voted pull requests as highlights at the beginning of changelog. After the highlights section, list any backward incompatible changes that the release may include. The :ref:`backward compatibility policy` lists the information that should be provided by the developer of any backward incompatible change. Make sure to also list any deprecations that the release may include, as well as a brief description on how to upgrade a deprecated feature. Make a pull request and get it merged into ``main``. If updated after the release branch is created, cherry pick it into the release branch. 4. Make the (pre-)release on GitHub ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Do a final check that all tests on CircleCI and GitHub Actions completed successfully. Then click the `releases tab `__ and create the new release. Create a tag corresponding to the release candidate or final release, e.g. ``v2.1.0rc1`` or ``v2.1.0``. You can add a link to the relevant changelog in the release notes. Tick the `This is a pre-release` box if working with a release candidate. If this is the *first* release candidate, create the release and tag off the ``main`` branch. We do this to inform `setuptools-scm `_ about the release, so that it increases the version number in ``main``. All subsequent release candidates and the final release are created off the release branch. 5. Create a release branch ~~~~~~~~~~~~~~~~~~~~~~~~~~ Create a branch off the first release candidate tag and push it to GitHub. This step only needs to be performed once for every minor release. For the ``v2.1`` release, the command to create the release branch would be: ``git checkout -b v2.1.x tags/v2.1.0rc1``, where ``v2.1.0rc1`` is the tag of the first release candidate. Release branches must be named ``vX.Y.x`` where ``X`` is the major and ``Y`` is the minor version number of the release to ensure setuptools-scm_ provides the correct version number for the release. 6. Create and upload the PyPI package ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The package is automatically uploaded to the `PyPI `__ by a GitHub action. Note that for security reasons, the upload needs to be approved by someone from the `ESMValGroup/technical-lead-development-team `__ who is not the author of the release. If the automatic build and upload has failed for some reason, do it manually by following these instructions: - Check out the tag corresponding to the release, e.g. ``git checkout tags/v2.1.0`` - Make sure your current working directory is clean by checking the output of ``git status`` and by running ``git clean -xdf`` to remove any files ignored by git. - Install the required packages: ``python3 -m pip install --upgrade build twine`` - Build the package: ``python3 -m build`` This command should generate two files in the ``dist`` directory, e.g. ``ESMValCore-2.3.1-py3-none-any.whl`` and ``ESMValCore-2.3.1.tar.gz``. - Upload the package: ``python3 -m twine upload dist/*`` You will be prompted for an API token if you have not set this up before, see `here `__ for more information. You can read more about this in `Packaging Python Projects `__. 7. Create the Conda package ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``esmvalcore`` package is published on the `conda-forge conda channel `__. This is done via a pull request on the `esmvalcore-feedstock repository `__. To publish a release candidate, you have to open a pull request yourself. An example for this can be found `here `__. Make sure to use the `rc branch `__ as the target branch for your pull request and follow all instructions given by the linter bot. The testing of ESMValTool will be performed with the published release candidate. For the final release, this pull request is automatically opened by a bot. An example pull request can be found `here `__. Follow the instructions by the bot to finalize the pull request. This step mostly contains updating dependencies that have been changed during the last release cycle. Once approved by the `feedstock maintainers `__ they will merge the pull request, which will in turn publish the package on conda-forge some time later. Contact the feedstock maintainers if you want to become a maintainer yourself. 8. Check the Docker images ~~~~~~~~~~~~~~~~~~~~~~~~~~ There is one main Docker container images available for ESMValCore on `Dockerhub `_: - ``esmvalgroup/esmvalcore:stable``, built from `docker/Dockerfile `_, this is a tag that is always the same as the latest released version. This image is only built by Dockerhub when a new release is created. In addition to the image mentioned above, there is an image available for every release (e.g. ``esmvalgroup/esmvalcore:v2.5.0``). When working on the Docker images, always try to follow the `best practices `__. After making the release, check that the Docker image for that release has been built correctly by 1. checking that the version tag is available on `Dockerhub`_ and the ``stable`` tag has been updated, 2. running some recipes with the ``stable`` tag Docker container, for example one recipe for Python, NCL, and R, 3. running a recipe with a Singularity container built from the ``stable`` tag. If there is a problem with the automatically built container image, you can fix the problem and build a new image locally. For example, to `build `__ and `upload `__ the container image for v2.5.0 of the tool run: .. code-block:: bash git checkout v2.5.0 git clean -x docker build --pull -t esmvalgroup/esmvalcore:v2.5.0 . -f docker/Dockerfile docker push esmvalgroup/esmvalcore:v2.5.0 (when making updates, you may want to add .post0, .post1, .. to the version number to avoid overwriting an older tag) and if it is the latest release that you are updating, also run .. code-block:: bash docker tag esmvalgroup/esmvalcore:v2.5.0 esmvalgroup/esmvalcore:stable docker push esmvalgroup/esmvalcore:stable Note that the ``docker push`` command will overwrite the existing tags on Dockerhub, but the previous container image will remain available as an untagged image.