|
1 | 1 | # Versioning and Branching in controller-runtime |
2 | 2 |
|
3 | | -*NB*: this also applies to controller-tools. |
| 3 | +We follow the [common KubeBuilder versioning guidelines][guidelines], and |
| 4 | +use the corresponding tooling. |
4 | 5 |
|
5 | | -## TL;DR: |
| 6 | +For the purposes of the aforementioned guidelines, controller-runtime |
| 7 | +counts as a "library project", but otherwise follows the guidelines |
| 8 | +exactly. |
6 | 9 |
|
7 | | -### Users |
8 | | - |
9 | | -- We follow [Semantic Versioning (semver)](https://semver.org) |
10 | | -- Use releases with your dependency management to ensure that you get |
11 | | - compatible code |
12 | | -- The master branch contains all the latest code, some of which may break |
13 | | - compatibility (so "normal" `go get` is not recommended) |
14 | | - |
15 | | -### Contributors |
16 | | - |
17 | | -- All code PR must be labeled with :bug: (patch fixes), :sparkles: |
18 | | - (backwards-compatible features), or :warning: (breaking changes) |
19 | | - |
20 | | -- Breaking changes will find their way into the next major release, other |
21 | | - changes will go into an semi-immediate patch or minor release |
22 | | - |
23 | | -- Please *try* to avoid breaking changes when you can. They make users |
24 | | - face difficult decisions ("when do I go through the pain of |
25 | | - upgrading?"), and make life hard for maintainers and contributors |
26 | | - (dealing with differences on stable branches). |
27 | | - |
28 | | -### Mantainers |
29 | | - |
30 | | -Don't be lazy, read the rest of this doc :-) |
31 | | - |
32 | | -## Overview |
33 | | - |
34 | | -controller-runtime (and friends) follow [Semantic |
35 | | -Versioning](https://semver.org). I'd recommend reading the aforementioned |
36 | | -link if you're not familiar, but essentially, for any given release X.Y.Z: |
37 | | - |
38 | | -- an X (*major*) release indicates a set of backwards-compatible code. |
39 | | - Changing X means there's a breaking change. |
40 | | - |
41 | | -- a Y (*minor*) release indicates a minimum feature set. Changing Y means |
42 | | - the addition of a backwards-compatible feature. |
43 | | - |
44 | | -- a Z (*patch*) release indicates minimum set of bugfixes. Changing |
45 | | - Z means a backwards-compatible change that doesn't add functionality. |
46 | | - |
47 | | -*NB*: If the major release is `0`, any minor release may contain breaking |
48 | | -changes. |
49 | | - |
50 | | -These guarantees extend to all code exposed in public APIs of |
51 | | -controller-runtime. This includes code both in controller-runtime itself, |
52 | | -*plus types from dependencies in public APIs*. Types and functions not in |
53 | | -public APIs are not considered part of the guarantee. |
54 | | - |
55 | | -In order to easily maintain the guarantees, we have a couple of processes |
56 | | -that we follow. |
57 | | - |
58 | | -## Branches |
59 | | - |
60 | | -controller-runtime contains two types of branches: the *master* branch and |
61 | | -*release-X* branches. |
62 | | - |
63 | | -The *master* branch is where development happens. All the latest and |
64 | | -greatest code, including breaking changes, happens on master. |
65 | | - |
66 | | -The *release-X* branches contain stable, backwards compatible code. Every |
67 | | -major (X) release, a new such branch is created. It is from these |
68 | | -branches that minor and patch releases are tagged. If some cases, it may |
69 | | -be necessary open PRs for bugfixes directly against stable branches, but |
70 | | -this should generally not be the case. |
71 | | - |
72 | | -The maintainers are responsible for updating the contents of this branch; |
73 | | -generally, this is done just before a release using release tooling that |
74 | | -filters and checks for changes tagged as breaking (see below). |
75 | | - |
76 | | -### Tooling |
77 | | - |
78 | | -Tooling for releases lives in the [kubebuilder-release-tools |
79 | | -repository][rel-tools]. |
80 | | - |
81 | | -* `go run sigs.k8s.io/kubebuilder-release-tools/notes` from a `release-X` |
82 | | - (or `release-0.Y`) branch will generate release notes based on the emoji |
83 | | - described below. |
84 | | - |
85 | | - You can generally paste the stdout output directly into the release, |
86 | | - unless the tool mentions needing manual edits. |
87 | | - |
88 | | -* the [GitHub actions workflow][actions-wf] in this repo will verify PRs |
89 | | - using the verifier action from the [release-tools][rel-tools] mentioned |
90 | | - above. If you want to add new checks, you can do it there. |
91 | | - |
92 | | -[rel-tools]: https://sigs.k8s.io/kubebuilder-release-tools |
93 | | - |
94 | | -[actions-wf]: /.github/workflows/verify.yml |
95 | | - |
96 | | -## PR Process |
97 | | - |
98 | | -Every PR should be annotated with an icon indicating whether it's |
99 | | -a: |
100 | | - |
101 | | -- Breaking change: :warning: (`:warning:`) |
102 | | -- Non-breaking feature: :sparkles: (`:sparkles:`) |
103 | | -- Patch fix: :bug: (`:bug:`) |
104 | | -- Docs: :book: (`:book:`) |
105 | | -- Infra/Tests/Other: :seedling: (`:seedling:`) |
106 | | -- No release note: :ghost: (`:ghost:`) |
107 | | - |
108 | | -Use :ghost: (no release note) only for the PRs that change or revert unreleased |
109 | | -changes, which don't deserve a release note. Please don't abuse it. |
110 | | - |
111 | | -You can also use the equivalent emoji directly, since GitHub doesn't |
112 | | -render the `:xyz:` aliases in PR titles. |
113 | | - |
114 | | -Individual commits should not be tagged separately, but will generally be |
115 | | -assumed to match the PR. For instance, if you have a bugfix in with |
116 | | -a breaking change, it's generally encouraged to submit the bugfix |
117 | | -separately, but if you must put them in one PR, mark the commit |
118 | | -separately. |
119 | | - |
120 | | -### Commands and Workflow |
121 | | - |
122 | | -controller-runtime follows the standard Kubernetes workflow: any PR needs |
123 | | -`lgtm` and `approved` labels, PRs authors must have signed the CNCF CLA, |
124 | | -and PRs must pass the tests before being merged. See [the contributor |
125 | | -docs](https://github.com/kubernetes/community/blob/master/contributors/guide/pull-requests.md#the-testing-and-merge-workflow) |
126 | | -for more info. |
127 | | - |
128 | | -We use the same priority and kind labels as Kubernetes. See the labels |
129 | | -tab in GitHub for the full list. |
130 | | - |
131 | | -The standard Kubernetes comment commands should work in |
132 | | -controller-runtime. See [Prow](https://prow.k8s.io/command-help) for |
133 | | -a command reference. |
134 | | - |
135 | | -## Release Process |
136 | | - |
137 | | -Minor and patch releases are generally done immediately after a feature or |
138 | | -bugfix is landed, or sometimes a series of features tied together. |
139 | | - |
140 | | -Minor releases will only be tagged on the *most recent* major release |
141 | | -branch, except in exceptional circumstances. Patches will be backported |
142 | | -to maintained stable versions, as needed. |
143 | | - |
144 | | -Major releases are done shortly after a breaking change is merged -- once |
145 | | -a breaking change is merged, the next release *must* be a major revision. |
146 | | -We don't intend to have a lot of these, so we may put off merging breaking |
147 | | -PRs until a later date. |
148 | | - |
149 | | -### Exact Steps |
150 | | - |
151 | | -Follow the release-specific steps below, then follow the general steps |
152 | | -after that. |
153 | | - |
154 | | -#### Minor and patch releases |
155 | | - |
156 | | -1. Update the release-X branch with the latest set of changes by calling |
157 | | - `git rebase master` from the release branch. |
158 | | - |
159 | | -#### Major releases |
160 | | - |
161 | | -1. Create a new release branch named `release-X` (where `X` is the new |
162 | | - version) off of master. |
163 | | - |
164 | | -#### General |
165 | | - |
166 | | -2. Generate release notes using the release note tooling. |
167 | | - |
168 | | -3. Add a release for controller-runtime on GitHub, using those release |
169 | | - notes, with a title of `vX.Y.Z`. |
170 | | - |
171 | | -4. Do a similar process for |
172 | | - [controller-tools](https://github.com/kubernetes-sigs/controller-tools) |
173 | | - |
174 | | -5. Announce the release in `#kubebuilder` on Slack with a pinned message. |
175 | | - |
176 | | -6. Potentially update |
177 | | - [kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) as well. |
178 | | - |
179 | | -### Breaking Changes |
180 | | - |
181 | | -Try to avoid breaking changes. They make life difficult for users, who |
182 | | -have to rewrite their code when they eventually upgrade, and for |
183 | | -maintainers/contributors, who have to deal with differences between master |
184 | | -and stable branches. |
185 | | - |
186 | | -That being said, we'll occasionally want to make breaking changes. They'll |
187 | | -be merged onto master, and will then trigger a major release (see [Release |
188 | | -Process](#release-process)). Because breaking changes induce a major |
189 | | -revision, the maintainers may delay a particular breaking change until |
190 | | -a later date when they are ready to make a major revision with a few |
191 | | -breaking changes. |
192 | | - |
193 | | -If you're going to make a breaking change, please make sure to explain in |
194 | | -detail why it's helpful. Is it necessary to cleanly resolve an issue? |
195 | | -Does it improve API ergonomics? |
196 | | - |
197 | | -Maintainers should treat breaking changes with caution, and evaluate |
198 | | -potential non-breaking solutions (see below). |
199 | | - |
200 | | -Note that API breakage in public APIs due to dependencies will trigger |
201 | | -a major revision, so you may occasionally need to have a major release |
202 | | -anyway, due to changes in libraries like `k8s.io/client-go` or |
203 | | -`k8s.io/apimachinery`. |
204 | | - |
205 | | -*NB*: Pre-1.0 releases treat breaking changes a bit more lightly. We'll |
206 | | -still consider carefully, but the pre-1.0 timeframe is useful for |
207 | | -converging on a ergonomic API. |
208 | | - |
209 | | -#### Avoiding breaking changes |
210 | | - |
211 | | -##### Solutions to avoid |
212 | | - |
213 | | -- **Confusingly duplicate methods, functions, or variables.** |
214 | | - |
215 | | - For instance, suppose we have an interface method `List(ctx |
216 | | - context.Context, options *ListOptions, obj runtime.Object) error`, and |
217 | | - we decide to switch it so that options come at the end, parametrically. |
218 | | - Adding a new interface method `ListParametric(ctx context.Context, obj |
219 | | - runtime.Object, options... ListOption)` is probably not the right |
220 | | - solution: |
221 | | - |
222 | | - - Users will intuitively see `List`, and use that in new projects, even |
223 | | - if it's marked as deprecated. |
224 | | - |
225 | | - - Users who don't notice the deprecation may be confused as to the |
226 | | - difference between `List` and `ListParametric`. |
227 | | - |
228 | | - - It's not immediately obvious in isolation (e.g. in surrounding code) |
229 | | - why the method is called `ListParametric`, and may cause confusion |
230 | | - when reading code that makes use of that method. |
231 | | - |
232 | | - In this case, it may be better to make the breaking change, and then |
233 | | - eventually do a major release. |
234 | | - |
235 | | -## Why don't we... |
236 | | - |
237 | | -### Use "next"-style branches |
238 | | - |
239 | | -Development branches: |
240 | | - |
241 | | -- don't win us much in terms of maintenance in the case of breaking |
242 | | - changes (we still have to merge/manage multiple branches for development |
243 | | - and stable) |
244 | | - |
245 | | -- can be confusing to contributors, who often expect master to have the |
246 | | - latest changes. |
247 | | - |
248 | | -### Never break compatibility |
249 | | - |
250 | | -Never doing a new major release could be an admirable goal, but gradually |
251 | | -leads to API cruft. |
252 | | - |
253 | | -Since one of the goals of controller-runtime is to be a friendly and |
254 | | -intuitive API, we want to avoid too much API cruft over time, and |
255 | | -occasional breaking changes in major releases help accomplish that goal. |
256 | | - |
257 | | -Furthermore, our dependency on Kubernetes libraries makes this difficult |
258 | | -(see below) |
259 | | - |
260 | | -### Always assume we've broken compatibility |
261 | | - |
262 | | -*a.k.a. k8s.io/client-go style* |
263 | | - |
264 | | -While this makes life easier (a bit) for maintainers, it's problematic for |
265 | | -users. While breaking changes arrive sooner, upgrading becomes very |
266 | | -painful. |
267 | | - |
268 | | -Furthermore, we still have to maintain stable branches for bugfixes, so |
269 | | -the maintenance burden isn't lessened by a ton. |
270 | | - |
271 | | -### Extend compatibility guarantees to all dependencies |
272 | | - |
273 | | -This is very difficult with the number of Kubernetes dependencies we have. |
274 | | -Kubernetes dependencies tend to either break compatibility every major |
275 | | -release (e.g. k8s.io/client-go, which loosely follows semver), or at |
276 | | -a whim (many other Kubernetes libraries). |
277 | | - |
278 | | -If we limit to the few objects we expose, we can better inform users about |
279 | | -how *controller-runtime itself* has changed in a given release. Then, |
280 | | -users can make informed decisions about how to proceed with any direct |
281 | | -uses of Kubernetes dependencies their controller-runtime-based application |
282 | | -may have. |
| 10 | +[guidelines]: https://sigs.k8s.io/kubebuilder-release-tools/VERSIONING.md |
0 commit comments