Skip to content

Contribution guidelines

Repository structure

This repository functions as a "monorepo", i.e. one where the top-level package (SpeciesDistributionToolkit.jl) and its components packages reside. The documentation for all packages is centralized in docs, and then each package has its code, unit tests, and Project.toml file in its own sub-folder. As a rule, we try to minimize the situations where a component package depends on another component package – currently, only Fauxcurrences has direct dependences on other component packages. Code that is meant to facilitate the integration of multiple packages lives in SpeciesDistributionToolkit.jl.

If some of the code in SpeciesDistributionToolkit.jl becomes too large, it can branched of to another component package. Note that because we re-export all of the component packages, this can be done without affecting existing code.

How to contribute

Discussions

There is a discussion board where you can talk about the package(s). Useful contributions there are feature ideas, use cases, and clarifications to the documentation.

Issues

Everything that doesn't feel right as a discussion can be opened as an issue. Issues are tracked in a central project, which is used internally to prioritize the work. We have a tag system in place to sort issues in broad categories, based on what they target, the type of work required, the amount of effort needed, and the overall priority.

Issues are a good starting point (in fact, essentially a pre-requisite) to opening a pull request, as explained in the name paragraph.

Working on the code

It is advised to not fork this repository to make a contribution – instead, reach out to @tpoisot and ask for access to the repo; this will make it easier for other contributors to checkout your branch and contribute to it during the pull request process. Typically, you will be added to the repo when opening an issue or a discussion that you have indicated you would be willing to work on.

It is advised to open a pull request as soon as possible (typically upon the first commit), so that the link to the preview documentation will be generated, and the tests can start running. Each pull request is resulting in a new documentation build, which takes a lot of time as the vignettes are using almost all of the package(s) functionalities.

Documentation

New functionalities should have an entry in the howto or the tutorial folder, as well as be listed in the sidebar in config.mts. The files in these sections are all .jl files, which will be converted to markdown using the Literate package.

New features must come with either a new vignette or a modification to an existing one. New vignettes must be listed in the docs/src/.vitepress/config.mts file; specifically, they must be in the "sidebar" array, grouped together with the other vignettes in the section.

It is fine to use using Revise in the documentation scripts, this line will be removed at build time.

Tables should be generated with pretty_table from the PrettyTables package, using backend = :markdown, somewhere in the keywords.

Figures should be generated with CairoMakie – a configuration line with the correct format and DPI will be added automatically.

All figures must be organized in the following way:

julia
#figure Short one-line summary
f = Figure()
# ...
current_figure() #hide

This will be modified during the build to save the figure as a .png file with a unique name. The one-line description will become the mouseover/alt text for the figure, and the code will be hidden in a Details box in order to not make the tutorials and vignettes too long.

You do not need to set a random seed in the files, this will be done for all vignettes at build time.

Repository conventions

Naming of branches

Branches are named with the following scheme: <package>/<type>/<description>

The <package> entry specifies which package is covered by the changes (packages names are lowercase and we omit the .jl extension). For branches that cover the top level package, the abbreviation sdt (for SpeciesDistributionToolkit) is acceptable. For branches that target the documentation, the prefix doc should be used.

The <type> entry specifies what the branch does, and can be one of feat (new feature), refactor (changes in the internal code), bug (for longer work on a bug), or hotfix (for something that's gotta be merged soon. If needed, the chore or misc types can also be used.

Finally, the <description> suffix is a short (a few characters) description of what the branch does.

For example, gbif/feat/map-api-interface is an appropriate name for a branch that targets the GBIF component, adds a new feature, specifically about the map API interface.

Do not reference an issue number in the branch name – this can be done in the issue itself on github. The branch name must convey more context than the issue number can.

Commit conventions

We use a variant of [conventional commits][convcom] for the commits. Specifically, in addition to the fix and feat actions, we also use semver (for changes to the versions of packages, following [semantic versioning][semver]), compat (for compatibilies changes in the Julia [package management][pkg]), dependencies (for changes in requirements), doc (for documentation), and test (for unit testing).

As a reference, this table summarizes what type of commit may go with each prefix:

PrefixExplanation
fixSolves a bug / closes a PR (bug also accepted)
featAdds a new feature
semverCommit that will be tagged in a new release – this should contain a change in Project.toml
depChanges in Project.toml to add or drop a dependency
compatChanges in Project.toml to change the compatibility entry
ciActs on github actions / workflows
docChanges or adds documentation, including docstrings, and possibly comments
perfImproves the performance of the code
testAdds (or fixes) unit tests
styleApplies the formatter without modifying the content
refactorChanges the internals of a function, or changes to methods that are not exported
choreGeneral housekeeping
extDealing with packages extensions

[convcom]: https://www.conventionalcommits.org/en/v1.0.0/#summary [semver]: https://semver.org/ [pkg]: https://pkgdocs.julialang.org/v1/compatibility/

As much as possible, we try to qualify the action by specifying which component package is targeted by the commit (this might be apparent from the branch name, but especially when doing work in branches that start with doc or sdt, there may be changes in more than one package. For example, a commit that modifies the internals of SimpleSDMLayers would start with refactor(layers):.

Note that the name of component packages are lowercase, and that abbreviations are encouraged as they make the commits substantially shorter. Specifically, Phylopic.jl is phylopic, SpeciesDistributionToolkit.jl is sdt, GBIF.jl is gbif, PseudoAbsences.jl is pseudo, SimpleSDMLayers.jl is layers, OccurrencesInterface.jl is occ, Fauxcurrences.jl is faux, SDeMo.jl is demo, SimpleSDMDatasets.jl is datasets, and SimpleSDMPolygons.jl is poly.

In case of breaking changes, the commit prefix must be followed by !. This is not limited to commits with the semver prefix, but is meant to be used in the specific commit that introduces breaking changes. For example, a new feature in GBIF that would require to re-write all code would have the prefix feat(gbif)!: (and be followed by a semver commit to reflect the new version). There should never be a case outside of next major release where breaking changes are required. A rare example of a "breaking" change that is allowed is when changing the julia compat entry when a new LTS is released.

In case of an incomplete commit (e.g. the code is only partly finished), the commit prefix must be followed by ?. This is useful when leaving work unfinished at the end of a session. For example, a commit with an incomplete SimpleSDMDatasets.jl vignette can start with doc(datasets)?:.

The commit message is on the same line as the commit prefix, and is (ideally) a short sentence in the imperative. The next line in the body of the message, if required, can be used to mention linked issues or close them. Additional information about the commit is given after the links to issues.

Pull requests and merging

The commits in a pull request must be squashed before merging, and the list of commit messages will be kept in the body of the closing commit. The merge commit may not follow the commit convention, and it is acceptable to use the title of the pull request in its place. The branches are automatically deleted when a pull request is merged.

The commits that result from pulling/rebasing/conflicts operations may not to follow the commit naming convention, especially when done in branches that are not main.

Changes in a single pull request should never affect more than a single package. Semantic versioning allows rapid releases, and the changes must always be limited to a single package.

Releases

Releases are handled by @tpoisot - we use the Julia Registrator bot to create new releases. Ideally, the release process is: merging a PR in main, confirming that the unit tests pass and the documentation build, and then commenting on the commit with @JuliaRegistrator register(), adding subdir="<PKGNAME>" when the release is about a sub-package.