1Maintainer / core-developer information 2======================================== 3 4 5Releasing 6--------- 7 8This section is about preparing a major release, incrementing the minor 9version, or a bug fix release incrementing the patch version. Our convention is 10that we release one or more release candidates (0.RRrcN) before releasing the 11final distributions. We follow the `PEP101 12<https://www.python.org/dev/peps/pep-0101/>`_ to indicate release candidates, 13post, and minor releases. 14 15Before a release 16................ 17 181. Update authors table: 19 20 .. prompt:: bash $ 21 22 cd build_tools; make authors; cd .. 23 24 and commit. This is only needed if the authors have changed since the last 25 release. This step is sometimes done independent of the release. This 26 updates the maintainer list and is not the contributor list for the release. 27 282. Confirm any blockers tagged for the milestone are resolved, and that other 29 issues tagged for the milestone can be postponed. 30 313. Ensure the change log and commits correspond (within reason!), and that the 32 change log is reasonably well curated. Some tools for these tasks include: 33 34 - ``maint_tools/sort_whats_new.py`` can put what's new entries into 35 sections. It's not perfect, and requires manual checking of the changes. 36 If the what's new list is well curated, it may not be necessary. 37 38 - The ``maint_tools/whats_missing.sh`` script may be used to identify pull 39 requests that were merged but likely missing from What's New. 40 414. Make sure the deprecations, FIXME and TODOs tagged for the release have 42 been taken care of. 43 44**Permissions** 45 46The release manager requires a set of permissions on top of the usual 47permissions given to maintainers, which includes: 48 49- *maintainer* role on ``scikit-learn`` projects on ``pypi.org`` and 50 ``test.pypi.org``, separately. 51- become a member of the *scikit-learn* team on conda-forge by editing the 52 ``recipe/meta.yaml`` file on 53 ``https://github.com/conda-forge/scikit-learn-feedstock`` 54 55.. _preparing_a_release_pr: 56 57Preparing a release PR 58...................... 59 60Major version release 61~~~~~~~~~~~~~~~~~~~~~ 62 63Prior to branching please do not forget to prepare a Release Highlights page as 64a runnable example and check that its HTML rendering looks correct. These 65release highlights should be linked from the ``doc/whats_new/v0.99.rst`` file 66for the new version of scikit-learn. 67 68Releasing the first RC of e.g. version `0.99.0` involves creating the release 69branch `0.99.X` directly on the main repo, where `X` really is the letter X, 70**not a placeholder**. The development for the major and minor releases of `0.99` 71should **also** happen under `0.99.X`. Each release (rc, major, or minor) is a 72tag under that branch. 73 74This is done only once, as the major and minor releases happen on the same 75branch: 76 77 .. prompt:: bash $ 78 79 # Assuming upstream is an alias for the main scikit-learn repo: 80 git fetch upstream main 81 git checkout upstream/main 82 git checkout -b 0.99.X 83 git push --set-upstream upstream 0.99.X 84 85 Again, `X` is literal here, and `99` is replaced by the release number. 86 The branches are called ``0.19.X``, ``0.20.X``, etc. 87 88In terms of including changes, the first RC ideally counts as a *feature 89freeze*. Each coming release candidate and the final release afterwards will 90include only minor documentation changes and bug fixes. Any major enhancement 91or feature should be excluded. 92 93Then you can prepare a local branch for the release itself, for instance: 94``release-0.99.0rc1``, push it to your github fork and open a PR **to the** 95`scikit-learn/0.99.X` **branch**. Copy the :ref:`release_checklist` templates 96in the description of the Pull Request to track progress. 97 98This PR will be used to push commits related to the release as explained in 99:ref:`making_a_release`. 100 101You can also create a second PR from main and targeting main to increment 102the ``__version__`` variable in `sklearn/__init__.py` to increment the dev 103version. This means while we're in the release candidate period, the latest 104stable is two versions behind the main branch, instead of one. In this PR 105targeting main you should also include a new file for the matching version 106under the ``doc/whats_new/`` folder so PRs that target the next version can 107contribute their changelog entries to this file in parallel to the release 108process. 109 110Minor version release 111~~~~~~~~~~~~~~~~~~~~~ 112 113The minor releases should include bug fixes and some relevant documentation 114changes only. Any PR resulting in a behavior change which is not a bug fix 115should be excluded. 116 117First, create a branch, **on your own fork** (to release e.g. `0.99.3`): 118 119.. prompt:: bash $ 120 121 # assuming main and upstream/main are the same 122 git checkout -b release-0.99.3 main 123 124Then, create a PR **to the** `scikit-learn/0.99.X` **branch** (not to 125main!) with all the desired changes: 126 127.. prompt:: bash $ 128 129 git rebase -i upstream/0.99.2 130 131Copy the :ref:`release_checklist` templates in the description of the Pull 132Request to track progress. 133 134Do not forget to add a commit updating ``sklearn.__version__``. 135 136It's nice to have a copy of the ``git rebase -i`` log in the PR to help others 137understand what's included. 138 139.. _making_a_release: 140 141Making a release 142................ 143 1440. Ensure that you have checked out the branch of the release PR as explained 145 in :ref:`preparing_a_release_pr` above. 146 1471. Update docs. Note that this is for the final release, not necessarily for 148 the RC releases. These changes should be made in main and cherry-picked 149 into the release branch, only before the final release. 150 151 - Edit the ``doc/whats_new/v0.99.rst`` file to add release title and list of 152 contributors. 153 You can retrieve the list of contributor names with: 154 155 :: 156 157 $ git shortlog -s 0.98.33.. | cut -f2- | sort --ignore-case | tr '\n' ';' | sed 's/;/, /g;s/, $//' | fold -s 158 159 - For major releases, link the release highlights example from the ``doc/whats_new/v0.99.rst`` file. 160 161 - Update the release date in ``whats_new.rst`` 162 163 - Edit the ``doc/templates/index.html`` to change the 'News' entry of the 164 front page (with the release month as well). 165 1662. On the branch for releasing, update the version number in 167 ``sklearn/__init__.py``, the ``__version__``. 168 169 For major releases, please add a 0 at the end: `0.99.0` instead of `0.99`. 170 171 For the first release candidate, use the `rc1` suffix on the expected final 172 release number: `0.99.0rc1`. 173 1743. Trigger the wheel builder with the ``[cd build]`` commit marker using 175 the command: 176 177 .. prompt:: bash $ 178 179 git commit --allow-empty -m "Trigger wheel builder workflow: [cd build]" 180 181 The wheel building workflow is managed by GitHub Actions and the results be browsed at: 182 https://github.com/scikit-learn/scikit-learn/actions?query=workflow%3A%22Wheel+builder%22 183 184.. note:: 185 186 Before building the wheels, make sure that the ``pyproject.toml`` file is 187 up to date and using the oldest version of ``numpy`` for each Python version 188 to avoid `ABI <https://en.wikipedia.org/wiki/Application_binary_interface>`_ 189 incompatibility issues. Moreover, a new line have to be included in the 190 ``pyproject.toml`` file for each new supported version of Python. 191 192.. note:: 193 194 The acronym CD in `[cd build]` stands for `Continuous Delivery 195 <https://en.wikipedia.org/wiki/Continuous_delivery>`_ and refers to the 196 automation used to generate the release artifacts (binary and source 197 packages). This can be seen as an extension to CI which stands for 198 `Continuous Integration 199 <https://en.wikipedia.org/wiki/Continuous_integration>`_. The CD workflow on 200 GitHub Actions is also used to automatically create nightly builds and 201 publish packages for the development branch of scikit-learn. See 202 :ref:`install_nightly_builds`. 203 2044. Once all the CD jobs have completed successfully in the PR, merge it, 205 again with the `[cd build]` marker in the commit message. This time 206 the results will be uploaded to the staging area. 207 208 You should then be able to upload the generated artifacts (.tar.gz and .whl 209 files) to https://test.pypi.org using the "Run workflow" form for the 210 following GitHub Actions workflow: 211 212 https://github.com/scikit-learn/scikit-learn/actions?query=workflow%3A%22Publish+to+Pypi%22 213 2144.1 You can test the conda-forge builds by submitting a PR to the feedstock 215 repo: https://github.com/conda-forge/scikit-learn-feedstock. If you want to 216 publish an RC release on conda-forge, the PR should target the `rc` branch 217 as opposed to the `master` branch. The two branches need to be kept sync 218 together otherwise. 219 2205. If this went fine, you can proceed with tagging. Proceed with caution. 221 Ideally, tags should be created when you're almost certain that the release 222 is ready, since adding a tag to the main repo can trigger certain automated 223 processes. 224 225 Create the tag and push it (if it's an RC, it can be ``0.xx.0rc1`` for 226 instance): 227 228 .. prompt:: bash $ 229 230 git tag -a 0.99.0 # in the 0.99.X branch 231 git push git@github.com:scikit-learn/scikit-learn.git 0.99.0 232 2336. Trigger the GitHub Actions workflow again but this time to upload the artifacts 234 to the real https://pypi.org (replace "testpypi" by "pypi" in the "Run 235 workflow" form). 236 2377. Alternatively, it's possible to collect locally the generated binary wheel 238 packages and source tarball and upload them all to PyPI by running the 239 following commands in the scikit-learn source folder (checked out at the 240 release tag): 241 242 .. prompt:: bash $ 243 244 rm -r dist 245 pip install -U wheelhouse_uploader twine 246 python setup.py fetch_artifacts 247 248 This command will download all the binary packages accumulated in the 249 `staging area on the anaconda.org hosting service 250 <https://anaconda.org/scikit-learn-wheels-staging/scikit-learn/files>`_ and 251 put them in your local `./dist` folder. 252 253 Check the content of the `./dist` folder: it should contain all the wheels 254 along with the source tarball ("scikit-learn-RRR.tar.gz"). 255 256 Make sure that you do not have developer versions or older versions of 257 the scikit-learn package in that folder. 258 259 Before uploading to pypi, you can test upload to test.pypi.org: 260 261 .. prompt:: bash $ 262 263 twine upload --verbose --repository-url https://test.pypi.org/legacy/ dist/* 264 265 Upload everything at once to https://pypi.org: 266 267 .. prompt:: bash $ 268 269 twine upload dist/* 270 2718. For major/minor (not bug-fix release), update the symlink for ``stable`` 272 and the ``latestStable`` variable in 273 https://github.com/scikit-learn/scikit-learn.github.io: 274 275 .. prompt:: bash $ 276 277 cd /tmp 278 git clone --depth 1 --no-checkout git@github.com:scikit-learn/scikit-learn.github.io.git 279 cd scikit-learn.github.io 280 echo stable > .git/info/sparse-checkout 281 git checkout main 282 rm stable 283 ln -s 0.999 stable 284 sed -i "s/latestStable = '.*/latestStable = '0.999';/" versionwarning.js 285 git add stable versionwarning.js 286 git commit -m "Update stable to point to 0.999" 287 git push origin master 288 289.. _release_checklist: 290 291Release checklist 292................. 293 294The following GitHub checklist might be helpful in a release PR:: 295 296 * [ ] update news and what's new date in release branch 297 * [ ] update news and what's new date and sklearn dev0 version in main branch 298 * [ ] check that the for the release wheels can be built successfully 299 * [ ] merge the PR with `[cd build]` commit message to upload wheels to the staging repo 300 * [ ] upload the wheels and source tarball to https://test.pypi.org 301 * [ ] create tag on the main github repo 302 * [ ] confirm bot detected at 303 https://github.com/conda-forge/scikit-learn-feedstock and wait for merge 304 * [ ] upload the wheels and source tarball to PyPI 305 * [ ] https://github.com/scikit-learn/scikit-learn/releases publish 306 * [ ] announce on mailing list and on Twitter, and LinkedIn 307 308Merging Pull Requests 309--------------------- 310 311Individual commits are squashed when a Pull Request (PR) is merged on Github. 312Before merging, 313 314- the resulting commit title can be edited if necessary. Note 315 that this will rename the PR title by default. 316- the detailed description, containing the titles of all the commits, can 317 be edited or deleted. 318- for PRs with multiple code contributors care must be taken to keep 319 the `Co-authored-by: name <name@example.com>` tags in the detailed 320 description. This will mark the PR as having `multiple co-authors 321 <https://help.github.com/en/github/committing-changes-to-your-project/creating-a-commit-with-multiple-authors>`_. 322 Whether code contributions are significanly enough to merit co-authorship is 323 left to the maintainer's discretion, same as for the "what's new" entry. 324 325 326The scikit-learn.org web site 327----------------------------- 328 329The scikit-learn web site (http://scikit-learn.org) is hosted at GitHub, 330but should rarely be updated manually by pushing to the 331https://github.com/scikit-learn/scikit-learn.github.io repository. Most 332updates can be made by pushing to master (for /dev) or a release branch 333like 0.99.X, from which Circle CI builds and uploads the documentation 334automatically. 335 336Travis Cron jobs 337---------------- 338 339From `<https://docs.travis-ci.com/user/cron-jobs>`_: Travis CI cron jobs work 340similarly to the cron utility, they run builds at regular scheduled intervals 341independently of whether any commits were pushed to the repository. Cron jobs 342always fetch the most recent commit on a particular branch and build the project 343at that state. Cron jobs can run daily, weekly or monthly, which in practice 344means up to an hour after the selected time span, and you cannot set them to run 345at a specific time. 346 347For scikit-learn, Cron jobs are used for builds that we do not want to run in 348each PR. As an example the build with the dev versions of numpy and scipy is 349run as a Cron job. Most of the time when this numpy-dev build fail, it is 350related to a numpy change and not a scikit-learn one, so it would not make sense 351to blame the PR author for the Travis failure. 352 353The definition of what gets run in the Cron job is done in the .travis.yml 354config file, exactly the same way as the other Travis jobs. We use a ``if: type 355= cron`` filter in order for the build to be run only in Cron jobs. 356 357The branch targeted by the Cron job and the frequency of the Cron job is set 358via the web UI at https://www.travis-ci.org/scikit-learn/scikit-learn/settings. 359 360Experimental features 361--------------------- 362 363The :mod:`sklearn.experimental` module was introduced in 0.21 and contains 364experimental features / estimators that are subject to change without 365deprecation cycle. 366 367To create an experimental module, you can just copy and modify the content of 368`enable_hist_gradient_boosting.py 369<https://github.com/scikit-learn/scikit-learn/blob/c9c89cfc85dd8dfefd7921c16c87327d03140a06/sklearn/experimental/enable_hist_gradient_boosting.py>`__, 370or 371`enable_iterative_imputer.py 372<https://github.com/scikit-learn/scikit-learn/blob/c9c89cfc85dd8dfefd7921c16c87327d03140a06/sklearn/experimental/enable_iterative_imputer.py>`_. 373 374.. note:: 375 376 These are permalink as in 0.24, where these estimators are still 377 experimental. They might be stable at the time of reading - hence the 378 permalink. See below for instructions on the transition from experimental 379 to stable. 380 381Note that the public import path must be to a public subpackage (like 382``sklearn/ensemble`` or ``sklearn/impute``), not just a ``.py`` module. 383Also, the (private) experimental features that are imported must be in a 384submodule/subpackage of the public subpackage, e.g. 385``sklearn/ensemble/_hist_gradient_boosting/`` or 386``sklearn/impute/_iterative.py``. This is needed so that pickles still work 387in the future when the features aren't experimental anymore. 388 389To avoid type checker (e.g. mypy) errors a direct import of experimental 390estimators should be done in the parent module, protected by the 391``if typing.TYPE_CHECKING`` check. See `sklearn/ensemble/__init__.py 392<https://github.com/scikit-learn/scikit-learn/blob/c9c89cfc85dd8dfefd7921c16c87327d03140a06/sklearn/ensemble/__init__.py>`_, 393or `sklearn/impute/__init__.py 394<https://github.com/scikit-learn/scikit-learn/blob/c9c89cfc85dd8dfefd7921c16c87327d03140a06/sklearn/impute/__init__.py>`_ 395for an example. 396 397Please also write basic tests following those in 398`test_enable_hist_gradient_boosting.py 399<https://github.com/scikit-learn/scikit-learn/blob/c9c89cfc85dd8dfefd7921c16c87327d03140a06/sklearn/experimental/tests/test_enable_hist_gradient_boosting.py>`__. 400 401 402Make sure every user-facing code you write explicitly mentions that the feature 403is experimental, and add a ``# noqa`` comment to avoid pep8-related warnings:: 404 405 # To use this experimental feature, we need to explicitly ask for it: 406 from sklearn.experimental import enable_hist_gradient_boosting # noqa 407 from sklearn.ensemble import HistGradientBoostingRegressor 408 409For the docs to render properly, please also import 410``enable_my_experimental_feature`` in ``doc/conf.py``, else sphinx won't be 411able to import the corresponding modules. Note that using ``from 412sklearn.experimental import *`` **does not work**. 413 414Note that some experimental classes / functions are not included in the 415:mod:`sklearn.experimental` module: ``sklearn.datasets.fetch_openml``. 416 417Once the feature become stable, remove all `enable_my_experimental_feature` 418in the scikit-learn code (even feature highlights etc.) and make the 419`enable_my_experimental_feature` a no-op that just raises a warning: 420`enable_hist_gradient_boosting.py 421<https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/experimental/enable_hist_gradient_boosting.py>`__. 422The file should stay there indefinitely as we don't want to break users code: 423we just incentivize them to remove that import with the warning. 424 425Also update the tests accordingly: `test_enable_hist_gradient_boosting.py 426<https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/experimental/tests/test_enable_hist_gradient_boosting.py>`__. 427