Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: preserve major version zero on breaking changes (when using conventional commits) #2486

Merged
merged 1 commit into from May 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,8 @@
{
"command": {
"publish": {
"conventionalCommits": true
}
},
"version": "independent"
}
@@ -0,0 +1,5 @@
{
"name": "conventional-commits-major-zero",
"repository": "lerna/conventional-commits-major-zero",
"version": "0.0.0-root"
}
@@ -0,0 +1,5 @@
{
"name": "package-0",
"repository": "lerna/conventional-commits-major-zero",
"version": "0.1.0"
}
@@ -0,0 +1,5 @@
{
"name": "package-1",
"repository": "lerna/conventional-commits-major-zero",
"version": "1.0.0"
}
15 changes: 15 additions & 0 deletions core/conventional-commits/__tests__/conventional-commits.test.js
Expand Up @@ -217,6 +217,21 @@ describe("conventional-commits", () => {
).rejects.toThrow("Unable to load conventional-changelog preset 'conventional-changelog-garbage/pail'");
});

describe("bump for major version zero", () => {
evocateur marked this conversation as resolved.
Show resolved Hide resolved
it("treats breaking changes as semver-minor", async () => {
const cwd = await initFixture("major-zero");
const [pkg0] = await getPackages(cwd);

// make a change in package-0
await pkg0.set("changed", 1).serialize();
await gitAdd(cwd, pkg0.manifestLocation);
await gitCommit(cwd, "feat: changed\n\nBREAKING CHANGE: changed");

const bump = await recommendVersion(pkg0, "independent", {});
expect(bump).toBe("0.2.0");
});
});

describe("prerelease bumps", () => {
let cwd;
let pkg;
Expand Down
22 changes: 21 additions & 1 deletion core/conventional-commits/lib/recommend-version.js
Expand Up @@ -51,14 +51,34 @@ function recommendVersion(pkg, type, { changelogPreset, rootPath, tagPrefix, pre

// result might be undefined because some presets are not consistent with angular
// we still need to bump _something_ because lerna saw a change here
const releaseType = data.releaseType || "patch";
let releaseType = data.releaseType || "patch";

if (prereleaseId) {
const shouldBump = shouldBumpPrerelease(releaseType, pkg.version);
const prereleaseType = shouldBump ? `pre${releaseType}` : "prerelease";
log.verbose(type, "increment %s by %s", pkg.version, prereleaseType);
resolve(semver.inc(pkg.version, prereleaseType, prereleaseId));
} else {
if (semver.major(pkg.version) === 0) {
// According to semver, 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 version 1.0.0 defines
// the (initial stable) public API.
//
// To allow monorepos to use major version zero meaningfully,
// the transition from 0.x to 1.x must be explicitly requested
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some info-level logging indicating what is happening would be helpful. I appreciate the detailed comment.

// by the user. Breaking changes MUST NOT automatically bump
// the major version from 0.x to 1.x.
//
// The usual convention is to use semver-patch bumps for bugfix
// releases and semver-minor for everything else, including
// breaking changes. This matches the behavior of `^` operator
// as implemented by `npm`.
//
if (releaseType === "major") {
releaseType = "minor";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess if --conventional-graduate is true, we will bump the release to the new major, such as 0.1.0 -> 1.0.0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I would find such rule as possibly confusing. Also, how would such rule work in large monorepos having packages both in pre-release versions (2.0.0-beta.1) and major zero versions (0.2.5)?

I am currently envisioning the following process for graduating from 0.x to 1.0.0:

  1. Add a commit changing the version in package.json to 1.0.0-1 (or a similar pre-release). This will be just a commit, no release/tag is associated with it. The commit can have a nice descriptive message for the changelog, e.g. feat: graduate to 1.0.

  2. Run lerna version with --conventional-graduate to bump the temporary version 1.0.0-1 to final 1.0.0.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note --conventional-graduate allows a list of packages. Whether it's passed in as a CLI option or configured in lerna.json, we probably should honor it. See https://github.com/lerna/lerna/blob/master/commands/version/README.md#--conventional-graduate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see --conventional-graduate affecting 0.x ranges, as they are not "prereleases" in the sense that option is intended to modify. 0.x ranges, as I understand them, mean "API unstable", not "this is a prerelease of a specified quality".

}
}
log.verbose(type, "increment %s by %s", pkg.version, releaseType);
resolve(semver.inc(pkg.version, releaseType));
}
Expand Down