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(conventional-commits): Add conventional prerelease/graduation #1991

Merged
merged 6 commits into from May 11, 2019
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
3 changes: 3 additions & 0 deletions __fixtures__/prerelease-independent/lerna.json
@@ -0,0 +1,3 @@
{
"version": "independent"
}
3 changes: 3 additions & 0 deletions __fixtures__/prerelease-independent/package.json
@@ -0,0 +1,3 @@
{
"name": "independent"
}
@@ -0,0 +1,4 @@
{
"name": "package-1",
"version": "1.0.0-alpha.0"
}
@@ -0,0 +1,7 @@
{
"name": "package-2",
"version": "2.0.0-alpha.0",
"dependencies": {
"package-1": "^1.0.0-alpha.0"
}
}
@@ -0,0 +1,7 @@
{
"name": "package-3",
"version": "3.0.0-beta.3",
"devDependencies": {
"package-2": "^2.0.0-alpha.0"
}
}
@@ -0,0 +1,7 @@
{
"name": "package-4",
"version": "4.0.0",
"dependencies": {
"package-1": "^0.0.0"
}
}
@@ -0,0 +1,8 @@
{
"name": "package-5",
"dependencies": {
"package-3": "^3.0.0-beta.3"
},
"private": true,
"version": "5.0.0-alpha.0"
}
3 changes: 3 additions & 0 deletions __fixtures__/prerelease/lerna.json
@@ -0,0 +1,3 @@
{
"version": "1.0.0-alpha.0"
}
3 changes: 3 additions & 0 deletions __fixtures__/prerelease/package.json
@@ -0,0 +1,3 @@
{
"name": "normal"
}
4 changes: 4 additions & 0 deletions __fixtures__/prerelease/packages/package-1/package.json
@@ -0,0 +1,4 @@
{
"name": "package-1",
"version": "1.0.0-alpha.0"
}
7 changes: 7 additions & 0 deletions __fixtures__/prerelease/packages/package-2/package.json
@@ -0,0 +1,7 @@
{
"name": "package-2",
"version": "1.0.0-alpha.0",
"dependencies": {
"package-1": "^1.0.0-alpha.0"
}
}
10 changes: 10 additions & 0 deletions __fixtures__/prerelease/packages/package-3/package.json
@@ -0,0 +1,10 @@
{
"name": "package-3",
"version": "1.0.0-alpha.0",
"peerDependencies": {
"package-2": "^1.0.0-alpha.0"
},
"devDependencies": {
"package-2": "^1.0.0-alpha.0"
}
}
7 changes: 7 additions & 0 deletions __fixtures__/prerelease/packages/package-4/package.json
@@ -0,0 +1,7 @@
{
"name": "package-4",
"version": "1.0.0-alpha.0",
"dependencies": {
"package-1": "^0.0.0"
}
}
11 changes: 11 additions & 0 deletions __fixtures__/prerelease/packages/package-5/package.json
@@ -0,0 +1,11 @@
{
"name": "package-5",
"dependencies": {
"package-1": "^1.0.0-alpha.0"
},
"optionalDependencies": {
"package-3": "^1.0.0-alpha.0"
},
"private": true,
"version": "1.0.0-alpha.0"
}
4 changes: 4 additions & 0 deletions commands/__mocks__/@lerna/collect-updates.js
@@ -1,5 +1,7 @@
"use strict";

const { collectPackages, getPackagesForOption } = jest.requireActual("@lerna/collect-updates");

