Skip to main content

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 to medium-sized changes: Open a GitHub issue for the project to which you would like to contribute. Your idea can then be discussed within the issue. The pull request will reference and close this issue.
  • Big changes: These would affect multiple repositories and propose significant architectural changes or changes to the project. In this case, consider writing a Metal Enhancement Proposal (MEP).
  • General feature requests: Please suggest your thoughts and ideas on the discussions page.

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-By labels should be kept in the final commit description.
  • 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.

Pull Requests

Please consider the following aspects when you open an issue or pull request:

  1. Create a meaningful description why your contribution is needed.
  2. Try to set appropriate labels. For example, attach the triage label 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.

Regarding pull requests there are some additional guidelines to follow:

  1. 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.
  2. Develop, document and test your contribution. Try not to solve more than one issue in a single pull request.
  3. 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.
  4. 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.
  5. 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.
  6. In case you did not hear back from us within two weeks, add the triage label and participate in the next planning meeting.

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:

  1. Reviewing pull requests.
  2. Participate and respond to issues and discussions.
  3. Issue refinement regarding description, type, labels and project state.
  4. Cleanup of stale issues.
  5. Take responsibility for the release integration of the artifacts. Respect the different needs of the community.
  6. 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.

General Objectives

This section contains language-agnostic topics that all metal-stack projects are trying to follow.

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 experience for using repositories in the metal-stack landscape. It is available on nearly all Linux distributions and provides newcomers with easy access to repositories.

Tasks that are usually contained in a Makefile are artifact builds, code generation, dev environment spinup, etc.

Try to keep the Makefile 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

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).