Repository

The git repos we are maintaining use multiple branches with a specific scope:

  • main: for developed and release code usable by the public

  • other branches are temporary feature branches

The common ``main`` branches is protected and developers must not work directly on it.

When starting a new development, you should always span a new temporary branch from the common main branch. We strongly recommend that each new feature development or bug fix gets its own branch.

When you have checked extensively the modifications made on a feature branch, you can then merge them on the common main branch. As a matter of fact, always check extensively your changes before merging them on any common branch. This merge should be made using a gitlab merge request.

After each block of code implementing a feature that has been checked, you must, without exception, commit and push.

Commits

Your commits should be frequent and atomic (never bundle lots of changes to multiple features inside a single commit). If you have made a lot of changes, you can add file changes to the commit interactively using git add -p.

Do not underestimate the value of a clear-cut, well formatted commit message. We recommend the following guidelines to be used when writing a commit message: https://chris.beams.io/posts/git-commit/

For the format of the commit message, we demand the following:

  • First line (header): commit short message (again see https://chris.beams.io/posts/git-commit/)

  • Body: details about the commit (if needed), written as complete sentences

  • Last line (if applicable): references to the issue(s) related to this commit (ex: See #1 #7 or Fix #5)

Tags

Tags are used (among other things) to indicates the commit number of a specific version of the repo. This is important to put in place once the repo is made available to the public so users and developers alike can track versions.

We use three numbers identifying a version: a.b.c

  • a: indicates major revisions (lot of changes perhaps with no backward compatibility)

  • b: indicates minor revisions (new feature introduced or a bunch of smaller ones)

  • c: indicates patch or bug-fix

Those version numbers should be at least used for the master branch, and can indicate releases. The tags indicating versions should be formatted: {a}.{b}.{c} (for example: 1.0.1)

We are using bump2version to ensure our semantic package versioning (it coherently update the version number in setup.py):

  • The release is a bugfix that only changes internal functions, then it’s a patch: bump2version patch (change from {a}.{b}.{c} to {a}.{b}.{c+1})

  • The release adds new features but don’t break backwards compatibility, then it’s a minor: bump2version minor (change from {a}.{b}.{c} to {a}.{b+1}.0)

  • The release breaks backwards compatibility but adds a lot of features, then it’s a major: bump2version major (change from {a}.{b}.{c} to {a+1}.0.0)

The current version number is always set in both .bump2version.cfg and VERSION files.

You can get the commits associated with each tag, which gives you the version number of these commits. But you can also get the version number associated with any commit in the history, by calling the following command (having checkout the commit to version):

git describe --tags --match "[0-9]*"

This command will generate a version number with the following format: LAST_TAG_NAME-NB_COMMITS-COMMIT-CHECKSUM with LAST_TAG_NAME the closest tag in the commit history, COMMIT_CHECKSUM the checksum of the current commit and NB_COMMIT the number of commits separating the commit from the tag. For example in our case, with a commit checksum “gfface8d”, 3 commits after commit tagged with version “1.2.0”, we get: 1.2.0-3-gfface8d

Changelog

A changelog file CHANGES must be maintained, detailing the changes brought about by a new revision. It is recommended you modify it along your other commits to not miss anything. Each set of changes is associated to a version number, which is associated to a tag.

We are using the following format:

...

{a}.{b}.{c+1}
-------------

- change1
  - subchange1
  ...
- change2
...


{a}.{b}.{c}
-----------
(start of the changelog)

So each new version changes are appended above the changelog.

Between two releases, new changes are added to the top without a version number as section header (as version number still need to be determined). The addition as a version number as the top section header must be done upon releasing a new version.

Package requirements for development

It is mandatory that you keep an up-to-date file requirements.txt at the root of your project directory containing the package dependencies (which you can obtain through pip freeze > requirements.txt).

In this purpose, it is best to have set a python virtual environment to not gather requirements of other projects. If you need help setting that up, see section Python environment.

Requirements for usage of the package as a normal user should be up-to-date and gathered in the setup.py file.

Makefile

For easier usability, we provide a Makefile for developers. It defines many commands and their options, the more useful ones being:

  • make lint: check all linters + mypy

  • make lint-apply: apply isort and black formatting

  • make doc: generate the documentation with sphinx

  • make test: run the package unit tests

  • make make coverage-report: generate a coverage report running unit tests

Gitlab CI/CD pipeline

This repository has an associated pipeline for continuous integration. It consists of a succession of operations that are applied on each commit and merge-request pushed on the online repository.

This pipeline runs the following jobs on every change pushed:

  • Lint: test code readability and coherence (see linters)

    • black

    • flake8

    • isort

  • Tests-integration (see this)

    • blackbox-coverage: compute coverage of blackbox tests

    • blackbox-html: export blackbox tests coverage html report

  • Build

    • doc: generate doc (see this)

When a push or merge request is made on master, the following jobs are added:

  • Tests-integration

    • install: test installation of the package works

  • Build

    • build: build package binaries and wheel

    • doc: build doc html files

  • Deploy

    • release: deploy package on repository package registry (manual job)

    • pages: deploy doc online

    • docker-base: build and deploy docker base image of the package on the repository container registry

Note

while it is a good practice to only push commits that are guaranteed to pass those tests for every branch (by running those tests locally beforehand), they are only required to pass for the common main branch.

Package structure

This package uses the following structure:

.
├── .bumpversion.cfg                   # Configuration file for bump2version (used for coherent and easy package versioning)
├── .devcontainer/devcontainer.json    # VS Code devcontainer parameters (used to build a development container through VS Code)
├── README.md                          # package readme in .md or .rst format
├── Makefile                           # contains all helpers/utilities for developers
├── CHANGES                            # changelog (TO DO)
├── requirements.txt                   # up-to-date list of python packages and versions required (obtained with `pip freeze > requirements.txt`) distributed binaries
├── .gitlab-ci.yml                     # Continuous Integration script for gitlab pipeline
├── pyproject.toml                     # Minimal configuration to build package distributed binaries
├── VERSION                            # Hold the current version number
├── src                                # folder for python sources structured for packaging
│   .
├── tests                              # folder containing tests (TO DO)
│   .
│   .
├── doc                                # documentation folder
│   .
│   ├── notebooks                      # folder containing all notebooks supplied as examples
│   └── html                           # html documentation folder
├── LICENSE                            # present package intent, license choice and authors (english)
├── LICENCE
│   ├── {complete_license_file}_EN.txt # complete license file in english
│   ├── {complete_license_file}_FR.txt # complete license file in french
│   ├── LICENCE.en                     # present package intent, license choice and authors (english)
│   └── LICENCE.fr                     # present package intent, license choice and authors (french)
│   .