Loopback-next: Build: `lerna publish` upgrades from `0.x.y` to `1.0.0` for breaking changes

Created on 1 Mar 2018  路  11Comments  路  Source: strongloop/loopback-next

We have conventionalCommits configured to be true in lerna.json and use 0.x.y versioning for packages. If a commit log contains BREAKING CHANGE, lerna publish prompts the new versions as follows:

Changes:
 - @loopback/authentication: 0.1.1 => 1.0.0
 - @loopback/boot: 0.1.1 => 1.0.0
 - @loopback/build: 0.1.1 => 1.0.0
 - @loopback/cli: 0.1.2 => 0.1.3
 - @loopback/context: 0.1.1 => 1.0.0
 - @loopback/core: 0.1.1 => 0.2.0
 - @loopback/example-getting-started: 0.1.1 => 0.2.0 (private)
 - @loopback/example-hello-world: 0.1.1 => 0.1.2 (private)
 - @loopback/example-log-extension: 0.1.1 => 0.1.2 (private)
 - @loopback/example-rpc-server: 0.1.1 => 1.0.0 (private)
 - @loopback/metadata: 0.1.1 => 0.1.2
 - @loopback/openapi-spec-builder: 0.1.1 => 0.1.2
 - @loopback/openapi-spec: 0.1.1 => 0.1.2
 - @loopback/openapi-v2: 0.1.1 => 0.1.2
 - @loopback/openapi-v3-types: 0.1.1 => 0.2.0
 - @loopback/openapi-v3: 0.1.0 => 0.2.0
 - @loopback/repository-json-schema: 0.1.1 => 0.1.2
 - @loopback/repository: 0.1.1 => 1.0.0
 - @loopback/rest: 0.1.1 => 1.0.0
 - @loopback/testlab: 0.1.1 => 0.1.2

We want to upgrade from 0.<x>.<y> to 0.<x+1>.0 instead of 1.0.0.

To work around the issue, we have two options:

  1. Force all modules to be upgraded to the next minor version (0.<x>.<y> to 0.<x+1>.0) by using lerna publish --cd-version minor. For example:
Changes:
 - @loopback/authentication: 0.1.1 => 0.2.0
 - @loopback/boot: 0.1.1 => 0.2.0
 - @loopback/build: 0.1.1 => 0.2.0
 - @loopback/cli: 0.1.2 => 0.2.0
 - @loopback/context: 0.1.1 => 0.2.0
 - @loopback/core: 0.1.1 => 0.2.0
 - @loopback/example-getting-started: 0.1.1 => 0.2.0 (private)
 - @loopback/example-hello-world: 0.1.1 => 0.2.0 (private)
 - @loopback/example-log-extension: 0.1.1 => 0.2.0 (private)
 - @loopback/example-rpc-server: 0.1.1 => 0.2.0 (private)
 - @loopback/metadata: 0.1.1 => 0.2.0
 - @loopback/openapi-spec-builder: 0.1.1 => 0.2.0
 - @loopback/openapi-spec: 0.1.1 => 0.2.0
 - @loopback/openapi-v2: 0.1.1 => 0.2.0
 - @loopback/openapi-v3-types: 0.1.1 => 0.2.0
 - @loopback/openapi-v3: 0.1.0 => 0.2.0
 - @loopback/repository-json-schema: 0.1.1 => 0.2.0
 - @loopback/repository: 0.1.1 => 0.2.0
 - @loopback/rest: 0.1.1 => 0.2.0
 - @loopback/testlab: 0.1.1 => 0.2.0
  1. Disable conventionalCommits when breaking changes need to be published and manually select the versions package by package.

  2. Do not use BREAKING CHANGE in commit logs since feat(...) will upgrade to the next minor version ( 0.<x>.<y> to 0.<x+1>.0) anyway.

discussion

Most helpful comment

I vote for option 3, since semver says that "breaking changes" are a post-1.0.0 concept and that the implication of any 0.x.y API is that things can and will break without notice. (source)

==Added by @bajtos==
Spec item 4 says

Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.

All 11 comments

I vote for option 3, since semver says that "breaking changes" are a post-1.0.0 concept and that the implication of any 0.x.y API is that things can and will break without notice. (source)

==Added by @bajtos==
Spec item 4 says

