Thank you for considering to contribute to Euro-Calliope. In the following we show you around in our software workshop to make your contribution as easy as possible.
If you have found a bug in Euro-Calliope or you want to propose a new feature, please feel free to do so using our issue tracker.
We welcome changes that you provide as a pull request.
If you consider doing that, you need to know two things: our code guidelines and our branching model. Our code guidelines are implemented through automatic linting (code analysis) and formatting. For both, we employ the tool Ruff. It is open-source and available as a plug-in to many IDEs. All you need is to install the plug-in for your IDE and then you should see linting problems and you will be able to format the code automatically based on our guidelines. If you want more, you can use a Git pre-commit-hook but that step is optional.
Next, let's talk about our branching model -- that is, which branches exist and what meaning they have. Do not worry, it is easy. Our branching model is a simplified version of git-flow. We are giving you a summary here that is likely sufficient for you. If you want more information, read the blog entry introducing git-flow.
We have two central and long-lived branches: main
and develop
.
The main
branch always points to the latest stable version: the latest release.
The develop
branch always points to the most recent development version.
It is ahead of main
and while we aim at keeping it clean and functional, it is less thoroughly tested and less mature than its older sibling.
Your change is developed on a feature branch (preferably in your own fork of the repository) that branches off of develop
and will eventually be merged back into develop
.
To keep up-to-date with this branch on your fork, you can pull in changes periodically: git pull upstream develop
.
In 99.9% of the cases, that's all you need to know.
In rare instances in which you need a hotfix, release, or long-lived feature branch, git-flow will provide you the flexibility you need. If you do not know what all this means, you do not need this flexibility.
ℹ️ By contributing to Euro-Calliope, e.g. through opening a pull request, you declare that your contributions are your own original work and that you have the right to license them, and you agree that your contributions are licensed according to the repository's license.
There are two types of tests: those that run on our continuous integration software (CI), and those that cannot.
The tests that are executed on and by the CI are unit tests of the functions in the scripts (./scripts/
) and in the library code (./lib/
), and tests of the configuration schema and the documentation.
All CI tests are GitHub workflows and accordingly you can find them in ./.github/workflows/
.
In addition, we have integration tests that test the models generated by Snakemake. As the generation is resource-intense, we cannot run them on CI at this point (see feature request). These tests are also fully automated and run each time the entire workflow is run, but you need to run the workflow on your local machine or your own cluster.
The following subsections show you how to run the tests and how to write your own.
Tests of models with continental and national resolution run automatically when you run the entire workflow. To run the tests of models with regional resolution too, do the following:
snakemake # builds all models and runs continental and national tests
snakemake all_tests # builds all models and runs continental, national, and regional tests
As a developer, you may want to run the entire workflow often to spot errors early. For that, you can use a minimal test configuration that takes less time to run than the default configuration.
snakemake --configfile="config/minimal.yaml" all_tests
Make sure to run this in a clean working directory.
Do not use the working directory in which you are using your normal configuration, or run snakemake clean
first.
Library code and scripts are tested automatically by our CI. You still may want to run these tests locally while developing. Here's how. First, create a test environment using mamba or conda:
mamba env create -f requirements-test.yaml --no-default-packages # or replace mamba with conda
conda activate test-eurocalliope
Then run the test suite with py.test:
py.test
All test code is in ./tests/
and all GitHub workflow definitions are in ./.github/workflows/
.
The test folder comprises tests of code in scripts (./tests/scripts/
), tests of library code (./tests/lib/
), and tests of the model and other workflow artefacts (./tests/model/
).
Script and library code tests are based on plain Pytest and therefore, if you are familiar with Pytest, they should be self-explanatory to you.
If you are unfamiliar with Pytest, we advise you to go and check out their documentation first.
Model tests are based on Pytest, too, but they require a custom Plugin and test runner through which we hook tests into the Snakemake workflow. This requires explanation.
The main reason for the custom mechanism is that we need a way to inject workflow artefacts (mainly Snakemake inputs
) into the test suite.
We do this through a custom Pytest plugin that lives within a script executed by Snakemake (./tests/model/test_runner.py
) and takes Snakemake inputs
and provides them as Pytest fixtures
.
Because fixtures are available to all tests, all tests can access Snakemake inputs
in this way, no matter where tests are defined.
This specific Pytest plugin cannot be used from the command line and therefore requires our own test runner, but this test runner is very simple: it is a small function in the same script (./tests/model/test_runner
) that calls Pytest normally but includes the plugin into the call.
If you are intending to add a test that uses existing Snakemake inputs, you can use the existing fixtures in ./tests/model/test_runner.py
.
If you need new Snakemake inputs, add them to the Snakemake rule and create a new fixture providing these inputs.
Take the existing fixtures as a starting point.
Whenever you want to publish a new release of Euro-Calliope, you need to perform several manual steps. Be aware that you can publish a release only if you are a maintainer of the GitHub repository and if you have edit access to the two Zenodo archives.
- Branch off of
develop
into arelease-vX.Y.Z
branch and apply the following changes:- Bump version to
vX.Y.Z
in the following places: - Verify consistent versions of Snakemake.
- Verify consistent versions of Calliope.
- Update the changelog and add the release date.
- Update the release date in ./CITATION.cff.
- (If necessary) Update ./LICENSE.md.
- (If necessary) Update
docs/img/spatial-scope-and-resolutions.png
by runningsnakemake -s rules/doc.smk docs/img/spatial-scope-and-resolutions.png
. Inspect the result visually. Check it in if it changed; check out the old version if it did not change. The figure will change when the spatial scope or resolution has changed.
- Bump version to
- Build the pre-builts and test everything using the
all_tests
rule. Make sure you start with a clean workflow folder: delete./build
and./data/automatic
should they exist. - Commit, open a pull request onto
develop
, and merge the release branch into bothdevelop
andmain
after successful review. - Add a
vX.Y.Z
release tag tomain
, push it, and add a release on GitHub. - Bump version on
develop
in the same places as in point 1. - Upload the pre-builts to their home on Zenodo and make sure all metadata is correct.