= Versioning

RuboCop is stable between major versions, both in terms of API and cop
configuration. We aim to ease the maintenance of RuboCop extensions
(by keeping the API stable) and the upgrades between RuboCop releases
(by not enabling new cops and changing the configuration of existing cops).
All big (breaking) changes are reserved for major releases.

== Release Policy

We're following https://semver.org/[Semantic Versioning]. API
compatibility between major releases is a big concern, as there are
many RuboCop extensions that can be affected by breaking API changes.

The development cycle for the next minor (feature) release starts
immediately after the previous one has been shipped. Bug-fix (point)
releases (if any) address only serious bugs and never contain new
features.

Here are a few examples:

* 1.1.0 - Feature release
* 1.1.1 - Bug-fix release
* 1.1.2 - Bug-fix release
* 1.2.0 - Feature release

=== What goes in each release type

|===
| Change type | Release

| Bug fixes to existing cops | Patch
| New cops (added as *pending*) | Minor
| New configuration options | Minor
| New CLI flags or formatters | Minor
| Renaming or moving cops (with backwards-compatible obsoletions) | Minor
| Dropping runtime Ruby version support | Minor
| Enabling pending cops by default | *Major*
| Changing cop defaults (e.g. `EnforcedStyle`) | *Major*
| Removing cops without a replacement | *Major*
| Breaking changes to the Ruby API | *Major*
| Dropping analysis support for a Ruby version | *Major*
|===

NOTE: Dropping **runtime** support for a particular Ruby version is not considered a breaking change,
as it doesn't affect clients in any way. They are simply restricted to the last version of
RuboCop supporting their Ruby runtime.

NOTE: Prior to RuboCop 1.0 bumps of the minor (second) version number
were considered major releases and always included new features and/or
changes to existing features.

== Pending Cops

In the early versions of RuboCop a common source of frustration was that
new cops were added to pretty much every release, and as they were enabled
by default, every upgrade resulted in broken CI builds and trying to figure
out what exactly was changed. After considering many options to address
this eventually we opted for an approach that limits these types of changes
to major RuboCop releases.

Now new cops introduced between major versions are set to a special pending
status and are not enabled by default. A warning is emitted if such cops
are not explicitly enabled or disabled in the user configuration. Here's
one such message:

----
The following cops were added to RuboCop, but are not configured. Please
set Enabled to either `true` or `false` in your `.rubocop.yml` file:
 - Style/HashEachMethods (0.80)
 - Style/HashTransformKeys (0.80)
 - Style/HashTransformValues (0.80)
For more information: https://docs.rubocop.org/rubocop/versioning.html
----

You can see that 3 new cops were added in RuboCop 0.80 and it's up to you
to decide if you want to enable or disable them.

NOTE: Occasionally, some new cops will be introduced as *disabled* by
default. Usually, this means that we believe that the cop is useful,
but not for everyone. Typical cases might be the enforcement of
programming styles that are not very common in the wild, or cops that
yield too many false positives (so you'd run them manually from time
to time, instead of running them all the time).

=== Enabling/Disabling Pending Cops in Bulk

To suppress this message set `NewCops` to either `enable` or `disable` in your `.rubocop.yml` file.
You can use the following configuration or the `--enable-pending-cops` command-line option to enable all pending cops in bulk:

[source,yaml]
----
AllCops:
  NewCops: enable
----

Alternatively, you can use the following configuration or the `--disable-pending-cops` command-line option to disable all pending cops in bulk:

[source,yaml]
----
AllCops:
  NewCops: disable
----

NOTE: The command-line option takes precedence over the `.rubocop.yml` file.

=== Enabling/Disabling Pending Cops per Department

A single version in `AllCops` cannot express which pending cops to enable, because extension gems follow their own version schemes.
Instead, `NewCops` can be set for a department, in which case it takes precedence over the `AllCops` setting for the cops of that department.
In addition to `enable`, `disable`, and `pending`, a department accepts a version, which enables all pending cops of the department
that were added in the specified version or earlier:

[source,yaml]
----
AllCops:
  NewCops: disable # keywords only, as before

Lint:
  NewCops: enable  # a department overrides `AllCops`

Style:
  NewCops: '1.19'  # enables pending cops with `VersionAdded` <= 1.19

Minitest:
  NewCops: '0.10'  # an extension is pinned to its own version
----

Pending cops added in a later version keep emitting the warning, so you can review them and bump the version at your own pace.
Since each department is pinned to its own version, this also works for extensions whose version schemes differ from RuboCop's.

NOTE: Quote the version to avoid YAML interpreting it as a number (for example, an unquoted `1.20` is read as `1.2`).

=== Enabling/Disabling Individual Pending Cops

Finally, you can enable/disable individual pending cops by setting their `Enabled` configuration to either `true` or `false` in your `.rubocop.yml` file:

`Style/ANewCop` is an example of a newly added pending cop:

[source,yaml]
----
Style/ANewCop:
  Enabled: true
----

or

[source,yaml]
----
Style/ANewCop:
  Enabled: false
----

IMPORTANT: On major RuboCop version updates (e.g. 1.0 -> 2.0), *all* pending cops are enabled in bulk.