Major version zero (0.y.z) is for initial development. Anything may change at any time. The public API should not be considered stable.

The only question left to answer, IMO, would be whether or not we can do option #3 based on the existing commit messages in our history, since some of them are marked with "BREAKING CHANGE"

I assume there's some cutoff built in so that it knows which releases already contain those changes, but we should make sure.

The only question left to answer, IMO, would be whether or not we can do option #3 based on the existing commit messages in our history, since some of them are marked with "BREAKING CHANGE"

For those commits that are not published yet, let's use Option 1 to force minor upgrades to reestablish the new baseline.

Ideally, I'd like to see Option 4: fix our tooling to release breaking changes as 0.x semver-minor, features and bugfixes as 0.x.y semver-patch versions. I filled an issue for that: https://github.com/conventional-changelog/conventional-changelog/issues/294

Let's recall why we switched to 0.x.y versions. Quoting from https://github.com/strongloop/loopback-next/issues/954:

If we were versioning non-core modules as 0.x.y, then we could treat semver-patch release as backwards compatible and semver-minor releases as breaking. This works great with the carrot operator as implemented by npm's semver (https://www.npmjs.com/package/semver#caret-ranges-123-025-004):

this allows patch and minor updates for versions 1.0.0 and above, patch updates for versions 0.X >=0.1.0, and no updates for versions 0.0.X.

Is this goal still valid?

feat(...) will upgrade to the next minor version ( 0.. to 0..0) anyway.

IIUC, this will require all our dependents to bump up semver-minor part of their ^0.x.y spec whenever we release a new feature. That's not the user experience I would like myself!

Another point to consider: the section BREAKING CHANGE is parsed by the changelog generator to tell our consumers what has changed and how to upgrade. See @loopback/[email protected] for an example.

Even if we consider the API as not stable and allow any breaking changes in 0.x releases, I would still prefer if we can start practicing the habit of writing descriptive BREAKING CHANGE entries in our commit messages. Let's build the skill now, while we don't mind too much when we occasionally forget to describe breaking changes, so that we are ready by the time it becomes important.

Having wrote that, I agree that Option 3 looks like the best workaround for short-term.

Possibly related: https://github.com/lerna/lerna/issues/1195

Here is what I have found so far:

  • conventional-recommended-bump is returning a string major, minor or patch depending on what the commit messages say. This is intentional and isn't going to change for 0.x versions as far as the recommendation is concerned. See https://github.com/conventional-changelog/conventional-changelog/issues/239

  • Most tools are using semver.inc() to compute the next version using the current version number and the recommended bump. semver is not willing to treat 0.x versions differently, see https://github.com/npm/node-semver/issues/177.

  • There is a module shifted-semver-increment which provides different behavior for 0.x versions. Unfortunately, they don't shift semver-minor to semver-patch as I proposed in my earlier comment, at least AFAICT - see the code.

  • Lerna uses semver.inc() to compute the next version, see src/ConventionalCommitUtilities.js#L86 and https://github.com/lerna/lerna/pull/665. It should be fairly easy to change this behavior, but such proposal may create a lot of controversy and thus take longer to get accepted. We may need to introduce config options to control this behaviour and remove controversy, that will require more effort.

I'm a +1 for writing the Breaking Change message just for changelogs which imo serves as a great reference to see what's been added to a release and often look at those for packages.

That said, changing tooling seems a bit excessive imo since this is only a problem during development but depending on the effort involved it might not be too much work since we do have a while before we release out of preview and as 4.0.0

+1 to stay with 0.x.y versioning scheme. At least we can bump minor versions and prevent them from being accidentally picked up by existing apps.

+1 to explore a fix in lerna to honor 0.x.y upgrade path. We can submit a PR to see what will happen.
Upon that, we can continue to use BREAKING CHANGE.

Considering there have been more than 5 months from the last comment, and we are planning to release 4.0 GA in few months (after which lerna versioning won't be a problem anymore), I think this issue can be closed.

Our experimental packages are using 0.x version, I am re-opening this issue because it's affecting us again.

Submitted a PR to lerna to fix the problem: https://github.com/lerna/lerna/pull/2486

lerna/lerna#2486 was merged and published, I am closing this issue as resolved.

Was this page helpful?
0 / 5 - 0 ratings