Skip to content

Commit 44d8cdc

Browse files
committed
docs: document a breaking changes policy
This largely covers how to introduce a breaking change. It also attempts to clarify what is or isn't a breaking change. Closes #1424
1 parent 7e07684 commit 44d8cdc

File tree

1 file changed

+75
-1
lines changed

1 file changed

+75
-1
lines changed

CONTRIBUTING.md

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ BREAKING CHANGE: <summary>
128128
```
129129

130130
Where `(scope)` is optional, and `!` is only required if there is a breaking change.
131-
If a breaking change is introduced, then `BREAKING CHANGE:` is required.
131+
If a breaking change is introduced, then `BREAKING CHANGE:` is required; see
132+
the [Breaking Changes](#breaking-changes) section for how to introduce breaking
133+
changes.
132134

133135
Common `type`s:
134136

@@ -184,6 +186,78 @@ Issues should be triaged as follows:
184186
functionality, should also be filed in this repository but without the
185187
`core-rules` label.
186188

189+
## Breaking Changes
190+
191+
Breaking changes are generally permitted, but we follow a 3-step process for
192+
introducing them. The intent behind this process is to balance the difficulty of
193+
version upgrades for users, maintaining multiple code paths, and being able to
194+
introduce modern functionality.
195+
196+
The general process is:
197+
198+
1. In version `N`, introduce the new behavior, but it must be disabled by
199+
default. Users can opt into the new functionality when they upgrade to
200+
version `N`, which lets them try it and verify functionality.
201+
2. In version `N+1`, the new behavior can be enabled by default. Users can
202+
opt out if necessary, but doing so causes a warning to be issued.
203+
3. In version `N+2`, the new behavior is always enabled and cannot be opted out
204+
of. The API for the control mechanism can be removed in this release.
205+
206+
Note that the `+1` and `+2` releases are just examples; the steps are not
207+
required to happen in immedially subsequent releases.
208+
209+
210+
### How to control breaking changes
211+
212+
The details of the control mechanism will depend on the situation. Below is
213+
a summary of some different options.
214+
215+
* Environment variables are best for repository rule behavior. Environment
216+
variables can be propagated to rules and macros using the generated
217+
`@rules_python_internal//:config.bzl` file.
218+
* Attributes are applicable to macros and regular rules, especially when the
219+
behavior is likely to vary on a per-target basis.
220+
* [User defined build settings](https://bazel.build/extending/config#user-defined-build-settings)
221+
(aka custom build flags) are applicable for rules when the behavior change
222+
generally wouldn't vary on a per-target basis. They also have the benefit that
223+
an entire code base can have them easily enabled by a bazel command line flag.
224+
* Allowlists allow a project to centrally control if something is
225+
enabled/disabled. Under the hood, they are basically a specialized custom
226+
build flag.
227+
228+
Note that attributes and flags can seamlessly interoperate by having the default
229+
controlled by a flag, and an attribute can override the flag setting. This
230+
allows a project to enable the new behavior by default while they work to fix
231+
problematic cases to prepare for the next upgrade.
232+
233+
### What is considered a breaking change?
234+
235+
Precisely defining what constitutes a breaking change is hard because it's
236+
easy for _someone, somewhere_ to depend on _some_ observable behavior, despite
237+
our best efforts to thoroughly document what is or isn't supported and hiding
238+
any internal details.
239+
240+
In general, something is considered a breaking change when it changes the
241+
direct behavior of a supported public API. Simply being able to observe a
242+
behavior change doesn't necessarily mean it's a breaking change.
243+
244+
Long standing undocumented behavior is a large grey area and really depends on
245+
how load-bearing it has become and what sort of reasonable expectation of
246+
behavior there is.
247+
248+
Here's some examples of what would or wouldn't be considered a breaking change.
249+
250+
Breaking changes:
251+
* Renaming an function argument for public functions.
252+
* Enforcing stricter validation than was previously required when there's a
253+
sensible reason users would run afoul of it.
254+
* Changing the name of a public rule.
255+
256+
Not breaking changes:
257+
* Upgrading dependencies
258+
* Changing internal details, such as renaming an internal file.
259+
* Changing a rule to a macro.
260+
187261
## FAQ
188262

189263
### Installation errors when during `git commit`

0 commit comments

Comments
 (0)