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 #428

Merged
merged 1 commit into from Dec 13, 2022
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
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