From 6126e6c6cb52405d7ff98d3b4017bf39dcdfa965 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Sun, 24 May 2020 23:05:08 +0200 Subject: [PATCH] feat(conventional-commits): Preserve major version zero on breaking changes (#2486) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 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`. This commit implements the convention described above: - a patch-level change bumps semver-patch version (NO CHANGE) - a minor-level change bumps semver-minor version (NO CHANGE) - a major-level (breaking) change bumps semver-minor version (NEW) Signed-off-by: Miroslav Bajtoš --- .../__fixtures__/major-zero/lerna.json | 8 +++++++ .../__fixtures__/major-zero/package.json | 5 +++++ .../packages/package-0/CHANGELOG.md | 0 .../packages/package-0/package.json | 5 +++++ .../packages/package-1/CHANGELOG.md | 0 .../packages/package-1/package.json | 5 +++++ .../__tests__/conventional-commits.test.js | 15 +++++++++++++ .../lib/recommend-version.js | 22 ++++++++++++++++++- 8 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 core/conventional-commits/__tests__/__fixtures__/major-zero/lerna.json create mode 100644 core/conventional-commits/__tests__/__fixtures__/major-zero/package.json create mode 100644 core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-0/CHANGELOG.md create mode 100644 core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-0/package.json create mode 100644 core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-1/CHANGELOG.md create mode 100644 core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-1/package.json diff --git a/core/conventional-commits/__tests__/__fixtures__/major-zero/lerna.json b/core/conventional-commits/__tests__/__fixtures__/major-zero/lerna.json new file mode 100644 index 0000000000..84e537a34e --- /dev/null +++ b/core/conventional-commits/__tests__/__fixtures__/major-zero/lerna.json @@ -0,0 +1,8 @@ +{ + "command": { + "publish": { + "conventionalCommits": true + } + }, + "version": "independent" +} diff --git a/core/conventional-commits/__tests__/__fixtures__/major-zero/package.json b/core/conventional-commits/__tests__/__fixtures__/major-zero/package.json new file mode 100644 index 0000000000..5c1c951592 --- /dev/null +++ b/core/conventional-commits/__tests__/__fixtures__/major-zero/package.json @@ -0,0 +1,5 @@ +{ + "name": "conventional-commits-major-zero", + "repository": "lerna/conventional-commits-major-zero", + "version": "0.0.0-root" +} diff --git a/core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-0/CHANGELOG.md b/core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-0/CHANGELOG.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-0/package.json b/core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-0/package.json new file mode 100644 index 0000000000..4415541841 --- /dev/null +++ b/core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-0/package.json @@ -0,0 +1,5 @@ +{ + "name": "package-0", + "repository": "lerna/conventional-commits-major-zero", + "version": "0.1.0" +} diff --git a/core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-1/CHANGELOG.md b/core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-1/CHANGELOG.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-1/package.json b/core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-1/package.json new file mode 100644 index 0000000000..fdfbc2b635 --- /dev/null +++ b/core/conventional-commits/__tests__/__fixtures__/major-zero/packages/package-1/package.json @@ -0,0 +1,5 @@ +{ + "name": "package-1", + "repository": "lerna/conventional-commits-major-zero", + "version": "1.0.0" +} diff --git a/core/conventional-commits/__tests__/conventional-commits.test.js b/core/conventional-commits/__tests__/conventional-commits.test.js index 7b535e8d21..a23b2ddd55 100644 --- a/core/conventional-commits/__tests__/conventional-commits.test.js +++ b/core/conventional-commits/__tests__/conventional-commits.test.js @@ -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", () => { + 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; diff --git a/core/conventional-commits/lib/recommend-version.js b/core/conventional-commits/lib/recommend-version.js index f13ae56df9..f524f9d048 100644 --- a/core/conventional-commits/lib/recommend-version.js +++ b/core/conventional-commits/lib/recommend-version.js @@ -51,7 +51,7 @@ 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); @@ -59,6 +59,26 @@ function recommendVersion(pkg, type, { changelogPreset, rootPath, tagPrefix, pre 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 + // 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"; + } + } log.verbose(type, "increment %s by %s", pkg.version, releaseType); resolve(semver.inc(pkg.version, releaseType)); }