FSL project management
This document describes development and release workflows for individual FSL projects - the processes used for FSL releases are described separately.
All FSL projects and dependencies are released and published as conda packages, either in the internally managed FMRIB conda channels, or on https://anaconda.org, via conda-forge
.
Project and recipe repositories
Every FSL project comprises two git repositories1:
-
The project repository contains the project source code/resources, and is typically hosted at
https://git.fmrib.ox.ac.uk/fsl/<project>
2. -
The recipe repository contains a conda recipe for the project, and is hosted at
https://git.fmrib.ox.ac.uk/fsl/conda/fsl-<project>
3.
Activity on the project repository proceeds independently of activity on the recipe repository. The recipe repository only needs to be updated when the project developer wishes to release a new version.
1A small number of FSL projects have more than one recipe repository associated with them - for example, the fsl/fdt
project has two recipes - the fsl/conda/fsl-fdt
recipe provides CPU executables, and the fsl/conda/fsl-fdt-cuda
recipe provides GPU/CUDA executables.
2Most, but not all, FSL projects are hosted in the FMRIB GitLab fsl/
group. Some projects are hosted under the username of the developer (e.g. matteob/eddy_qc
). Some FSL projects and dependencies are hosted externally, such as MSM and oxford_asl. The conda recipes for these projects are, however, all hosted internally in the fsl/conda/
GitLab group.
3All FSL conda recipes are hosted in the fsl/conda/
GitLab group, with the sole exception of FSL projects which are published to conda-forge
(e.g. fsleyes
).
FSL project/conda package naming conventions
FSL conda package names must follow the conda package naming conventions, and be comprised solely of lowercase alpha characters, numeric digits, underscores, hyphens, or dots.
Furthermore, all FSL conda packages are prefixed with fsl-
. An FSL project with name <project>
will have a corresponding conda package name of fsl-<project>
. For FSL projects with a name that begins with fsl
(e.g. fslvbm
, fsl_deface
), the leading fsl
will be dropped in the construction of the corresponding conda-package name. For example:
FSL project name | Conda package name |
---|---|
avwutils |
fsl-avwutils |
fslvbm |
fsl-vbm |
fsl_deface |
fsl-deface |
fsl-mrs |
fsl-mrs |
NewNifti |
fsl-newnifti |
FSL project versioning scheme
FSL projects are released as conda packages, and therefore must adhere to conda package versioning conventions, described at https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/pkg-specs.html#version-ordering.
FSL projects (and hence their conda packages) follow a versioning scheme whereby each version comprises sequentially increasing numbers followed by periods. There are no more requirements beyond this, but the use of semantic versioning is encouraged.
If you are developing a project with a programming or command-line interface, a responsible strategy for managing releases is to use the version number to denote changes to the interface (for example, by using semantic versioning), and to use deprecation warnings to warn users of impending changes to the interface.
Having said this, many core FSL projects (e.g. miscmaths
, newimage
, etc) do not strictly follow the semantic versioning scheme, but instead use a versioning scheme of the form:
where YYMM
is the year and month of release (e.g. 2101
for January 2021), and B
is an incremental release number, starting at 0
.
The YYMM
component should be considered a major release number - it should be updated when breaking changes are introduced into the project. For minor changes and bug-fixes, the YYMM
component should not be changed.
The B
component should be incremented for backwards-compatible changes, such as bug fixes or new features, which do not break compatibility with the previous version.
See also the section below on development releases.
ABI/API compatibility
Following a consistent versioning scheme is important for developers of projects which provide an Application Programming Interface (API), such as an importable Python package, and in particular for C/C++ projects which provide compiled shared libraries.
Most core C/C++ FSL projects follow the YYMM.B
versioning scheme described above, and are versioned such that API/ABI compatibility is guaranteed for all releases within each YYMM
series. Some core FSL projects follow a conventional major.minor.patch
versioning scheme, and are versioned such that API/ABI compatibility is guaranteed for each major
release.
For C/C++ library projects, whenever a function definition or data structure (e.g. class or struct) changes, all users of that library must be recompiled. The compiled representation of the functions and data structures provided by a library are referred to as its Appilcation Binary Interface (ABI), and the problem of ensuring that a new version of a library will work with existing binary executables is referred to as ABI compatibility.
A new version of a library which preserves ABI compatibility with older versions can be used by existing executables and libraries which depend on that library. In contrast, when the ABI of a library changes, all projects which depend on that library must be re-built and re-released. Therefore, developers should take care when making changes to existing libraries, and should strive to preserve ABI compatibility in new releases wherever possible.
The conda package for a software library can encode its specific ABI compatibility guarantees in such a way that dependant packages of the library will be automatically pinned to the specific library version that the dependant package was built against. This is further described in the page on FSL conda package recipes.
Contributing to a FSL project
No restrictions are placed on the ways in which development of a particular FSL project takes place. Developers are free to manage their project in any way they wish.
However, contribution to core FSL projects (avwutils
, newimage
, etc) follow a merge request and review process, and it is recommended that developers follow a similar process for their own projects.
- The
master
ormain
branch of the project repository should be considered stable and ready to release at any time. - All development should occur on a separate branch within the project repository, or personal fork of the project repository.
- All changes to the
master
/main
branch should take place through GitLab merge requests (MRs). - When a MR is opened, it is reviewed, approved, and merged into the
master
/main
branch by the project maintainer, possibly after any requested changes to the MR have been made.
Releasing a new version of a FSL project
A new versions of a FSL project is denoted by a new tag being added to the project repository. Tag names must follow the FSL project versioning scheme scheme outlined above.
When a new tag is added to a FSL project repository, the corresponding recipe repository is updated, and a new conda package built and published to the public FSL conda channel. Specifically, this takes place as follows:
-
The project maintainer creates a new tag on the project repository. The tag must be the version number of the new release.
-
Creation of a new tag will result in a merge request (MR) being automatically opened on the recipe repository, in which the version number is updated, and the package build number potentially reset to 0. If additional updates need to be made to the recipe repository (e.g. new entry points added to
post-link.sh
/pre-unlink.sh
), the maintainer can make these changes on the same MR branch. -
A test build will take place on the open MR branch. When this test build has succeeded, the project maintainer may merge the MR into the recipe repository. If the test build fails, the maintainer must resolve the problem on either the project or recipe repository and, if necessary, tag a new version of the project4.
-
When MR is merged into the recipe repository, a new build will be started. Once this build has completed, the project maintainer may then deploy the built packages to the public FSL conda channel, by running the
deploy-all-packages
CI job on the build pipeline. -
The new version can then be added to the next FSL release by updating the FSL release manifest at the [
fsl/conda/manifest
(https://git.fmrib.ox.ac.uk/fsl/conda/manifest/) repository (refer to the page on FSL releases.
4When the build for a new version fails, and additional changes need to be made to the project repository, creating a new tag is preferable to deleting and re-creating an existing tag.
For projects which are included in FSL, but developed externally (e.g. truenet), the recipe repository is manually updated on an as-needed basis.
Note: Some FSL projects are not included in public FSL releases, and are only intended to be installed internally. The conda recipe repository for such a project can be configured so that both stable and development packages are instead published to the internal FSL conda channel - see the FSL build system documentation for more details.
Development releases
As described above, every time a new tag is added to a project repository, a stable package is built and uploaded to the public FSL conda channel.
In addition to these stable releases, developers have the option to publish development, or pre-release packages to a separate development conda channel. This feature may be used by developers to make pre-release versions of their tools available to other developers or advanced users for testing, evaluation and feedback. Development packages are published to the FSL conda development channel, currently at https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/development/.
Warning
The development channel is only intended to be used for testing. It is periodically cleared, so do not rely on your development packages being available for long periods of time.
Building a development package
-
On the project repository (e.g.
fsl/eddy
), start thetrigger-devrelease-package-build
CI job on the commit you want to build:a) Open the CI / CD pipelines page (e.g. by clicking on the Rocket button on the left sidebar).
b) Identify the pipeline associated with the commit that you want to build.
c) Underneath the Stages column, find the
trigger-devrelease-package-build
job, and start it by clicking the Play button. -
This will trigger a new pipeline on the recipe repository/repositories (e.g.
fsl/conda/fsl-eddy
andfsl/conda/fsl-eddy-cuda
). A conda package will be built for all platforms, and unit tests will be run, if any tests have been configured for the project. You can monitor the progress of the builds via the CI / CD pipelines page on the recipe repositiory. -
Wait for the build to complete and then, if you are happy, start the
deploy-all-conda-packages
job. This will result in the built packages being published to the FSL conda development channel.
Installing a development package
To install and use a development package, the best option is to create a separate conda environment, isolated from your main FSL installation. You can do this with a command such as:
$FSLDIR/bin/micromamba create \
--override-channels \
-c https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/development/ \
-c https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/public/ \
-c conda-forge \
-p <path-to-dev-env> \
<names-of-packages-to-install>
This command will create a new conda environment located in your file system at <path-to-dev-env>
, containing all FSL packages (and their dependencies) that you specified. Development versions of each package will be installed if they are available, otherwise stable versions will be installed.
Once the environment has been created, you can configure your current shell environment to use it with these commands5:
source ${FSLDIR}/bin/activate <path-to-dev-env>
export FSLDIR=${CONDA_PREFIX}
source ${FSLDIR}/etc/fslconf/fsl.sh
Then you will be able to use development versions of the packages that you installed.
5Note that your default shell profile will not be modified - you will need to repeat these commands for each new shell that you open, when you want to use the development packages that you have installed.
Development release versioning
Stable FSL packages are versioned as described in the FSL project versioning scheme section, above. Development FSL packages are versioned slightly differently, to ensure a sensible ordering of version numbers across both stable and development packages. The version string for a development package adheres to the following structure:
<last_stable_tag>.<time>.dev0[+<commit>]
where:
<last_stable_tag>
is the version/tag for the most recent stable release.<time>
is the time (YYYYMMDDHHMM
) that the development package was built.<commit>
is the first 7 characters of the git commit hash that the development package was built from. This may be omitted for externally hosted projects.
For example, if the latest stable release for the fsl/base
project is 2106.1
, and a new commit, with hash ac28d14
, is subsequently pushed to the fsl/base
master
branch at 14:45 on the 8th June 2021, the resulting development package will be assigned the version string 2106.1.202106081445.dev0+ac28d14
.
This convention ensures that development packages which are built after the most recent stable package will be given higher priority, and will be installed in preference to the stable package. However, because development packages are published to a separate channel, they won't be installed as part of a standard FSL installation - users must "opt-in" by adding the development channel to their conda configuration.
Maintenance releases
Stable packages for a given project are typically built and published from a branch on the recipe repository named master
or main
. This branch should contain a build recipe for the latest available version of the project. However it is possible to publish maintenance releases for an older version of the project, if the need arises. This can be done by creating a branch on the recipe repository named maint/<release-series>
, where <release-series>
contains the version string prefix of the maintenance release series.
For example, imagine the following scenario:
- Versions
3.1.0
and3.2.0
of a package have already been published. - The
master
branch of the recipe repository is configured to build version3.2.0
. - A bug is found, but an important user is unable to upgrade to version
3.2.0
for some reason. So the bug fix needs to be applied to both the3.1
and3.2
series, and new versions3.1.1
and3.2.1
need to be released.
This can be achieved like so:
1. Create a new branch on the recipe repository called maint/3.1
, and adjust the recipe on that branch to build version 3.1.1
.
2. Update the master
branch on the recipe repository to build version 3.2.1
.
3. Publish the built packages from both branches.
Note that packages cannot be published from branches with any name other
than main
, master
, or maint/<release-series>
Private/internal packages
By default, all built conda packages are deployed to the public FSL conda channel, and made publicly available to the world. Certain packages may be intended for private/internal use only, and can instead be deployed to an internal conda channel, to which access is restricted by requiring login credentials. Instructions on how to publish a package to the internal channel can be found on the FSL build system page.