Contribution Guideline
This document describes the way we want to contribute code to the projects of metal-stack, which are hosted on github.com/metal-stack.
The document is meant to be understood as a general guideline for contributions, but not as a burden to be placed on a developer. Use your best judgment when contributing code. Try to be as clean and precise as possible when writing code and try to make your code as maintainable and understandable as possible for other people.
Even if it should go without saying, we live in an open culture of discussion, in which everybody is welcome to participate. We treat every contribution with respect and objectiveness with the general aim of writing software of quality.
If you want, feel free to propose changes to this document in a pull request.
How Can I Contribute?
There are different approaches to suggest and contribute changes to metal-stack depending on their size.
- Tiny changes: Directly create a pull request in the corresponding repository.
- Small changes: Open a GitHub issue in the project you would like to contribute. Within the issue, your idea can be discussed.
- General feature requests: Please suggest your thoughts on the discussions page.
- More technical, impactful change requests: These would affect multiple repositories, propose bigger architectural changes or changes for end-users. In this case, consider writing a Metal Enhancement Proposal (MEP).
Please consider the following aspects when you open an issue or pull request:
- Create a meaningful description why your contribution is needed.
- Try to set appropriate labels. For example, attach the
triagelabel to your issue if you want it to be discussed in the next planning meeting. It might be useful to attend the meeting if you want to emphasize it being worked on. - For pull requests: Read the template and fill out the requested fields.
Pull Requests
Regarding pull requests there are some additional guidelines to follow:
- Create a repository fork within the context of that issue. Members of the organization may work on the repository directly without a fork, which allows building development artifacts more easily.
- Develop, document and test your contribution. Try not to solve more than one issue in a single pull request.
- Create a Draft Pull Request to the repository's main branch if you do not want to directly request a review from a code owner. It makes sense not to hold back your commits such that the community can notice there is progress going on.
- Create a meaningful description of the pull request and reference related issues if there are any. The pull request template explains what the content should include, please read it.
- Ask for merging your contribution by removing the draft marker. Repository maintainers (see Code Ownership) are notified automatically, but you can also reach out to people directly if you want a review from a specific person. You can do so by mentioning them in a comment or reaching out to them on our Slack channel.
- In case you did not hear back from us within two weeks, add the
triagelabel and participate in the next planning meeting.
Usage of Generative AI Tools
The metal-stack project generally accepts contributions that make use of generative AI tools. We believe that AI can increase productivity and improve quality when developers use it consciously. Using this technology unconsciously, however, comes with risks for the project and the community, which is why we expect contributors to respect the following aspects for AI-generated contents:
- Compliance: The contributor is responsible for the disclosed sources and ensures that it complies with the Open Source definition, copyright and license regulations of the metal-stack project.
- Communication: Comments, motivations and issues are genuinely written by humans.
- Transparency: Commits where substantial parts were generated by AI must include:
- Commit labels for the review process, like:
Generated-By: [tool name] <your commit message>. - The names of the tools that were used with AI should be included in the pull request description. For this, there is a dedicated section in the pull request template. As we usually squash commits when we merge, the
Generated-Bylabels should be kept in the final commit description.
- Commit labels for the review process, like:
- Code Understanding: We expect full understanding of the contributed code. The code must have been executed and tested in some way by the contributor. The contribution guideline's overall style and design choices must be followed.
- Quality over Quantity: It is very easy to generate a lot of code with the help of AI in a very short amount of time. By contrast, reviewing large pull requests takes exponentially longer as they grow in size. Therefore, contributions are expected to be minimal. Large changes must be discussed in issues as usual and discussed in the community.
General Objectives
This section contains language-agnostic topics that all metal-stack projects are trying to follow.
Code Ownership
As a matter of fact, there are persons in a project, which already have experience with the sources. These are defined directly in the repository's CODEOWNERS file. If you want to merge changes into the main branch, it is advisable to include code owners into the process of discussion and merging.
The responsibilities of code owners are:
- Reviewing pull requests.
- Participate and respond to issues and discussions.
- Issue refinement regarding description, type, labels and project state.
- Cleanup of stale issues.
- Take responsibility for the release integration of the artifacts. Respect the different needs of the community.
- Keep an eye that documentation is up-to-date. This includes the website repository, too.
There should always be at least two code owners for a repository.
Stale Issues
Code owners are expected to take care of the repository issues and pull requests. They decide whether they are still relevant for the project or if they can be closed.
In general, issues should not be older than two years as it is unlikely they will ever be implemented.
There can always be exceptions like long-standing umbrella issues, but if an issue receives no activity after a reasonable period of time, it should be closed and instead be re-opened. Otherwise it pollutes the planning dashboard and prevents the community from finding relevant issues.
Microservices
One major ambition of metal-stack is to follow the idea of microservices. This way, we want to achieve that we can
- adapt to changes faster than with monolithic architectures,
- be free of restrictions due to certain choices of technology,
- leverage powerful traits of cloud infrastructures (e.g. high-scalability, high-availability, ...).
Programming Languages
We are generally open to write code in any language that fits best to the function of the software. However, we encourage golang to be the main language of metal-stack as we think that it makes development faster when not establishing too many different languages in our architecture. Reason for this is that we are striving for consistent behavior of the microservices, similar to what has been described for the Twelve-Factor App (see 12 Factor). We help enforcing unified behavior by allowing a small layer of shared code for every programming language. We will refer to this shared code as "libraries" for the rest of this document.
Artifacts
Artifacts are always produced by a CI process (i.e. GitHub Actions).
Container images and OCI artifacts are published on the GitHub Container Registry of the metal-stack organization. Please consider using GitHub Actions workflows utilizing similar actions as the other repositories (e.g. build-push-action, ...)
For OCI images, we usually utilize oras for pushing the artifact to the registry.
For signing artifacts we use cosign. The private key for signing artifacts is a CI secret called COSIGN_PRIVATE_KEY.
Binary artifacts or OS images can be uploaded to images.metal-stack.io if necessary.
APIs
The preferred way to implement an API is using Connect RPC, which is based on grpc. For working with the Protobuf definitions, we utilize buf.
The metal-api does still have a Swagger-based API exposing traditional REST APIs for end-users. This API framework will become deprecated so it should not be used anymore for new projects.
Versioning
Artifacts are versioned by tagging the respective repository with a tag starting with the letter v. After the letter, there stands a valid semantic version.
Generally, we apply forward fixes and do not backport features or fixes to previous artifact releases. For certain repositories consider using pre-releases as described in the release flow.
Documentation
In order to make it easier for others to understand a repository, we document general information and usage instructions in a README.md. It must contain the purpose of the repository. Ideally, the README.md targets new users and should describe how to use it and how it can be developed. For complex development setups consider a dedicated documentation in a DEVELOPMENT.md.
Documentation should be as close to the source code as possible such that it can be easily maintained along with the pull requests. Parts of this information can be made available in the reference section of our central metal-stack.io documentation.
If the documentation spans across multiple repositories, touches architectural aspects or interplay between components, it should be contributed to the website repository. Code owners can use the requires docs update label to indicate when a change in a repository requires a general update on the website.
Language Guidelines
This chapter describes general guidelines on how to develop and contribute code for a certain programming language.
Comments
Just a few words about using comments in programming languages: Write code that is understandable without comments. There can always be exceptions to this rule, e.g. the solution is not intuitive, something is really complex, etc.
Of course, public interfaces should be documented, which often happens in the form of code comments.
Dependencies
Only use dependencies when they are really necessary. When introducing a new dependency, make sure the dependency is maintained and trustworthy.
Dependencies have to be updated regularly.
Makefile
Provide common tasks for a repository by using GNU Make even if the repository's preferred language choice includes common ways to run tasks (e.g. npm run, go generate, ...).
This creates a unified to use repositories in the metal-stack landscape. It is available on almost all Linux distributions and makes the repository easier to access for new users.
Usual tasks defined in a Makefile are artifact builds, code generation, dev environment spinup, etc.
Try to keep them as minimal as possible.
Go
Write clear, idiomatic Go code. Here are some useful links to look up what this means:
In order to unify common behavior, there are some libraries to consider using:
- metal-lib: For common microservice behavior like auditing, health checks, test helpers, ...
- v: For version information of an application.
JavaScript
Prefer TypeScript over JavaScript.
TypeScript
- Runtime and package manager is bun.
- For code formatting use prettier and add a
.prettierrc.jsonto the repository.- Activate automatic formatting on save.
- Prefer strict mode.
- Especially keep your dependencies minimal.
Bash
Try not to use bash scripts, especially not for bigger tasks. It turns out they are really hard to maintain and to understand. In sum, they must not be an integral part of a repository, meaning you should always be able to delete them without breaking substantial features of the project (including builds, prefer a Makefile).