Skip to content

Commit

Permalink
feat(publish): add --summary-file option (#2653)
Browse files Browse the repository at this point in the history
  • Loading branch information
HamishBuckmaster committed Dec 13, 2022
1 parent 2517ffb commit 027d943
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 4 deletions.
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, i.e. `./lerna-publish-summary.json`
lerna publish --canary --yes --summary-file
# Will create a summary file in the provided directory, i.e. `./some/other/dir/lerna-publish-summary.json`
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
47 changes: 47 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,51 @@ 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 within the provided directory", async () => {
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)
);
});

it("creates the summary file at the root when no custom directory is provided", async () => {
const cwd = await initFixture("normal");
const fsSpy = jest.spyOn(fsmain, "writeFileSync");
await lernaPublish(cwd)("--summary-file");

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(
"./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
6 changes: 6 additions & 0 deletions commands/publish/command.js
Expand Up @@ -110,6 +110,12 @@ exports.builder = (yargs) => {
describe: "Verify package read-write access for current npm user.",
type: "boolean",
},
"summary-file": {
// generate lerna publish json output.
describe:
"Generate a json summary report after all packages have been successfully published, you can pass an optional path for where to save the file.",
type: "string",
},
};

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 !== undefined) {
// 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": "Generate a json summary report after all packages have been successfully published, you can pass an optional path for where to save the file."
}
},
"commandOptions": {
Expand Down

0 comments on commit 027d943

Please sign in to comment.