Skip to content

Commit

Permalink
feat(conventional-commits): add conventional prerelease/graduation
Browse files Browse the repository at this point in the history
  • Loading branch information
erquhart committed Mar 19, 2019
1 parent a7ad9b6 commit eeaabaf
Show file tree
Hide file tree
Showing 9 changed files with 1,399 additions and 1,201 deletions.
22 changes: 22 additions & 0 deletions commands/version/README.md
Expand Up @@ -39,6 +39,8 @@ If you have any packages with a prerelease version number (e.g. `2.0.0-beta.3`)
- [`--allow-branch`](#--allow-branch-glob)
- [`--amend`](#--amend)
- [`--conventional-commits`](#--conventional-commits)
- [`--conventional-graduate`](#--conventional-graduate)
- [`--conventional-prerelease`](#--conventional-prerelease)
- [`--changelog-preset`](#--changelog-preset)
- [`--exact`](#--exact)
- [`--force-publish`](#--force-publish)
Expand Down Expand Up @@ -116,6 +118,26 @@ When run with this flag, `lerna version` will use the [Conventional Commits Spec

Passing [`--no-changelog`](#--no-changelog) will disable the generation (or updating) of `CHANGELOG.md` files.

### `--conventional-prerelease`

```sh
lerna version --conventional-commits --conventional-prerelease
```

Provides automated prerelease versioning, works with both fixed and independent versioning. The version itself is only bumped if the current prerelease version does not meet the recommended bump level - for example, `package@1.0.1` will be bumped if features or breaking changes are present in the commits, while `package@2.0.0-alpha.0` will only ever receive prerelease identifier bumps, eg. `package@2.0.0-alpha.0 => package@2.0.0-alpha.1`, because `2.0.0` will be a major release and contain any type of change.

### `--conventional-graduate`

```sh
lerna version --conventional-commits --conventional-graduate=package-2,package-4

# force all prerelease packages to be graduated
lerna version --conventional-commits --conventional-graduate
```
When run with this flag, `lerna version` will graduate the specified packages (comma-separated) or all packages using `*`. Any non-prerelease packages are ignored. As always when running `lerna version`, all packages that depend on a package that is being released will themselves be released, but only specified packages will be graduated to a non-prerelease version.

"Graduating" a package means bumping to the non-prerelease variant of a prerelease version, eg. `package-1@1.0.0-alpha.0 => package-1@1.0.0`.

### `--changelog-preset`

```sh
Expand Down
23 changes: 18 additions & 5 deletions commands/version/index.js
Expand Up @@ -176,6 +176,15 @@ class VersionCommand extends Command {
);
}

if (this.options.conventionalPrerelease && this.options.conventionalGraduate) {
throw new ValidationError(
"ENOTALLOWED",
dedent`
--conventional-prerelease cannot be combined with --conventional-graduate.
`
);
}

this.updates = collectUpdates(
this.packageGraph.rawPackageList,
this.packageGraph,
Expand Down Expand Up @@ -232,7 +241,10 @@ class VersionCommand extends Command {

// amending a commit probably means the working tree is dirty
if (this.commitAndTag && this.gitOpts.amend !== true) {
tasks.unshift(() => checkWorkingTree(this.execOpts));
const { forcePublish, conventionalCommits, conventionalGraduate } = this.options;
const checkUncommittedOnly = forcePublish || (conventionalCommits && conventionalGraduate);
const check = checkUncommittedOnly ? checkWorkingTree.throwIfUncommitted : checkWorkingTree;
tasks.unshift(() => check(this.execOpts));
} else {
this.logger.warn("version", "Skipping working tree validation, proceed at your own risk");
}
Expand Down Expand Up @@ -275,10 +287,10 @@ class VersionCommand extends Command {

getVersionsForUpdates() {
const independentVersions = this.project.isIndependent();
const { bump, conventionalCommits, preid } = this.options;
const { bump, conventionalCommits, conventionalPrerelease, preid } = this.options;
const repoVersion = bump ? semver.clean(bump) : "";
const increment = bump && !semver.valid(bump) ? bump : "";
const isPrerelease = increment.startsWith("pre");
const isPrerelease = increment.startsWith("pre") || (conventionalCommits && conventionalPrerelease);

const getExistingPreId = version => (semver.prerelease(version) || []).shift();
const resolvePrereleaseId = existingPreid => preid || (isPrerelease && existingPreid) || "alpha";
Expand All @@ -305,7 +317,7 @@ class VersionCommand extends Command {
predicate = makeGlobalVersionPredicate(nextVersion);
} else if (conventionalCommits) {
// it's a bit weird to have a return here, true
return this.recommendVersions();
return this.recommendVersions(conventionalPrerelease, resolvePrereleaseId);
} else if (independentVersions) {
// prompt for each independent update with potential prerelease ID
predicate = makePromptVersion(resolvePrereleaseId);
Expand All @@ -328,7 +340,7 @@ class VersionCommand extends Command {
return pReduce(this.updates, iterator, new Map());
}

recommendVersions() {
recommendVersions(conventionalPrerelease, resolvePrereleaseId) {
const independentVersions = this.project.isIndependent();
const { changelogPreset } = this.options;
const rootPath = this.project.manifest.location;
Expand All @@ -346,6 +358,7 @@ class VersionCommand extends Command {
changelogPreset,
rootPath,
tagPrefix: this.tagPrefix,
prereleaseId: conventionalPrerelease && resolvePrereleaseId(node.prereleaseId),
})
)
);
Expand Down
27 changes: 24 additions & 3 deletions core/conventional-commits/lib/recommend-version.js
Expand Up @@ -7,7 +7,7 @@ const getChangelogConfig = require("./get-changelog-config");

module.exports = recommendVersion;

function recommendVersion(pkg, type, { changelogPreset, rootPath, tagPrefix }) {
function recommendVersion(pkg, type, { changelogPreset, rootPath, tagPrefix, prereleaseId }) {
log.silly(type, "for %s at %s", pkg.name, pkg.location);

const options = {
Expand All @@ -21,6 +21,20 @@ function recommendVersion(pkg, type, { changelogPreset, rootPath, tagPrefix }) {
options.tagPrefix = tagPrefix;
}

const shouldBumpPrerelease = (releaseType, version) => {
if (!semver.prerelease(version)) {
return true;
}
switch (releaseType) {
case "major":
return semver.minor(version) !== 0;
case "minor":
return semver.patch(version) !== 0;
default:
return false;
}
};

return getChangelogConfig(changelogPreset, rootPath).then(config => {
// "new" preset API
options.config = config;
Expand All @@ -35,8 +49,15 @@ function recommendVersion(pkg, type, { changelogPreset, rootPath, tagPrefix }) {
// we still need to bump _something_ because lerna saw a change here
const releaseType = data.releaseType || "patch";

log.verbose(type, "increment %s by %s", pkg.version, releaseType);
resolve(semver.inc(pkg.version, releaseType));
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 {
log.verbose(type, "increment %s by %s", pkg.version, releaseType);
resolve(semver.inc(pkg.version, releaseType));
}
});
});
});
Expand Down

0 comments on commit eeaabaf

Please sign in to comment.