Contribution guidelines
Guide on the project's conventions and code style.
Commits
Commits should be concise and small, such that they are easy to review. Avoid at all costs including non-related changes in a commit - use git add -p
or something similar to force yourself to review the changes you are commiting, and to avoid accidentally commiting unrelated changes.
Commits should follow Conventional Commits and be written in imperative mood. As scopes, we use the names of the labels that start by B-
in the label list (e.g.: assets
, audio
). If the commit affects multiple of those areas, then pick one of the labels that start by A-
(e.g.: core
, engine
, tesseratos
). If a commit affects more than one of those, then you can ommit the scope.
If your description is too long, you can add a body to the commit message. The body should be separated from the description by a blank line.
Examples of good commit messages:
feat(core): add CUBOS_FAIL, CUBOS_UNREACHABLE and CUBOS_DEBUG_ASSERT test(core): move filesystem tests to data/fs fix(core): fix segfault when popping a sub context feat(engine): implement system for sweeping the markers docs(engine): add comments to colliders chore: replace GoogleTest submodule with doctest
Examples of bad commit messages:
fix: fix bug make it work feat(core): Add CUBOS_FAIL docs(engine): added comments to colliders
Pull Requests
Pull requests should be concise and small, and if needed, split into multiple smaller PRs so that they are easier to review. If your PR is still not finished, mark it as a draft. When working on new features, draft PRs should be created so that other contributors can have an idea of what is being worked on.
Any features added in a PR should be covered by tests and documentation, including new examples demonstrating the feature.
Documentation
We use Doxygen for documentation, which means that the documentation is mostly written in the code itself. When adding new files, classes, functions, etc, make sure to at least add a triple slash comment (///
) with a @brief
section describing what it does, otherwise Doxygen will omit it from the documentation.
Make sure to document all function parameters, template parameters and return values. Take a look at other files to get a grasp of the documentation style we use.
When changing the code, the documentation should be updated accordingly.
Plugins
Engine plugins should document which components and resources they add, which tags and settings are used, and how to use them. Take a look at the documentation of other plugins such as the renderer plugin to get an idea of how it should look like.
Every type or function that is part of the public API of a plugin should be added to its corresponding group
in the Doxygen documentation, using the @ingroup
tag.
Code Style
Casing
We use camelCase
for functions, methods, local variables and fields. Private fields are prefixed with m
(e.g. mMyField
). PascalCase
is used for class names and constants. UPPER_CASE
is used for macros. snake_case
is used for namespaces, folders and files.
Formatting
Code is formatted using clang format. Although we have an action that runs clang format on every PR, it is recommended that you run it locally before commiting your changes, to make it easier for the reviewers to read your code.
We also check the code with clang tidy, which is a static analysis tool which picks up many common mistakes and code smell. This runs on every commit you push to your branch.
Macros
Avoid using macros whenever possible - use constexpr
variables or functions instead. If you do need to use a macro to make an implementation more readable, restrict the macro to the source file where it is used. Defining macros in header files is heavily discouraged.
Namespaces
Avoid using namespace
in header files. In source files, prefer using foo::bar::X
over using namespace foo::bar
. If your code is under the namespace foo::bar
, you can use using namespace foo::bar
in the source files, to make the code more readable.
When closing a namespace the namespace name should be added as a comment. E.g.:
namespace foo { ... } // namespace foo