-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1198 from DirectXMan12/docs/common-versioning
📖 Update versioning to reference common guidelines
- Loading branch information
Showing
1 changed file
with
6 additions
and
278 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,282 +1,10 @@ | ||
# Versioning and Branching in controller-runtime | ||
|
||
*NB*: this also applies to controller-tools. | ||
We follow the [common KubeBuilder versioning guidelines][guidelines], and | ||
use the corresponding tooling. | ||
|
||
## TL;DR: | ||
For the purposes of the aforementioned guidelines, controller-runtime | ||
counts as a "library project", but otherwise follows the guidelines | ||
exactly. | ||
|
||
### Users | ||
|
||
- We follow [Semantic Versioning (semver)](https://semver.org) | ||
- Use releases with your dependency management to ensure that you get | ||
compatible code | ||
- The master branch contains all the latest code, some of which may break | ||
compatibility (so "normal" `go get` is not recommended) | ||
|
||
### Contributors | ||
|
||
- All code PR must be labeled with :bug: (patch fixes), :sparkles: | ||
(backwards-compatible features), or :warning: (breaking changes) | ||
|
||
- Breaking changes will find their way into the next major release, other | ||
changes will go into an semi-immediate patch or minor release | ||
|
||
- Please *try* to avoid breaking changes when you can. They make users | ||
face difficult decisions ("when do I go through the pain of | ||
upgrading?"), and make life hard for maintainers and contributors | ||
(dealing with differences on stable branches). | ||
|
||
### Mantainers | ||
|
||
Don't be lazy, read the rest of this doc :-) | ||
|
||
## Overview | ||
|
||
controller-runtime (and friends) follow [Semantic | ||
Versioning](https://semver.org). I'd recommend reading the aforementioned | ||
link if you're not familiar, but essentially, for any given release X.Y.Z: | ||
|
||
- an X (*major*) release indicates a set of backwards-compatible code. | ||
Changing X means there's a breaking change. | ||
|
||
- a Y (*minor*) release indicates a minimum feature set. Changing Y means | ||
the addition of a backwards-compatible feature. | ||
|
||
- a Z (*patch*) release indicates minimum set of bugfixes. Changing | ||
Z means a backwards-compatible change that doesn't add functionality. | ||
|
||
*NB*: If the major release is `0`, any minor release may contain breaking | ||
changes. | ||
|
||
These guarantees extend to all code exposed in public APIs of | ||
controller-runtime. This includes code both in controller-runtime itself, | ||
*plus types from dependencies in public APIs*. Types and functions not in | ||
public APIs are not considered part of the guarantee. | ||
|
||
In order to easily maintain the guarantees, we have a couple of processes | ||
that we follow. | ||
|
||
## Branches | ||
|
||
controller-runtime contains two types of branches: the *master* branch and | ||
*release-X* branches. | ||
|
||
The *master* branch is where development happens. All the latest and | ||
greatest code, including breaking changes, happens on master. | ||
|
||
The *release-X* branches contain stable, backwards compatible code. Every | ||
major (X) release, a new such branch is created. It is from these | ||
branches that minor and patch releases are tagged. If some cases, it may | ||
be necessary open PRs for bugfixes directly against stable branches, but | ||
this should generally not be the case. | ||
|
||
The maintainers are responsible for updating the contents of this branch; | ||
generally, this is done just before a release using release tooling that | ||
filters and checks for changes tagged as breaking (see below). | ||
|
||
### Tooling | ||
|
||
Tooling for releases lives in the [kubebuilder-release-tools | ||
repository][rel-tools]. | ||
|
||
* `go run sigs.k8s.io/kubebuilder-release-tools/notes` from a `release-X` | ||
(or `release-0.Y`) branch will generate release notes based on the emoji | ||
described below. | ||
|
||
You can generally paste the stdout output directly into the release, | ||
unless the tool mentions needing manual edits. | ||
|
||
* the [GitHub actions workflow][actions-wf] in this repo will verify PRs | ||
using the verifier action from the [release-tools][rel-tools] mentioned | ||
above. If you want to add new checks, you can do it there. | ||
|
||
[rel-tools]: https://sigs.k8s.io/kubebuilder-release-tools | ||
|
||
[actions-wf]: /.github/workflows/verify.yml | ||
|
||
## PR Process | ||
|
||
Every PR should be annotated with an icon indicating whether it's | ||
a: | ||
|
||
- Breaking change: :warning: (`:warning:`) | ||
- Non-breaking feature: :sparkles: (`:sparkles:`) | ||
- Patch fix: :bug: (`:bug:`) | ||
- Docs: :book: (`:book:`) | ||
- Infra/Tests/Other: :seedling: (`:seedling:`) | ||
- No release note: :ghost: (`:ghost:`) | ||
|
||
Use :ghost: (no release note) only for the PRs that change or revert unreleased | ||
changes, which don't deserve a release note. Please don't abuse it. | ||
|
||
You can also use the equivalent emoji directly, since GitHub doesn't | ||
render the `:xyz:` aliases in PR titles. | ||
|
||
Individual commits should not be tagged separately, but will generally be | ||
assumed to match the PR. For instance, if you have a bugfix in with | ||
a breaking change, it's generally encouraged to submit the bugfix | ||
separately, but if you must put them in one PR, mark the commit | ||
separately. | ||
|
||
### Commands and Workflow | ||
|
||
controller-runtime follows the standard Kubernetes workflow: any PR needs | ||
`lgtm` and `approved` labels, PRs authors must have signed the CNCF CLA, | ||
and PRs must pass the tests before being merged. See [the contributor | ||
docs](https://github.com/kubernetes/community/blob/master/contributors/guide/pull-requests.md#the-testing-and-merge-workflow) | ||
for more info. | ||
|
||
We use the same priority and kind labels as Kubernetes. See the labels | ||
tab in GitHub for the full list. | ||
|
||
The standard Kubernetes comment commands should work in | ||
controller-runtime. See [Prow](https://prow.k8s.io/command-help) for | ||
a command reference. | ||
|
||
## Release Process | ||
|
||
Minor and patch releases are generally done immediately after a feature or | ||
bugfix is landed, or sometimes a series of features tied together. | ||
|
||
Minor releases will only be tagged on the *most recent* major release | ||
branch, except in exceptional circumstances. Patches will be backported | ||
to maintained stable versions, as needed. | ||
|
||
Major releases are done shortly after a breaking change is merged -- once | ||
a breaking change is merged, the next release *must* be a major revision. | ||
We don't intend to have a lot of these, so we may put off merging breaking | ||
PRs until a later date. | ||
|
||
### Exact Steps | ||
|
||
Follow the release-specific steps below, then follow the general steps | ||
after that. | ||
|
||
#### Minor and patch releases | ||
|
||
1. Update the release-X branch with the latest set of changes by calling | ||
`git rebase master` from the release branch. | ||
|
||
#### Major releases | ||
|
||
1. Create a new release branch named `release-X` (where `X` is the new | ||
version) off of master. | ||
|
||
#### General | ||
|
||
2. Generate release notes using the release note tooling. | ||
|
||
3. Add a release for controller-runtime on GitHub, using those release | ||
notes, with a title of `vX.Y.Z`. | ||
|
||
4. Do a similar process for | ||
[controller-tools](https://github.com/kubernetes-sigs/controller-tools) | ||
|
||
5. Announce the release in `#kubebuilder` on Slack with a pinned message. | ||
|
||
6. Potentially update | ||
[kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) as well. | ||
|
||
### Breaking Changes | ||
|
||
Try to avoid breaking changes. They make life difficult for users, who | ||
have to rewrite their code when they eventually upgrade, and for | ||
maintainers/contributors, who have to deal with differences between master | ||
and stable branches. | ||
|
||
That being said, we'll occasionally want to make breaking changes. They'll | ||
be merged onto master, and will then trigger a major release (see [Release | ||
Process](#release-process)). Because breaking changes induce a major | ||
revision, the maintainers may delay a particular breaking change until | ||
a later date when they are ready to make a major revision with a few | ||
breaking changes. | ||
|
||
If you're going to make a breaking change, please make sure to explain in | ||
detail why it's helpful. Is it necessary to cleanly resolve an issue? | ||
Does it improve API ergonomics? | ||
|
||
Maintainers should treat breaking changes with caution, and evaluate | ||
potential non-breaking solutions (see below). | ||
|
||
Note that API breakage in public APIs due to dependencies will trigger | ||
a major revision, so you may occasionally need to have a major release | ||
anyway, due to changes in libraries like `k8s.io/client-go` or | ||
`k8s.io/apimachinery`. | ||
|
||
*NB*: Pre-1.0 releases treat breaking changes a bit more lightly. We'll | ||
still consider carefully, but the pre-1.0 timeframe is useful for | ||
converging on a ergonomic API. | ||
|
||
#### Avoiding breaking changes | ||
|
||
##### Solutions to avoid | ||
|
||
- **Confusingly duplicate methods, functions, or variables.** | ||
|
||
For instance, suppose we have an interface method `List(ctx | ||
context.Context, options *ListOptions, obj runtime.Object) error`, and | ||
we decide to switch it so that options come at the end, parametrically. | ||
Adding a new interface method `ListParametric(ctx context.Context, obj | ||
runtime.Object, options... ListOption)` is probably not the right | ||
solution: | ||
|
||
- Users will intuitively see `List`, and use that in new projects, even | ||
if it's marked as deprecated. | ||
|
||
- Users who don't notice the deprecation may be confused as to the | ||
difference between `List` and `ListParametric`. | ||
|
||
- It's not immediately obvious in isolation (e.g. in surrounding code) | ||
why the method is called `ListParametric`, and may cause confusion | ||
when reading code that makes use of that method. | ||
|
||
In this case, it may be better to make the breaking change, and then | ||
eventually do a major release. | ||
|
||
## Why don't we... | ||
|
||
### Use "next"-style branches | ||
|
||
Development branches: | ||
|
||
- don't win us much in terms of maintenance in the case of breaking | ||
changes (we still have to merge/manage multiple branches for development | ||
and stable) | ||
|
||
- can be confusing to contributors, who often expect master to have the | ||
latest changes. | ||
|
||
### Never break compatibility | ||
|
||
Never doing a new major release could be an admirable goal, but gradually | ||
leads to API cruft. | ||
|
||
Since one of the goals of controller-runtime is to be a friendly and | ||
intuitive API, we want to avoid too much API cruft over time, and | ||
occasional breaking changes in major releases help accomplish that goal. | ||
|
||
Furthermore, our dependency on Kubernetes libraries makes this difficult | ||
(see below) | ||
|
||
### Always assume we've broken compatibility | ||
|
||
*a.k.a. k8s.io/client-go style* | ||
|
||
While this makes life easier (a bit) for maintainers, it's problematic for | ||
users. While breaking changes arrive sooner, upgrading becomes very | ||
painful. | ||
|
||
Furthermore, we still have to maintain stable branches for bugfixes, so | ||
the maintenance burden isn't lessened by a ton. | ||
|
||
### Extend compatibility guarantees to all dependencies | ||
|
||
This is very difficult with the number of Kubernetes dependencies we have. | ||
Kubernetes dependencies tend to either break compatibility every major | ||
release (e.g. k8s.io/client-go, which loosely follows semver), or at | ||
a whim (many other Kubernetes libraries). | ||
|
||
If we limit to the few objects we expose, we can better inform users about | ||
how *controller-runtime itself* has changed in a given release. Then, | ||
users can make informed decisions about how to proceed with any direct | ||
uses of Kubernetes dependencies their controller-runtime-based application | ||
may have. | ||
[guidelines]: https://sigs.k8s.io/kubebuilder-release-tools/VERSIONING.md |