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(publish): add --summary-file option #2653

Merged
merged 15 commits into from Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from 10 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
29 changes: 27 additions & 2 deletions commands/publish/README.md
Expand Up @@ -65,6 +65,7 @@ This is useful when a previous `lerna publish` failed to publish all packages to
- [`--tag-version-prefix`](#--tag-version-prefix)
- [`--temp-tag`](#--temp-tag)
- [`--yes`](#--yes)
- [`--summary-file <dir>`](#--summary-file)

### `--canary`

Expand Down Expand Up @@ -118,11 +119,10 @@ This option can be used to publish a [`prerelease`](http://carrot.is/coding/npm_

> Note: the `latest` tag is the one that is used when a user runs `npm install my-package`.
> To install a different tag, a user can run `npm install my-package@prerelease`.
>

### `--force-publish`

To be used with [`--canary`](#--canary) to publish a canary version of all packages in your monorepo. This flag can be helpful when you need to make canary releases of packages beyond what was changed in the most recent commit.
To be used with [`--canary`](#--canary) to publish a canary version of all packages in your monorepo. This flag can be helpful when you need to make canary releases of packages beyond what was changed in the most recent commit.

```
lerna publish --canary --force-publish
Expand Down Expand Up @@ -303,6 +303,31 @@ lerna publish --canary --yes
When run with this flag, `lerna publish` will skip all confirmation prompts.
Useful in [Continuous integration (CI)](https://en.wikipedia.org/wiki/Continuous_integration) to automatically answer the publish confirmation prompt.

### `--summary-file`

```sh
# Will create a summary file in the root directory ./lerna-publish-summary.json
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
lerna publish --canary --yes --summary-file
# Will create a summary file in the root directory ./some/other/dir/lerna-publish-summary.json
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
lerna publish --canary --yes --summary-file ./some/other/dir

```

When run with this flag, a json summary report will be generated after all packages have been successfully published (see below for an example).

```json
[
{
"packageName": "package1",
"version": "v1.0.1-alpha"
},
{
"packageName": "package2",
"version": "v2.0.1-alpha"
}
]
```

## Deprecated Options

### `--no-verify-access`
Expand Down
29 changes: 29 additions & 0 deletions commands/publish/__tests__/publish-command.test.js
Expand Up @@ -34,6 +34,8 @@ const initFixture = require("@lerna-test/helpers").initFixtureFactory(__dirname)
const path = require("path");
const fs = require("fs-extra");

const fsmain = require("fs");

// file under test
const lernaPublish = require("@lerna-test/helpers").commandRunner(require("../command"));

Expand Down Expand Up @@ -360,6 +362,33 @@ Map {
});
});

describe("--summary-file", () => {
it("skips creating the summary file", async () => {
const cwd = await initFixture("normal");
const fsSpy = jest.spyOn(fs, "writeFileSync");
await lernaPublish(cwd);

expect(fsSpy).not.toHaveBeenCalled();
});

it("creates the summary file", async () => {
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
const cwd = await initFixture("normal");
const fsSpy = jest.spyOn(fsmain, "writeFileSync");
await lernaPublish(cwd)("--summary-file", "./outputs");

const expectedJsonResponse = [
{ packageName: "package-1", version: "1.0.1" },
{ packageName: "package-2", version: "1.0.1" },
{ packageName: "package-3", version: "1.0.1" },
{ packageName: "package-4", version: "1.0.1" },
];
expect(fsSpy).toHaveBeenCalled();
expect(fsSpy).toHaveBeenCalledWith(
"./outputs/lerna-publish-summary.json",
JSON.stringify(expectedJsonResponse)
);
});
});
describe("--verify-access", () => {
it("publishes packages after verifying the user's access to each package", async () => {
const testDir = await initFixture("normal");
Expand Down
5 changes: 5 additions & 0 deletions commands/publish/command.js
Expand Up @@ -110,6 +110,11 @@ exports.builder = (yargs) => {
describe: "Verify package read-write access for current npm user.",
type: "boolean",
},
"summary-file": {
// generate lerna publish json output.
describe: "A json summary report will be generated after all packages have been successfully published",
type: "string",
HamishBuckmaster marked this conversation as resolved.
Show resolved Hide resolved
},
};

composeVersionOptions(yargs);
Expand Down
26 changes: 24 additions & 2 deletions commands/publish/index.js
@@ -1,6 +1,7 @@
"use strict";

const os = require("os");
const fs = require("fs");
const path = require("path");
const crypto = require("crypto");
const pMap = require("p-map");
Expand Down Expand Up @@ -256,10 +257,31 @@ class PublishCommand extends Command {

return chain.then(() => {
const count = this.packagesToPublish.length;
const message = this.packagesToPublish.map((pkg) => ` - ${pkg.name}@${pkg.version}`);

output("Successfully published:");
output(message.join(os.EOL));

if (this.options.summaryFile) {
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
// create a json object and output it to a file location.
const filePath = this.options.summaryFile
? `${this.options.summaryFile}/lerna-publish-summary.json`
: "./lerna-publish-summary.json";
const jsonObject = this.packagesToPublish.map((pkg) => {
return {
packageName: pkg.name,
version: pkg.version,
};
});
output(jsonObject);
try {
fs.writeFileSync(filePath, JSON.stringify(jsonObject));
output("Publish summary created: ", filePath);
} catch (error) {
output("Failed to create the summary report", error);
}
} else {
const message = this.packagesToPublish.map((pkg) => ` - ${pkg.name}@${pkg.version}`);
output(message.join(os.EOL));
}

this.logger.success("published", "%d %s", count, count === 1 ? "package" : "packages");
});
Expand Down
7 changes: 7 additions & 0 deletions core/lerna/schemas/lerna-schema.json
Expand Up @@ -874,6 +874,9 @@
},
"continueIfNoMatch": {
"$ref": "#/$defs/filters/continueIfNoMatch"
},
"summaryFile": {
"$ref": "#/$defs/filters/summaryFile"
}
}
},
Expand Down Expand Up @@ -1487,6 +1490,10 @@
"continueIfNoMatch": {
"type": "boolean",
"description": "Don't fail if no package is matched."
},
"summaryFile": {
"type": "string",
"description": "A json summary report will be generated after all packages have been successfully published."
JamesHenry marked this conversation as resolved.
Show resolved Hide resolved
}
},
"commandOptions": {
Expand Down