// collectUpdates.setUpdated(cwd, packageNames...)
// otherwise, enables everything
const updated = new Map();
Expand All @@ -20,3 +22,5 @@ afterEach(() => {

module.exports = mockCollectUpdates;
module.exports.setUpdated = setUpdated;
module.exports.collectPackages = collectPackages;
module.exports.getPackagesForOption = getPackagesForOption;
9 changes: 9 additions & 0 deletions commands/publish/README.md
Expand Up @@ -52,6 +52,7 @@ This is useful when a previous `lerna publish` failed to publish all packages to
- [`--no-git-reset`](#--no-git-reset)
- [`--no-verify-access`](#--no-verify-access)
- [`--preid`](#--preid)
- [`--pre-dist-tag <tag>`](#--pre-dist-tag-tag)
- [`--registry <url>`](#--registry-url)
- [`--temp-tag`](#--temp-tag)
- [`--ignore-scripts`](#--ignore-scripts)
Expand Down Expand Up @@ -157,6 +158,14 @@ lerna publish --canary --preid next
When run with this flag, `lerna publish --canary` will increment `premajor`, `preminor`, `prepatch`, or `prerelease` semver
bumps using the specified [prerelease identifier](http://semver.org/#spec-item-9).

### `--pre-dist-tag <tag>`
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 any of these flags documented in the yargs command builder for publish: https://github.com/lerna/lerna/blob/master/commands/publish/command.js

I suppose it's not vital, since yargs seems perfectly happy to consume them implicitly...


```sh
lerna publish --pre-dist-tag next
```

Works the same as [`--dist-tag`](#--dist-tag-tag), except only applies to packages being released with a prerelease version.

### `--registry <url>`

When run with this flag, forwarded npm commands will use the specified registry for your package(s).
Expand Down
62 changes: 62 additions & 0 deletions commands/publish/__tests__/publish-tagging.test.js
Expand Up @@ -96,3 +96,65 @@ Map {
expect(npmDistTag.add).toHaveBeenCalledWith("@integration/package-1@1.0.1", "beta", conf); // <--
expect(npmDistTag.add).toHaveBeenCalledWith("@integration/package-2@1.0.1", "beta", conf);
});

test("publish prerelease --pre-dist-tag beta", async () => {
const cwd = await initFixture("normal");

collectUpdates.setUpdated(cwd, "package-1");

await lernaPublish(cwd)("prerelease", "--pre-dist-tag", "beta");

expect(npmPublish.registry.get("package-1")).toBe("beta");
expect(npmDistTag.remove).not.toHaveBeenCalled();
});

test("publish non-prerelease --pre-dist-tag beta", async () => {
const cwd = await initFixture("normal");

collectUpdates.setUpdated(cwd, "package-1");

await lernaPublish(cwd)("--pre-dist-tag", "beta");

expect(npmPublish.registry.get("package-1")).toBe("latest");
expect(npmDistTag.remove).not.toHaveBeenCalled();
});

test("publish non-prerelease --dist-tag next --pre-dist-tag beta", async () => {
const cwd = await initFixture("normal");

collectUpdates.setUpdated(cwd, "package-1");

await lernaPublish(cwd)("--dist-tag", "next", "--pre-dist-tag", "beta");

expect(npmPublish.registry.get("package-1")).toBe("next");
expect(npmDistTag.remove).not.toHaveBeenCalled();
});

test("publish --pre-dist-tag beta --temp-tag", async () => {
const cwd = await initFixture("integration");

await lernaPublish(cwd)(
"prerelease",
"--dist-tag",
"next",
"--preid",
"beta",
"--pre-dist-tag",
"beta",
"--temp-tag"
);

expect(npmPublish.registry).toMatchInlineSnapshot(`
Map {
"@integration/package-1" => "lerna-temp",
"@integration/package-2" => "lerna-temp",
}
`);

const conf = expect.objectContaining({
tag: "next",
});

expect(npmDistTag.add).toHaveBeenCalledWith("@integration/package-1@1.0.1-beta.0", "beta", conf);
expect(npmDistTag.add).toHaveBeenCalledWith("@integration/package-2@1.0.1-beta.0", "beta", conf);
});
24 changes: 20 additions & 4 deletions commands/publish/index.js
Expand Up @@ -26,6 +26,7 @@ const batchPackages = require("@lerna/batch-packages");
const runParallelBatches = require("@lerna/run-parallel-batches");
const pulseTillDone = require("@lerna/pulse-till-done");
const versionCommand = require("@lerna/version");
const prereleaseIdFromVersion = require("@lerna/prerelease-id-from-version");

const createTempLicenses = require("./lib/create-temp-licenses");
const getCurrentSHA = require("./lib/get-current-sha");
Expand Down Expand Up @@ -642,15 +643,19 @@ class PublishCommand extends Command {

const mapper = pPipe(
[
pkg =>
pulseTillDone(npmPublish(pkg, pkg.packed.tarFilePath, opts)).then(() => {
pkg => {
const preDistTag = this.getPreDistTag(pkg);
const tag = !this.options.tempTag && preDistTag ? preDistTag : opts.tag;
const pkgOpts = Object.assign({}, opts, { tag });
return pulseTillDone(npmPublish(pkg, pkg.packed.tarFilePath, pkgOpts)).then(() => {
tracker.success("published", pkg.name, pkg.version);
tracker.completeWork(1);

logPacked(pkg.packed);

return pkg;
}),
});
},

this.options.requireScripts && (pkg => this.execScript(pkg, "postpublish")),
].filter(Boolean)
Expand Down Expand Up @@ -685,7 +690,8 @@ class PublishCommand extends Command {
};
const mapper = pkg => {
const spec = `${pkg.name}@${pkg.version}`;
const distTag = getDistTag(pkg.get("publishConfig"));
const preDistTag = this.getPreDistTag(pkg);
const distTag = preDistTag || getDistTag(pkg.get("publishConfig"));

return Promise.resolve()
.then(() => pulseTillDone(npmDistTag.remove(spec, "lerna-temp", opts)))
Expand Down Expand Up @@ -714,6 +720,16 @@ class PublishCommand extends Command {

// undefined defaults to "latest" OR whatever is in pkg.publishConfig.tag
}

getPreDistTag(pkg) {
if (!this.options.preDistTag) {
return;
}
const isPrerelease = prereleaseIdFromVersion(pkg.version);
if (isPrerelease) {
return this.options.preDistTag;
}
}
}

module.exports.PublishCommand = PublishCommand;
1 change: 1 addition & 0 deletions commands/publish/package.json
Expand Up @@ -46,6 +46,7 @@
"@lerna/npm-publish": "file:../../utils/npm-publish",
"@lerna/output": "file:../../utils/output",
"@lerna/pack-directory": "file:../../utils/pack-directory",
"@lerna/prerelease-id-from-version": "file:../../utils/prerelease-id-from-version",
"@lerna/prompt": "file:../../core/prompt",
"@lerna/pulse-till-done": "file:../../utils/pulse-till-done",
"@lerna/run-lifecycle": "file:../../utils/run-lifecycle",
Expand Down
35 changes: 34 additions & 1 deletion commands/version/README.md
Expand Up @@ -30,15 +30,23 @@ lerna version [major | minor | patch | premajor | preminor | prepatch | prerelea
When this positional parameter is passed, `lerna version` will skip the version selection prompt and [increment](https://github.com/npm/node-semver#functions) the version by that keyword.
You must still use the `--yes` flag to avoid all prompts.

#### "Graduating" prereleases
## Prerelease

If you have any packages with a prerelease version number (e.g. `2.0.0-beta.3`) and you run `lerna version` with and a non-prerelease bump (`major`, `minor`, or `patch`), it will publish those previously pre-released packages _as well as_ the packages that have changed since the last release.

For projects using conventional commits, use the following flags for prerelease management:
**[`--conventional-prerelease`](#--conventional-prerelease):** release current changes as prerelease versions.
**[`--conventional-graduate`](#--conventional-graduate):** graduate prerelease versioned packages to stable versions.

Running `lerna version --conventional-commits` without the above flags will release current changes as prerelease only if the version is already in prerelease.

## Options

- [`--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 @@ -117,6 +125,31 @@ 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-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 `*`. This command works regardless of whether the current HEAD has been released, similar to `--force-publish`, except that any non-prerelease packages are ignored. If changes are present for packages that are not specified (if specifying packages), or for packages that are not in prerelease, those packages will be versioned as they normally would using `--conventional-commits`.

"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`.

> NOTE: when specifying packages, dependents of specified packages will be released, but will not be graduated.

### `--conventional-prerelease`

```sh
lerna version --conventional-commits --conventional-prerelease=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 release with prerelease versions the specified packages (comma-separated) or all packages using `*`. Releases all unreleased changes as pre(patch/minor/major/release) by prefixing the version recommendation from `conventional-commits` with `pre`, eg. if present changes include a feature commit, the recommended bump will be `minor`, so this flag will result in a `preminor` release. If changes are present for packages that are not specified (if specifying packages), or for packages that are already in prerelease, those packages will be versioned as they normally would using `--conventional-commits`.

### `--changelog-preset`

```sh
Expand Down