.. _maintenance_process: =========== Maintenance =========== Project Organization ==================== This section describes how the project is organized. Issues ------ Nilearn uses :nilearn-gh:`issues ` for tracking bugs, requesting potential features, and holding project discussions. .. _issue_labels: Labels ...... :nilearn-gh:`Labels ` are useful to quickly sort :nilearn-gh:`issues ` and easily find what you are looking for in the issue tracker. When :nilearn-gh:`creating an issue `, the user is responsible for a very basic labeling categorizing the issue: - ``Bug`` issue type for bug reports - ``Enhancement`` issue type for feature requests - ``Documentation`` issue label for documentation related questions or requests. New issues get the ``Needs Triage`` label and must be reviewed by a member of the :ref:`core_devs` who should remove the ``Needs Triage`` label and give the issue an effort, impact and priority label. The reviewer should also: - ensure that bugs can be reproduced - feature requests are within the scope of the project We try to describe the **estimated amount of work** required to solve each issue: - ``Effort: high`` The issue is likely to require a serious amount of work (more than a couple of days). - ``Effort: medium`` The issue is likely to require a decent amount of work (in between a few hours and a couple days). - ``Effort: low`` The issue is likely to require a small amount of work (less than a few hours). We also try to quantify the **estimated impact** of the proposed change on the project: - ``Impact: high`` Solving this issue will have a high impact on the project. - ``Impact: medium`` Solving this issue will have a decent impact on the project. - ``Impact: low`` Solving this issue will have a small impact on the project. Finally, we also indicate the **priority level** of the issue: - ``Priority: high`` The task is urgent and needs to be addressed as soon as possible. - ``Priority: medium`` The task is important but not urgent and should be addressed over the next few months. - ``Priority: low`` The task is not urgent and can be delayed. Some issues---particular those which are low effort and low to medium priority---can serve as good starting project for new contributors. We label these issues with the ``Good first issue`` label which can be seen as an equivalent to a "very low effort" label. Because of this, good first issues do not require a separate effort label. We have many more labels which describes in more detail a given issue. For a complete list of all issue labels that can be used to describe and their description, see `this page `_ .. _closing_policy: Closing policy .............. Usually we expect the issue's author to close the issue, but there are several possible reasons for a community member to close an issue: - The issue has been solved: kindly asked the author whether the issue can be closed. In the absence of reply, close the issue after two weeks. - The issue is a usage question: label the issue with ``Usage`` and kindly redirect the author to :neurostars:`neurostars <>`. Close the issue afterwards. - The issue has no recent activity (no messages in the last three months): ping the author to see if the issue is still relevant. In the absence of reply, label the issue with ``stalled`` and close it after 2 weeks. .. _pull request: Pull Requests ------------- We welcome pull requests from all community members, if they follow the :ref:`contribution_guidelines` inspired from scikit learn conventions. (More details on their process are available :sklearn:`here `). Deprecations ============ Use :class:`FutureWarning` for deprecations that users should know about on which they can have some control, for example by making sure that the warning message mentions what action to take to prevent the warning to be thrown. If there is no way for the user to prevent the warning to be thrown, consider using a :class:`DeprecationWarning`. Tests are run via tox using ``-W error::FutureWarning`` so that any FutureWarning thrown by a test will raise an error. To prevent this, any call that will throw a :class:`FutureWarning` must be handled with a ``pytest.warns`` context manager: .. code-block:: python with pytest.warns(FutureWarning, match="message"): ... Generating new baseline figures for tests ========================================= Sometimes, the figure or report generated by a function may unintentionally change as a side effect of changing another function or piece of code that it depends on. These tests ensure that the outputs are not accidentally changed. For each figure / report to test, an image is generated and then subtracted from an existing reference image. If the residual is larger than a user-specified tolerance, the test will fail. Failures are expected at times when the output is changed intentionally (for example when fixing a bug, adding features, bumping the python or Matplotlib version...) for a particular function. In such cases, the output needs to be manually updated and visually checked as part of the PR review process and to set a new baseline for comparison. Python ------ We use the ``pytest-mpl`` pytest plugin to run several regression tests on our Matplotlib figures. Those tests can be run with tox. .. code-block:: bash pip install tox tox run -e pytest_mpl You can set a new 'baseline' (set of reference images) by running the following with the oldest supported Python and Matplotlib: .. code-block:: bash pip install tox tox run -e pytest_mpl_generate Javascript ---------- HTML outputs (for report or some interactive figures) are tested using Javascript. This requires to have `node and npm `_ installed (see ``package.json`` to know the minimum required version). Those tests can be run with tox. .. code-block:: bash pip install tox tox run -e test_html You can set a new 'baseline' (set of reference images) by running the following: .. code-block:: bash pip install tox tox run -e test_html_generate Updating vendored dependencies ============================== Some javascript dependencies are vendored with Nilearn and need to be updated manually when the upstream source changes. ```bash tox run -e update_js ``` .. note:: This requires to have `node and npm `_ installed. Datasets ======== Several datasets are on `OSF `_ and some of those are 'maintained' by the Nilearn developers. Here is a quick description of the different OSF projects that the dev have access to: - `nilearn_data `_ Project hosting the data for: - ``fetch_atlas_allen_2011``: https://osf.io/hrcku - `Nilearn_datasets `_ Project hosting the data for - ``fetch_surf_fsaverage``: - ``fsaverage3``: https://osf.io/329dq - ``fsaverage4``: https://osf.io/28uma - ``fsaverage6``: https://osf.io/jzxyr - ``fsaverage7``: https://osf.io/svf8k - `nistats `_ Project hosting the data for: - ``fetch_localizer_first_level``: https://osf.io/2bqxn - `NiLearn's Quick Files `_ Project hosting some of the data for: - ``fetch_ds000030_urls``: https://osf.io/86xj7 - ``fetch_icbm152_2009``: https://osf.io/7pj92 - `temporary space to store dataset for nilearn example gallery `_ Project hosting the data for - ``fetch_language_localizer_demo_dataset`` ``https://osf.io/3dj2a`` (from https://osf.io/5dr8p/overview) acts as fall-back URL in case ``https://osf.io/nh987`` (from https://osf.io/k4jp8/overview) fails - `nilearn_data_backup_archive `_ This is an old project used for back up Nilearn's data. .. TODO `Allen and MIALAB ICA atlas 2011 `_ Unrelated project under the Nilearn OSF user account .. admonition:: Important If you need to update certain files, do NOT remove any old files as this may break some older versions of Nilearn that still use that URL. Add new files and mention the version in their filename. How to make a release? ====================== This section describes how to make a new release of Nilearn. It is targeted to the specific case of Nilearn although it contains generic steps for packaging and distributing projects. More detailed information can be found on `packaging.python.org `_. The packaging specification is contained in `pyproject.toml `_. We use ``hatchling`` and ``hatch-vcs`` as described in these `guidelines `_ to build the sdist, wheel, and extract version number from the git tag. We assume that we are in a clean state where all the Pull Requests (PR) that we wish to include in the new release have been merged. Pre-release ----------- If you are doing a `pre-release `_, that users can install with the prerelease flag (``pip install --prerelease nilearn``), then the release protocol is simplified and only consists of: - adding a git tag and updating the upstream repository .. code-block:: bash git checkout main git pull upstream main git tag X.Y.ZrcN git push upstream --tags Use the ``rcN`` (release candidate) in the version tag, with ``N`` starting at 0 and incrementing with each new release candidate for a specific version. - :ref:`building and uploading the distributions to Pypi ` - doing a :ref:`Github release` Prepare code for the release ---------------------------- The repository should be checked and updated in preparation for the release. One thing that **must** be done before the release is made is to update ``deprecated``, ``versionchanged`` and ``versionadded`` directives from the current ``[X.Y.Z].dev`` tag to the new version number. These directives are added in a function's docstring to indicate the version number, when, say, a new parameter is added or deprecated. For example, if a parameter ``param2`` was added in version ``X.Y.Z``, the docstring should be updated to: .. code-block:: python def my_function(param1, param2): """ Parameters ---------- param1 : type Description of param1. param2 : type Description of param2. .. nilearn_versionadded:: X.Y.Z Returns ------- output : type Description of the output. """ ... Additionally, make sure all deprecations that are supposed to be removed with this new version have been addressed. If this new release comes with dependency version bumps (Python, Numpy...), make sure to implement and test these changes beforehand. Ideally, these would have been done before such as to update the code base if necessary. Finally, make sure the documentation can be built correctly. Prepare the documentation for the release ----------------------------------------- Check illustrations ................... In several places the user guide relies on the code examples and the figures they generate. If the examples are modified, and an expected figure is not created anymore or the order of the generated figures is changed, this may silently (without causing warnings or errors) "break" the documentation. It is not possible to list all the places to check, but care should be taken that at least the following have not been affected: - ``.rst`` files containing the string ``image:: ../auto_examples``, - the tables in the :ref:`plotting` section, - ``literalinclude`` sphinx-directives with a ``:start-after:`` - ... Update links ............ Update the links for the new version of the documentation in ``doc/versions.rst``. For example: .. code-block:: rst Web-based documentation is available for versions listed below: * `Nilearn latest - dev documentation `_ * `Nilearn latest - stable documentation `_ * `Nilearn X.Y.Z documentation `_ Update atlas figures .................... The :ref:`datasets_ref ` has tables with figures listing all the atlases that Nilearn provides. Run the script ``doc/make_atlas_table.py`` commit the new output to update the tables. Prepare the release ------------------- Switch to a new branch locally: .. code-block:: bash git checkout -b REL-X.Y.Z First we need to prepare the release by updating the file ``nilearn/doc/changes/latest.rst`` to make sure all the new features, enhancements, and bug fixes are included in their respective sections. Then we need to make sure that all the entries in each section of the changelog in ``nilearn/doc/changes/latest.rst``: - have a label, - are sorted by their "label" alphabetically - and are followed by an empty line. For example:: - :bdg-success:`API` ... - :bdg-dark:`Code` ... - :bdg-info:`Plotting` ... We also need to write a "Highlights" section promoting the most important additions that come with this new release. Finally, we need to change the title from ``Version X.Y.Z.dev`` to ``Version X.Y.Z``: .. code-block:: RST .. currentmodule:: nilearn Version X.Y.Z ============= **Released MONTH YEAR** HIGHLIGHTS ---------- - Nilearn now includes functionality A - ... We must also ensure that every entry in ``nilearn/doc/changes/latest.rst`` starts with a "badge" (see the :ref:`changelog` section). Once we have made all the necessary changes to ``nilearn/doc/changes/latest.rst``, we should rename it into ``nilearn/doc/changes/X.Y.Z.rst``, where ``X.Y.Z`` is the corresponding version number. We then need to update ``nilearn/doc/changes/whats_new.rst`` and replace: .. code-block:: RST .. _latest: .. include:: latest.rst By: .. code-block:: RST .. _vx.y.z: .. include:: X.Y.Z.rst Add these changes and submit a PR: .. code:: bash git add doc/changes/ git commit --message "REL X.Y.Z" git push origin REL-X.Y.Z Once the PR has been reviewed and merged, pull from master and tag the merge commit: .. code:: bash git checkout main git pull upstream main git tag X.Y.Z git push upstream --tags .. note:: When building the distribution as described below, ``hatch-vcs``, defined in ``pyproject.toml``, extracts the version number using this tag and writes it to a ``_version.py`` file. .. _build_distribution: Build the distributions and upload them to Pypi ----------------------------------------------- First of all we should make sure we don't include files that shouldn't be present: .. code-block:: bash git checkout X.Y.Z If the workspace contains a ``dist`` folder, make sure to clean it: .. code-block:: bash rm -r dist In order to build the binary wheel files, we need to install `build `_: .. code-block:: bash pip install build And, in order to upload to ``Pypi``, we will use `twine `_ that you can also install with ``pip``: .. code-block:: bash pip install twine Build the source and binary distributions: .. code-block:: bash python -m build This should add two files to the ``dist`` subfolder: - one for the source distribution that should look like ``PACKAGENAME-VERSION.tar.gz`` - one for the built distribution that should look like ``PACKAGENAME-PACKAGEVERSION-PYTHONVERSION-PYTHONCVERSION-PLATFORM.whl`` This will also update ``_version.py``. Optionally, we can run some basic checks with ``twine``: .. code-block:: bash twine check dist/* We are now ready to upload to ``Pypi``. Note that you will need to have an `account on Pypi `_, and be added to the maintainers of `Nilearn `_. If you satisfy these conditions, you should be able to run: .. code-block:: bash twine upload dist/* Once the upload is completed, make sure everything looks good on `Pypi `_. Otherwise you will probably have to fix the issue and start over a new release with the patch number incremented. .. _Github release: Github release -------------- At this point, we need to upload the binaries to GitHub and link them to the tag. To do so, go to the :nilearn-gh:`Nilearn GitHub page ` under the "Releases" tab, and edit the ``X.Y.Z`` tag by providing a description, and upload the distributions we just created (you can just drag and drop the files). Build of stable docs -------------------- Once the new tagged github release is made following the step above, the Github Actions workflow ``release-docs.yml`` will be triggered automatically to build the stable docs and push them to our github pages repository ``nilearn/nilearn.github.io``. The workflow can also be triggered manually from the Actions tab. Build and deploy the documentation manually ------------------------------------------- .. note:: This step is now automated as described above. If there is a need to run it manually please follow the instructions below. Before building the documentation, make sure that the following LaTeX dependencies are installed on your system: - `dvipng `_ - `texlive-latex-base `_ - `texlive-latex-extra `_ You can check if each package is installed by using ``command -v `` as in: .. code-block:: bash command -v dvipng If the package is installed, then the path to its location on your system will be returned. Otherwise, you can install using your system's package manager or from source, for example: .. code-block:: bash wget https://mirrors.ctan.org/dviware/dvipng.zip unzip dvipng.zip cd dvipng ./configure make make install See available linux distributions of texlive-latex-base and texlive-latex-extra: - https://pkgs.org/search/?q=texlive-latex-base - https://pkgs.org/search/?q=texlive-latex-extra We now need to update the documentation. We let tox handle creating virtual env and install dependencies. .. warning:: The doc build is done with the minimum python version supported by Nilearn. .. code-block:: bash pip install tox tox run --colored yes --list-dependencies -e doc -- html export DEPLOY_TYPE="stable" export COMMIT_SHA=$(git rev-parse HEAD) bash ./build_tools/github/deploy_doc.sh This will build the documentation (beware, this is time consuming...) and push it to the `GitHub pages repo `_. Post-release ------------ At this point, the release has been made. We also need to create a new file ``doc/changes/latest.rst`` with a title and the usual ``New``, ``Enhancements``, ``Bug Fixes``, and ``Changes`` sections for the version currently under development: .. code-block:: RST .. currentmodule:: nilearn Version X.Y.Z+1.dev ==================== .. Each changelog entry should begin with one of the following badges: - :bdg-primary:`Doc` - :bdg-secondary:`Maint` - :bdg-success:`API` - :bdg-info:`Plotting` - :bdg-warning:`Test` - :bdg-danger:`Deprecation` - :bdg-dark:`Code` NEW --- Fixes ----- Enhancements ------------ Changes ------- Finally, we need to include this new file in ``doc/changes/whats_new.rst``: .. code-block:: RST .. _latest: .. include:: latest.rst