Skip to content

Commit

Permalink
feat(publish): add --summary-file option (#428)
Browse files Browse the repository at this point in the history
- Outputs the packages and versions from publishing to a JSON file.
  • Loading branch information
ghiscoding committed Dec 13, 2022
1 parent c83ac76 commit 3de55ef
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 1 deletion.
7 changes: 7 additions & 0 deletions packages/cli/schemas/lerna-schema.json
Expand Up @@ -443,6 +443,9 @@
},
"continueIfNoMatch": {
"$ref": "#/$defs/filters/continueIfNoMatch"
},
"summaryFile": {
"$ref": "#/$defs/commandOptions/publish/summaryFile"
}
}
},
Expand Down Expand Up @@ -1281,6 +1284,10 @@
"type": "boolean",
"description": "During `lerna publish`, when true, do not verify package read-write access for current npm user."
},
"summaryFile": {
"anyOf": [{ "type": "string" }, { "type": "boolean" }],
"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."
},
"verifyAccess": {
"type": "boolean",
"description": "During `lerna publish`, when true, verify package read-write access for current npm user."
Expand Down
6 changes: 6 additions & 0 deletions packages/cli/src/cli-commands/cli-publish-commands.ts
Expand Up @@ -127,6 +127,12 @@ export default {
describe: 'Do not 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',
},
'verify-access': {
describe: 'Verify package read-write access for current npm user.',
type: 'boolean',
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/models/command-options.ts
Expand Up @@ -168,6 +168,9 @@ export interface PublishCommandOption extends VersionCommandOption {
/** Do not verify package read-write access for current npm user. */
noVerifyAccess?: boolean;

/** Generate a json summary report after all packages have been successfully published, you can pass an optional path for where to save the file. */
summaryFile?: boolean | string;

/** proxy for `--no-verify-access` */
verifyAccess?: boolean;

Expand Down
25 changes: 25 additions & 0 deletions packages/publish/README.md
Expand Up @@ -89,6 +89,7 @@ This is useful when a previous `lerna publish` failed to publish all packages to
- [`--registry <url>`](#--registry-url)
- [`--tag-version-prefix`](#--tag-version-prefix)
- [`--temp-tag`](#--temp-tag)
- [`--summary-file <dir>`](#--summary-file)
- [`--verify-access`](#--verify-access)
- [`--yes`](#--yes)
- [`publishConfig` Overrides](#publishconfig-overrides)
Expand Down Expand Up @@ -349,6 +350,30 @@ new version(s) to the dist-tag configured by [`--dist-tag`](#--dist-tag-tag) (de
This is not generally necessary, as lerna will publish packages in topological
order (all dependencies before dependents) by default.

### `--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"
}
]
```

### `--verify-access`

Historically, `lerna` attempted to fast-fail on authorization/authentication issues by performing some preemptive npm API requests using the given token. These days, however, there are multiple types of tokens that npm supports and they have varying levels of access rights, so there is no one-size fits all solution for this preemptive check and it is more appropriate to allow requests to npm to simply fail with appropriate errors for the given token. For this reason, the legacy `--verify-access` behavior is disabled by default and will likely be removed in a future major version.
Expand Down
41 changes: 41 additions & 0 deletions packages/publish/src/__tests__/publish-command.spec.ts
Expand Up @@ -49,6 +49,7 @@ jest.mock('../lib/pack-directory', () => jest.requireActual('../lib/__mocks__/pa
jest.mock('../lib/git-checkout');

import fs from 'fs-extra';
import fsmain from 'fs';
import path from 'path';

// helpers
Expand Down Expand Up @@ -493,6 +494,46 @@ describe('PublishCommand', () => {
});
});

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
25 changes: 24 additions & 1 deletion packages/publish/src/publish-command.ts
@@ -1,4 +1,5 @@
import chalk from 'chalk';
import fs from 'fs';
import os from 'os';
import path from 'path';
import crypto from 'crypto';
Expand Down Expand Up @@ -296,7 +297,29 @@ export class PublishCommand extends Command<PublishCommandOption> {
const message: string[] = this.packagesToPublish?.map((pkg) => ` - ${pkg.name}@${pkg.version}`) ?? [];

logOutput('Successfully published:');
logOutput(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,
};
});
logOutput(jsonObject);
try {
fs.writeFileSync(filePath, JSON.stringify(jsonObject));
logOutput('Publish summary created: ', filePath);
} catch (error) {
logOutput('Failed to create the summary report', error);
}
} else {
const message = this.packagesToPublish.map((pkg) => ` - ${pkg.name}@${pkg.version}`);
logOutput(message.join(os.EOL));
}

this.logger.success('published', '%d %s', count, count === 1 ? 'package' : 'packages');
}
Expand Down

0 comments on commit 3de55ef

Please sign in to comment.