semantic-release-lerna 0.2.2 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/lib/generate-notes.js +5 -2
- package/lib/get-changed-packages.js +5 -5
- package/lib/prepare.js +58 -1
- package/lib/prepare.test.js +439 -0
- package/lib/publish.js +7 -6
- package/lib/should-latch.test.js +58 -0
- package/lib/verify-git.test.js +49 -0
- package/package.json +21 -22
package/README.md
CHANGED
|
@@ -28,6 +28,15 @@ As of now the following features from `@semantic-release/npm` is not supported/i
|
|
|
28
28
|
| `prepare` | Update the `package.json` version and [create](https://docs.npmjs.com/cli/pack) the npm package tarball. |
|
|
29
29
|
| `publish` | [Publish the npm package](https://docs.npmjs.com/cli/publish) to the registry. |
|
|
30
30
|
|
|
31
|
+
## Dependencies
|
|
32
|
+
|
|
33
|
+
If a package version is bumped all the packages depending (`dependencies`, `devDependencies` and `peerDependencies`) on it will also have the range updated if the range has one of the following formats:
|
|
34
|
+
|
|
35
|
+
- `1.2.3`
|
|
36
|
+
- `^1.2.3`
|
|
37
|
+
- `^1.2`
|
|
38
|
+
- `^1`
|
|
39
|
+
|
|
31
40
|
## Install
|
|
32
41
|
|
|
33
42
|
```bash
|
package/lib/generate-notes.js
CHANGED
|
@@ -27,7 +27,7 @@ const { Project } = require("@lerna/project");
|
|
|
27
27
|
*
|
|
28
28
|
* @returns {String} The changelog for all the commits in `context.commits`.
|
|
29
29
|
*/
|
|
30
|
-
/* eslint-disable-next-line complexity */
|
|
30
|
+
/* eslint-disable-next-line complexity, sonarjs/cognitive-complexity */
|
|
31
31
|
async function generateNotes(pluginConfig, context) {
|
|
32
32
|
const { commits, lastRelease, nextRelease, options, cwd, logger } = context;
|
|
33
33
|
const { generateNotes = false } = pluginConfig;
|
|
@@ -58,12 +58,15 @@ async function generateNotes(pluginConfig, context) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const [match, auth, host, path] =
|
|
61
|
+
/* eslint-disable-next-line security/detect-unsafe-regex */
|
|
61
62
|
/^(?!.+:\/\/)(?:(?<auth>.*)@)?(?<host>.*?):(?<path>.*)$/.exec(repositoryUrl) || [];
|
|
62
|
-
const
|
|
63
|
+
const authString = auth ? `${auth}@` : "";
|
|
64
|
+
const url = new URL(match ? `ssh://${authString}${host}/${path}` : repositoryUrl);
|
|
63
65
|
const { hostname, pathname } = url;
|
|
64
66
|
let { port, protocol } = url;
|
|
65
67
|
port = protocol.includes("ssh") ? "" : port;
|
|
66
68
|
protocol = protocol && /http[^s]/.test(protocol) ? "http" : "https";
|
|
69
|
+
/* eslint-disable-next-line security/detect-unsafe-regex */
|
|
67
70
|
const [, owner, repository] = /^\/(?<owner>[^/]+)?\/?(?<repository>.+)?$/.exec(pathname);
|
|
68
71
|
|
|
69
72
|
const { issue, commit, referenceActions, issuePrefixes } =
|
|
@@ -37,8 +37,9 @@ function parse(stdout, options = {}) {
|
|
|
37
37
|
return { refCount, sha, isDirty: Boolean(isDirty) };
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
/* eslint-disable-next-line security/detect-unsafe-regex */
|
|
41
|
+
const result = /^((?:.*@)?(.*))-(\d+)-g([\da-f]+)(-dirty)?$/.exec(stdout) || [];
|
|
42
|
+
const [, lastTagName, lastVersion, refCount, sha, isDirty] = result;
|
|
42
43
|
|
|
43
44
|
return { lastTagName, lastVersion, refCount, sha, isDirty: Boolean(isDirty) };
|
|
44
45
|
}
|
|
@@ -55,7 +56,7 @@ function collectUpdates(filteredPackages, packageGraph, execOptions, commandOpti
|
|
|
55
56
|
|
|
56
57
|
if (hasTags(execOptions)) {
|
|
57
58
|
// Describe the last annotated tag in the current branch
|
|
58
|
-
const { refCount, lastTagName } = describeRefSync(execOptions
|
|
59
|
+
const { refCount, lastTagName } = describeRefSync(execOptions);
|
|
59
60
|
|
|
60
61
|
if (refCount === "0" && !committish) {
|
|
61
62
|
// No commits since previous release
|
|
@@ -109,9 +110,8 @@ async function getChangedPackages(latch, context) {
|
|
|
109
110
|
{ cwd },
|
|
110
111
|
{ logger, version, latch }
|
|
111
112
|
);
|
|
112
|
-
const changedProjects = updates.map((node) => packages.find((pkg) => pkg.name === node.name));
|
|
113
113
|
|
|
114
|
-
return
|
|
114
|
+
return updates.map((node) => packages.find((pkg) => pkg.name === node.name));
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
module.exports = getChangedPackages;
|
package/lib/prepare.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
2
|
const fs = require("fs").promises;
|
|
3
|
+
const { existsSync } = require("fs");
|
|
3
4
|
const { format } = require("util");
|
|
4
5
|
const execa = require("execa");
|
|
5
6
|
const { Project } = require("@lerna/project");
|
|
6
7
|
const { Package } = require("@lerna/package");
|
|
7
8
|
const writeJsonFile = require("write-json-file");
|
|
9
|
+
const semverParse = require("semver/functions/parse");
|
|
8
10
|
const getChangedPackages = require("./get-changed-packages");
|
|
9
11
|
|
|
10
12
|
/**
|
|
@@ -12,6 +14,7 @@ const getChangedPackages = require("./get-changed-packages");
|
|
|
12
14
|
* @returns {any}
|
|
13
15
|
**/
|
|
14
16
|
async function readJson(path) {
|
|
17
|
+
/* eslint-disable-next-line security/detect-non-literal-fs-filename */
|
|
15
18
|
return JSON.parse(await fs.readFile(path));
|
|
16
19
|
}
|
|
17
20
|
|
|
@@ -73,6 +76,39 @@ async function updatePackage(npmrc, pkg, context, currentVersions) {
|
|
|
73
76
|
}
|
|
74
77
|
}
|
|
75
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Bump version in a single package "package-lock.json".
|
|
81
|
+
*
|
|
82
|
+
* Noop if "package-lock.json" does not exist.
|
|
83
|
+
*
|
|
84
|
+
* @param {string} npmrc
|
|
85
|
+
* @param {Package} pkg
|
|
86
|
+
* @param {any} context
|
|
87
|
+
* @returns {Promise<void>}
|
|
88
|
+
*/
|
|
89
|
+
async function updateLockfile(npmrc, pkg, context) {
|
|
90
|
+
const { env, stdout, stderr, logger } = context;
|
|
91
|
+
|
|
92
|
+
const lockfile = path.join(pkg.location, "package-lock.json");
|
|
93
|
+
if (!existsSync(lockfile)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
logger.log("Update package-lock.json in %s", pkg.location);
|
|
98
|
+
|
|
99
|
+
const versionResult = execa(
|
|
100
|
+
"npm",
|
|
101
|
+
["install", "--package-lock-only", "--ignore-scripts", "--no-audit", "--userconfig", npmrc],
|
|
102
|
+
{
|
|
103
|
+
cwd: pkg.location,
|
|
104
|
+
env,
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
versionResult.stdout.pipe(stdout, { end: false });
|
|
108
|
+
versionResult.stderr.pipe(stderr, { end: false });
|
|
109
|
+
await versionResult;
|
|
110
|
+
}
|
|
111
|
+
|
|
76
112
|
/**
|
|
77
113
|
* @param {Record<string, string>} dependencies
|
|
78
114
|
* @param {string} newVersion
|
|
@@ -80,22 +116,40 @@ async function updatePackage(npmrc, pkg, context, currentVersions) {
|
|
|
80
116
|
* @returns {void}
|
|
81
117
|
*/
|
|
82
118
|
function bumpDependency(dependencies, newVersion, currentVersions) {
|
|
119
|
+
const newParsed = semverParse(newVersion);
|
|
120
|
+
if (!newParsed) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
83
123
|
for (const [dep, range] of Object.entries(dependencies)) {
|
|
84
124
|
if (!currentVersions[dep]) {
|
|
85
125
|
continue;
|
|
86
126
|
}
|
|
87
127
|
|
|
88
128
|
const version = currentVersions[dep];
|
|
129
|
+
const parsed = semverParse(version);
|
|
130
|
+
if (!parsed) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
89
133
|
|
|
90
134
|
/* Exact versions */
|
|
91
135
|
if (range === version) {
|
|
92
136
|
dependencies[dep] = newVersion;
|
|
93
137
|
}
|
|
94
138
|
|
|
95
|
-
/* Hat ^ */
|
|
139
|
+
/* Hat ^x.y.z */
|
|
96
140
|
if (range === `^${version}`) {
|
|
97
141
|
dependencies[dep] = `^${newVersion}`;
|
|
98
142
|
}
|
|
143
|
+
|
|
144
|
+
/* Hat ^x.y */
|
|
145
|
+
if (range === `^${parsed.major}.${parsed.minor}`) {
|
|
146
|
+
dependencies[dep] = `^${newParsed.major}.${newParsed.minor}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* Hat ^x */
|
|
150
|
+
if (range === `^${parsed.major}`) {
|
|
151
|
+
dependencies[dep] = `^${newParsed.major}`;
|
|
152
|
+
}
|
|
99
153
|
}
|
|
100
154
|
}
|
|
101
155
|
|
|
@@ -167,4 +221,7 @@ module.exports = async (npmrc, pluginConfig, context) => {
|
|
|
167
221
|
/* Bump version in "lerna.json" */
|
|
168
222
|
await updateLernaJson(basePath, context);
|
|
169
223
|
await updatePackage(npmrc, rootPkg, context);
|
|
224
|
+
|
|
225
|
+
/* Bump version in "package-lock.json" */
|
|
226
|
+
await updateLockfile(npmrc, rootPkg, context);
|
|
170
227
|
};
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/* eslint-env jest */
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { outputJson, readJson } = require("fs-extra");
|
|
4
|
+
const tempy = require("tempy");
|
|
5
|
+
const execa = require("execa");
|
|
6
|
+
const { WritableStreamBuffer } = require("stream-buffers");
|
|
7
|
+
const prepare = require("./prepare");
|
|
8
|
+
|
|
9
|
+
let context;
|
|
10
|
+
let mockChangedPackages;
|
|
11
|
+
|
|
12
|
+
jest.mock("../lib/get-changed-packages", () => {
|
|
13
|
+
function getChangedPackagesMock() {
|
|
14
|
+
return mockChangedPackages;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return getChangedPackagesMock;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
async function createProject(cwd, version, pkgData) {
|
|
21
|
+
const lernaPath = path.resolve(cwd, "lerna.json");
|
|
22
|
+
const manifestLocation = path.resolve(cwd, "package.json");
|
|
23
|
+
await outputJson(lernaPath, { version, packages: ["packages/*"] });
|
|
24
|
+
await outputJson(manifestLocation, { name: "root-pkg", version, ...pkgData });
|
|
25
|
+
return {
|
|
26
|
+
lernaPath,
|
|
27
|
+
manifestLocation,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* eslint-disable-next-line max-params */
|
|
32
|
+
async function createPackage(cwd, name, version, options, pkgData) {
|
|
33
|
+
const { changed = false } = options;
|
|
34
|
+
const pkgRoot = `packages/${name}`;
|
|
35
|
+
const location = path.resolve(cwd, pkgRoot);
|
|
36
|
+
const manifestLocation = path.resolve(cwd, pkgRoot, "package.json");
|
|
37
|
+
const pkg = {
|
|
38
|
+
name,
|
|
39
|
+
location,
|
|
40
|
+
manifestLocation,
|
|
41
|
+
shrinkwrapPath: path.resolve(cwd, pkgRoot, "npm-shrinkwrap.json"),
|
|
42
|
+
lockfilePath: path.resolve(cwd, pkgRoot, "package-lock.json"),
|
|
43
|
+
};
|
|
44
|
+
await outputJson(manifestLocation, { name, version, ...pkgData });
|
|
45
|
+
if (changed) {
|
|
46
|
+
mockChangedPackages.push(pkg);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return pkg;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
const log = jest.fn();
|
|
54
|
+
context = {
|
|
55
|
+
log,
|
|
56
|
+
logger: { log },
|
|
57
|
+
stdout: new WritableStreamBuffer(),
|
|
58
|
+
stderr: new WritableStreamBuffer(),
|
|
59
|
+
};
|
|
60
|
+
mockChangedPackages = [];
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("Update lerna.json and root package.json when no package has changed", async () => {
|
|
64
|
+
expect.assertions(4);
|
|
65
|
+
const cwd = tempy.directory();
|
|
66
|
+
const npmrc = tempy.file({ name: ".npmrc" });
|
|
67
|
+
const project = await createProject(cwd, "0.0.0");
|
|
68
|
+
|
|
69
|
+
await prepare(
|
|
70
|
+
npmrc,
|
|
71
|
+
{},
|
|
72
|
+
{
|
|
73
|
+
cwd,
|
|
74
|
+
env: {},
|
|
75
|
+
stdout: context.stdout,
|
|
76
|
+
stderr: context.stderr,
|
|
77
|
+
nextRelease: { version: "1.0.0" },
|
|
78
|
+
logger: context.logger,
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Verify lerna.json has been updated
|
|
83
|
+
expect(await readJson(project.lernaPath)).toEqual(
|
|
84
|
+
expect.objectContaining({
|
|
85
|
+
version: "1.0.0",
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// Verify root package.json has been updated
|
|
90
|
+
expect(await readJson(project.manifestLocation)).toEqual(
|
|
91
|
+
expect.objectContaining({
|
|
92
|
+
version: "1.0.0",
|
|
93
|
+
})
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// Verify the logger has been called with the version updated
|
|
97
|
+
expect(context.log).toHaveBeenCalledWith(
|
|
98
|
+
"No packages changed, applying version bump on root package only"
|
|
99
|
+
);
|
|
100
|
+
expect(context.log).toHaveBeenCalledWith("Write version %s to lerna.json in %s", "1.0.0", cwd);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("Update lerna.json and root package.json when one or more package has changed", async () => {
|
|
104
|
+
expect.assertions(5);
|
|
105
|
+
const cwd = tempy.directory();
|
|
106
|
+
const npmrc = tempy.file({ name: ".npmrc" });
|
|
107
|
+
const project = await createProject(cwd, "0.0.0");
|
|
108
|
+
const pkg = await createPackage(cwd, "foo", "0.0.0", {
|
|
109
|
+
changed: true,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await prepare(
|
|
113
|
+
npmrc,
|
|
114
|
+
{},
|
|
115
|
+
{
|
|
116
|
+
cwd,
|
|
117
|
+
env: {},
|
|
118
|
+
stdout: context.stdout,
|
|
119
|
+
stderr: context.stderr,
|
|
120
|
+
nextRelease: { version: "1.0.0" },
|
|
121
|
+
logger: context.logger,
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Verify lerna.json has been updated
|
|
126
|
+
expect(await readJson(project.lernaPath)).toEqual(
|
|
127
|
+
expect.objectContaining({
|
|
128
|
+
version: "1.0.0",
|
|
129
|
+
})
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// Verify package.json has been updated
|
|
133
|
+
expect(await readJson(project.manifestLocation)).toEqual(
|
|
134
|
+
expect.objectContaining({
|
|
135
|
+
version: "1.0.0",
|
|
136
|
+
})
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
// Verify the logger has been called with the version updated
|
|
140
|
+
expect(context.log).toHaveBeenCalledWith("1 package need version bump: [ 'foo' ]");
|
|
141
|
+
expect(context.log).toHaveBeenCalledWith(
|
|
142
|
+
"Write version %s to package.json in %s",
|
|
143
|
+
"1.0.0",
|
|
144
|
+
pkg.location
|
|
145
|
+
);
|
|
146
|
+
expect(context.log).toHaveBeenCalledWith("Write version %s to lerna.json in %s", "1.0.0", cwd);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("Update package.json in changed packages", async () => {
|
|
150
|
+
expect.assertions(2);
|
|
151
|
+
const cwd = tempy.directory();
|
|
152
|
+
const npmrc = tempy.file({ name: ".npmrc" });
|
|
153
|
+
await createProject(cwd, "0.0.0");
|
|
154
|
+
const foo = await createPackage(cwd, "foo", "0.0.0", {
|
|
155
|
+
changed: true,
|
|
156
|
+
});
|
|
157
|
+
const bar = await createPackage(cwd, "bar", "0.0.0", {
|
|
158
|
+
changed: false,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await prepare(
|
|
162
|
+
npmrc,
|
|
163
|
+
{},
|
|
164
|
+
{
|
|
165
|
+
cwd,
|
|
166
|
+
env: {},
|
|
167
|
+
stdout: context.stdout,
|
|
168
|
+
stderr: context.stderr,
|
|
169
|
+
nextRelease: { version: "1.0.0" },
|
|
170
|
+
logger: context.logger,
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
// Verify foo/package.json has been updated
|
|
175
|
+
expect(await readJson(foo.manifestLocation)).toEqual({
|
|
176
|
+
name: "foo",
|
|
177
|
+
version: "1.0.0",
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Verify bar/package.json has not been updated
|
|
181
|
+
expect(await readJson(bar.manifestLocation)).toEqual({
|
|
182
|
+
name: "bar",
|
|
183
|
+
version: "0.0.0",
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("Update npm-shrinkwrap.json if present", async () => {
|
|
188
|
+
expect.assertions(2);
|
|
189
|
+
const cwd = tempy.directory();
|
|
190
|
+
const npmrc = tempy.file({ name: ".npmrc" });
|
|
191
|
+
await createProject(cwd, "0.0.0");
|
|
192
|
+
const pkg = await createPackage(cwd, "foo", "0.0.0", {
|
|
193
|
+
changed: true,
|
|
194
|
+
});
|
|
195
|
+
// Create a npm-shrinkwrap.json file
|
|
196
|
+
await execa("npm", ["shrinkwrap"], { cwd: pkg.location });
|
|
197
|
+
|
|
198
|
+
await prepare(
|
|
199
|
+
npmrc,
|
|
200
|
+
{},
|
|
201
|
+
{
|
|
202
|
+
cwd,
|
|
203
|
+
env: {},
|
|
204
|
+
stdout: context.stdout,
|
|
205
|
+
stderr: context.stderr,
|
|
206
|
+
nextRelease: { version: "1.0.0" },
|
|
207
|
+
logger: context.logger,
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
// Verify foo/package.json has been updated
|
|
212
|
+
expect(await readJson(pkg.manifestLocation)).toEqual({
|
|
213
|
+
name: "foo",
|
|
214
|
+
version: "1.0.0",
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Verify foo/npm-shrinkwrap.json has been updated
|
|
218
|
+
expect(await readJson(pkg.shrinkwrapPath)).toEqual(
|
|
219
|
+
expect.objectContaining({
|
|
220
|
+
lockfileVersion: expect.anything(),
|
|
221
|
+
name: "foo",
|
|
222
|
+
version: "1.0.0",
|
|
223
|
+
})
|
|
224
|
+
);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it("Update package-lock.json if present", async () => {
|
|
228
|
+
expect.assertions(2);
|
|
229
|
+
const cwd = tempy.directory();
|
|
230
|
+
const npmrc = tempy.file({ name: ".npmrc" });
|
|
231
|
+
await createProject(cwd, "0.0.0");
|
|
232
|
+
const pkg = await createPackage(cwd, "foo", "0.0.0", {
|
|
233
|
+
changed: true,
|
|
234
|
+
});
|
|
235
|
+
// Create a package-lock.json file
|
|
236
|
+
await execa("npm", ["install"], { cwd: pkg.location });
|
|
237
|
+
|
|
238
|
+
await prepare(
|
|
239
|
+
npmrc,
|
|
240
|
+
{},
|
|
241
|
+
{
|
|
242
|
+
cwd,
|
|
243
|
+
env: {},
|
|
244
|
+
stdout: context.stdout,
|
|
245
|
+
stderr: context.stderr,
|
|
246
|
+
nextRelease: { version: "1.0.0" },
|
|
247
|
+
logger: context.logger,
|
|
248
|
+
}
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
// Verify foo/package.json has been updated
|
|
252
|
+
expect(await readJson(pkg.manifestLocation)).toEqual({
|
|
253
|
+
name: "foo",
|
|
254
|
+
version: "1.0.0",
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Verify foo/package-lock.json has been updated
|
|
258
|
+
expect(await readJson(pkg.lockfilePath)).toEqual(
|
|
259
|
+
expect.objectContaining({
|
|
260
|
+
lockfileVersion: expect.anything(),
|
|
261
|
+
name: "foo",
|
|
262
|
+
version: "1.0.0",
|
|
263
|
+
})
|
|
264
|
+
);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it("Update package.json dependency when using exact version", async () => {
|
|
268
|
+
expect.assertions(1);
|
|
269
|
+
const cwd = tempy.directory();
|
|
270
|
+
const npmrc = tempy.file({ name: ".npmrc" });
|
|
271
|
+
await createProject(cwd, "0.0.0");
|
|
272
|
+
const foo = await createPackage(
|
|
273
|
+
cwd,
|
|
274
|
+
"foo",
|
|
275
|
+
"0.0.0",
|
|
276
|
+
{
|
|
277
|
+
changed: true,
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
dependencies: {
|
|
281
|
+
a: "0.0.0",
|
|
282
|
+
},
|
|
283
|
+
devDependencies: {
|
|
284
|
+
b: "0.0.0",
|
|
285
|
+
},
|
|
286
|
+
peerDependencies: {
|
|
287
|
+
c: "0.0.0",
|
|
288
|
+
},
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
await createPackage(cwd, "a", "0.0.0", { changed: true });
|
|
292
|
+
await createPackage(cwd, "b", "0.0.0", { changed: true });
|
|
293
|
+
await createPackage(cwd, "c", "0.0.0", { changed: true });
|
|
294
|
+
|
|
295
|
+
await prepare(
|
|
296
|
+
npmrc,
|
|
297
|
+
{},
|
|
298
|
+
{
|
|
299
|
+
cwd,
|
|
300
|
+
env: {},
|
|
301
|
+
stdout: context.stdout,
|
|
302
|
+
stderr: context.stderr,
|
|
303
|
+
nextRelease: { version: "0.0.1" },
|
|
304
|
+
logger: context.logger,
|
|
305
|
+
}
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
// Verify dependency has been updated
|
|
309
|
+
expect(await readJson(foo.manifestLocation)).toEqual({
|
|
310
|
+
name: "foo",
|
|
311
|
+
version: "0.0.1",
|
|
312
|
+
dependencies: {
|
|
313
|
+
a: "0.0.1",
|
|
314
|
+
},
|
|
315
|
+
devDependencies: {
|
|
316
|
+
b: "0.0.1",
|
|
317
|
+
},
|
|
318
|
+
peerDependencies: {
|
|
319
|
+
c: "0.0.1",
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it("Update package.json dependency when using hat", async () => {
|
|
325
|
+
expect.assertions(1);
|
|
326
|
+
const cwd = tempy.directory();
|
|
327
|
+
const npmrc = tempy.file({ name: ".npmrc" });
|
|
328
|
+
await createProject(cwd, "0.1.2");
|
|
329
|
+
const foo = await createPackage(
|
|
330
|
+
cwd,
|
|
331
|
+
"foo",
|
|
332
|
+
"0.1.2",
|
|
333
|
+
{
|
|
334
|
+
changed: true,
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
dependencies: {
|
|
338
|
+
a: "^0.1.2",
|
|
339
|
+
b: "^0.1",
|
|
340
|
+
c: "^0",
|
|
341
|
+
},
|
|
342
|
+
}
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
await createPackage(cwd, "a", "0.1.2", { changed: true });
|
|
346
|
+
await createPackage(cwd, "b", "0.1.2", { changed: true });
|
|
347
|
+
await createPackage(cwd, "c", "0.1.2", { changed: true });
|
|
348
|
+
|
|
349
|
+
await prepare(
|
|
350
|
+
npmrc,
|
|
351
|
+
{},
|
|
352
|
+
{
|
|
353
|
+
cwd,
|
|
354
|
+
env: {},
|
|
355
|
+
stdout: context.stdout,
|
|
356
|
+
stderr: context.stderr,
|
|
357
|
+
nextRelease: { version: "1.0.0" },
|
|
358
|
+
logger: context.logger,
|
|
359
|
+
}
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
// Verify dependency has been updated
|
|
363
|
+
expect(await readJson(foo.manifestLocation)).toEqual({
|
|
364
|
+
name: "foo",
|
|
365
|
+
version: "1.0.0",
|
|
366
|
+
dependencies: {
|
|
367
|
+
a: "^1.0.0",
|
|
368
|
+
b: "^1.0",
|
|
369
|
+
c: "^1",
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("Should not update other dependencies", async () => {
|
|
375
|
+
expect.assertions(1);
|
|
376
|
+
const cwd = tempy.directory();
|
|
377
|
+
const npmrc = tempy.file({ name: ".npmrc" });
|
|
378
|
+
await createProject(cwd, "0.0.0");
|
|
379
|
+
const foo = await createPackage(
|
|
380
|
+
cwd,
|
|
381
|
+
"foo",
|
|
382
|
+
"0.0.0",
|
|
383
|
+
{
|
|
384
|
+
changed: true,
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
dependencies: {
|
|
388
|
+
a: "0.0.0",
|
|
389
|
+
},
|
|
390
|
+
}
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
await prepare(
|
|
394
|
+
npmrc,
|
|
395
|
+
{},
|
|
396
|
+
{
|
|
397
|
+
cwd,
|
|
398
|
+
env: {},
|
|
399
|
+
stdout: context.stdout,
|
|
400
|
+
stderr: context.stderr,
|
|
401
|
+
nextRelease: { version: "0.0.1" },
|
|
402
|
+
logger: context.logger,
|
|
403
|
+
}
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
// Verify dependency has been updated
|
|
407
|
+
expect(await readJson(foo.manifestLocation)).toEqual({
|
|
408
|
+
name: "foo",
|
|
409
|
+
version: "0.0.1",
|
|
410
|
+
dependencies: {
|
|
411
|
+
a: "0.0.0",
|
|
412
|
+
},
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
it("Handle dependencies from root package", async () => {
|
|
417
|
+
expect.assertions(1);
|
|
418
|
+
const cwd = tempy.directory();
|
|
419
|
+
const npmrc = tempy.file({ name: ".npmrc" });
|
|
420
|
+
await createProject(cwd, "0.0.1", {
|
|
421
|
+
devDependencies: {
|
|
422
|
+
"external-dependency": "1.2.3",
|
|
423
|
+
},
|
|
424
|
+
});
|
|
425
|
+
expect(async () => {
|
|
426
|
+
await prepare(
|
|
427
|
+
npmrc,
|
|
428
|
+
{},
|
|
429
|
+
{
|
|
430
|
+
cwd,
|
|
431
|
+
env: {},
|
|
432
|
+
stdout: context.stdout,
|
|
433
|
+
stderr: context.stderr,
|
|
434
|
+
nextRelease: { version: "0.0.2" },
|
|
435
|
+
logger: context.logger,
|
|
436
|
+
}
|
|
437
|
+
);
|
|
438
|
+
}).not.toThrow();
|
|
439
|
+
});
|
package/lib/publish.js
CHANGED
|
@@ -39,12 +39,13 @@ module.exports = async (npmrc, config, pkg, context) => {
|
|
|
39
39
|
"node",
|
|
40
40
|
// prettier-ignore
|
|
41
41
|
[
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
lerna, 'publish', 'from-package',
|
|
43
|
+
'--loglevel', 'verbose',
|
|
44
|
+
'--yes',
|
|
45
|
+
'--no-verify-access', // prepare step has already verify access and lerna doesn't properly pass authentication
|
|
46
|
+
'--dist-tag', distTag,
|
|
47
|
+
'--registry', registry,
|
|
48
|
+
...legacyAuth,
|
|
48
49
|
],
|
|
49
50
|
{
|
|
50
51
|
cwd,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* eslint-env jest */
|
|
2
|
+
|
|
3
|
+
const semver = require("semver");
|
|
4
|
+
const shouldLatch = require("./should-latch");
|
|
5
|
+
|
|
6
|
+
const version = "1.0.0";
|
|
7
|
+
|
|
8
|
+
describe("latch none", () => {
|
|
9
|
+
it.each`
|
|
10
|
+
bump | result | version | next
|
|
11
|
+
${"major"} | ${false} | ${version} | ${semver.inc(version, "major")}
|
|
12
|
+
${"minor"} | ${false} | ${version} | ${semver.inc(version, "minor")}
|
|
13
|
+
${"patch"} | ${false} | ${version} | ${semver.inc(version, "patch")}
|
|
14
|
+
${"prerelease"} | ${false} | ${version} | ${semver.inc(version, "prerelease")}
|
|
15
|
+
`("should return $result when version bump is $bump ($version -> $next)", ({ result, next }) => {
|
|
16
|
+
expect.assertions(1);
|
|
17
|
+
expect(shouldLatch(next, "none")).toBe(result);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe("latch major", () => {
|
|
22
|
+
it.each`
|
|
23
|
+
bump | result | version | next
|
|
24
|
+
${"major"} | ${true} | ${version} | ${semver.inc(version, "major")}
|
|
25
|
+
${"minor"} | ${false} | ${version} | ${semver.inc(version, "minor")}
|
|
26
|
+
${"patch"} | ${false} | ${version} | ${semver.inc(version, "patch")}
|
|
27
|
+
${"prerelease"} | ${false} | ${version} | ${semver.inc(version, "prerelease")}
|
|
28
|
+
`("should return $result when version bump is $bump ($version -> $next)", ({ result, next }) => {
|
|
29
|
+
expect.assertions(1);
|
|
30
|
+
expect(shouldLatch(next, "major")).toBe(result);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("latch minor", () => {
|
|
35
|
+
it.each`
|
|
36
|
+
bump | result | version | next
|
|
37
|
+
${"major"} | ${true} | ${version} | ${semver.inc(version, "major")}
|
|
38
|
+
${"minor"} | ${true} | ${version} | ${semver.inc(version, "minor")}
|
|
39
|
+
${"patch"} | ${false} | ${version} | ${semver.inc(version, "patch")}
|
|
40
|
+
${"prerelease"} | ${false} | ${version} | ${semver.inc(version, "prerelease")}
|
|
41
|
+
`("should return $result when version bump is $bump ($version -> $next)", ({ result, next }) => {
|
|
42
|
+
expect.assertions(1);
|
|
43
|
+
expect(shouldLatch(next, "minor")).toBe(result);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("latch patch", () => {
|
|
48
|
+
it.each`
|
|
49
|
+
bump | result | version | next
|
|
50
|
+
${"major"} | ${true} | ${version} | ${semver.inc(version, "major")}
|
|
51
|
+
${"minor"} | ${true} | ${version} | ${semver.inc(version, "minor")}
|
|
52
|
+
${"patch"} | ${true} | ${version} | ${semver.inc(version, "patch")}
|
|
53
|
+
${"prerelease"} | ${false} | ${version} | ${semver.inc(version, "prerelease")}
|
|
54
|
+
`("should return $result when version bump is $bump ($version -> $next)", ({ result, next }) => {
|
|
55
|
+
expect.assertions(1);
|
|
56
|
+
expect(shouldLatch(next, "patch")).toBe(result);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* eslint-env jest */
|
|
2
|
+
|
|
3
|
+
jest.mock("execa");
|
|
4
|
+
|
|
5
|
+
const execa = require("execa");
|
|
6
|
+
const verifyGit = require("./verify-git");
|
|
7
|
+
|
|
8
|
+
it("should return error if working copy is dirty", async () => {
|
|
9
|
+
expect.assertions(2);
|
|
10
|
+
execa.mockImplementation(() => ({ stdout: " M file.js\n" }));
|
|
11
|
+
const errors = await verifyGit({});
|
|
12
|
+
expect(errors).toHaveLength(1);
|
|
13
|
+
expect(errors[0]).toMatchObject({
|
|
14
|
+
code: "EDIRTYWC",
|
|
15
|
+
details: `The git working copy must be clean before releasing:
|
|
16
|
+
|
|
17
|
+
M file.js
|
|
18
|
+
`,
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should return error when working copy has mixed dirty and untracked", async () => {
|
|
23
|
+
expect.assertions(2);
|
|
24
|
+
execa.mockImplementation(() => ({ stdout: " M file.js\n?? file.c" }));
|
|
25
|
+
const errors = await verifyGit({});
|
|
26
|
+
expect(errors).toHaveLength(1);
|
|
27
|
+
expect(errors[0]).toMatchObject({
|
|
28
|
+
code: "EDIRTYWC",
|
|
29
|
+
details: `The git working copy must be clean before releasing:
|
|
30
|
+
|
|
31
|
+
M file.js
|
|
32
|
+
?? file.c
|
|
33
|
+
`,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should ignore untracked files", async () => {
|
|
38
|
+
expect.assertions(1);
|
|
39
|
+
execa.mockImplementation(() => ({ stdout: "?? file.js\n" }));
|
|
40
|
+
const errors = await verifyGit({});
|
|
41
|
+
expect(errors).toHaveLength(0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should not return error if working copy is clean", async () => {
|
|
45
|
+
expect.assertions(1);
|
|
46
|
+
execa.mockImplementation(() => ({ stdout: "" }));
|
|
47
|
+
const errors = await verifyGit({});
|
|
48
|
+
expect(errors).toHaveLength(0);
|
|
49
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "semantic-release-lerna",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "semantic-release plugin to publish lerna monorepo packages to npm",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"npm",
|
|
@@ -51,42 +51,41 @@
|
|
|
51
51
|
"@lerna/package": "^4.0.0",
|
|
52
52
|
"@lerna/package-graph": "^4.0.0",
|
|
53
53
|
"@lerna/project": "^4.0.0",
|
|
54
|
-
"@semantic-release/error": "^
|
|
55
|
-
"@semantic-release/release-notes-generator": "^
|
|
56
|
-
"aggregate-error": "^3.
|
|
57
|
-
"conventional-changelog-writer": "^
|
|
54
|
+
"@semantic-release/error": "^3.0.0",
|
|
55
|
+
"@semantic-release/release-notes-generator": "^10.0.0",
|
|
56
|
+
"aggregate-error": "^3.1.0",
|
|
57
|
+
"conventional-changelog-writer": "^5.0.0",
|
|
58
58
|
"conventional-commits-filter": "^2.0.0",
|
|
59
59
|
"conventional-commits-parser": "^3.2.0",
|
|
60
60
|
"debug": "^4.3.0",
|
|
61
61
|
"execa": "^5.0.0",
|
|
62
62
|
"get-stream": "^6.0.0",
|
|
63
|
-
"into-stream": "^
|
|
63
|
+
"into-stream": "^6.0.0",
|
|
64
64
|
"read-pkg-up": "^7.0.0",
|
|
65
|
+
"semver": "^7.0.0",
|
|
65
66
|
"tempy": "^1.0.0",
|
|
66
67
|
"write-json-file": "^4.0.0"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
69
|
-
"@html-validate/eslint-config": "
|
|
70
|
-
"@html-validate/eslint-config-jest": "
|
|
71
|
-
"@html-validate/prettier-config": "
|
|
72
|
-
"@semantic-release/npm": "
|
|
73
|
-
"@types/jest": "
|
|
74
|
-
"codecov": "3.8.
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"jest": "26.6.3",
|
|
70
|
+
"@html-validate/eslint-config": "5.3.1",
|
|
71
|
+
"@html-validate/eslint-config-jest": "5.3.1",
|
|
72
|
+
"@html-validate/prettier-config": "2.0.0",
|
|
73
|
+
"@semantic-release/npm": "9.0.0",
|
|
74
|
+
"@types/jest": "27.4.0",
|
|
75
|
+
"codecov": "3.8.3",
|
|
76
|
+
"fs-extra": "10.0.0",
|
|
77
|
+
"got": "11.8.3",
|
|
78
|
+
"jest": "27.4.7",
|
|
79
79
|
"lerna": "4.0.0",
|
|
80
|
-
"prettier": "
|
|
81
|
-
"semantic-release": "
|
|
82
|
-
"semver": "7.3.4",
|
|
80
|
+
"prettier": "2.5.1",
|
|
81
|
+
"semantic-release": "19.0.2",
|
|
83
82
|
"stream-buffers": "3.0.2",
|
|
84
|
-
"verdaccio": "4.
|
|
83
|
+
"verdaccio": "5.4.0"
|
|
85
84
|
},
|
|
86
85
|
"peerDependencies": {
|
|
87
86
|
"@semantic-release/npm": ">= 7",
|
|
88
87
|
"lerna": "^3.2 || ^4",
|
|
89
|
-
"semantic-release": ">=15.0.0 <
|
|
88
|
+
"semantic-release": ">=15.0.0 <20.0.0"
|
|
90
89
|
},
|
|
91
90
|
"engines": {
|
|
92
91
|
"node": ">= 12.10"
|
|
@@ -96,7 +95,7 @@
|
|
|
96
95
|
},
|
|
97
96
|
"renovate": {
|
|
98
97
|
"extends": [
|
|
99
|
-
"
|
|
98
|
+
"gitlab>html-validate/renovate-config"
|
|
100
99
|
]
|
|
101
100
|
}
|
|
102
101
|
}
|