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

fix(deps): upgrading pacote & npm-packlist to v7 requires arborist tree #367

Merged
merged 8 commits into from
Oct 14, 2022
3 changes: 3 additions & 0 deletions __fixtures__/normal-workspace-name-prefixed/lerna.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"version": "1.0.0"
}
3 changes: 3 additions & 0 deletions __fixtures__/normal-workspace-name-prefixed/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "my-workspace"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "@my-workspace/package-1",
"version": "1.0.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "@my-workspace/package-2",
"version": "1.0.0",
"dependencies": {
"@my-workspace/package-1": "^1.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "@my-workspace/package-3",
"version": "1.0.0",
"peerDependencies": {
"@my-workspace/package-2": "^1.0.0"
},
"devDependencies": {
"@my-workspace/package-2": "^1.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "@my-workspace/package-4",
"version": "1.0.0",
"dependencies": {
"@my-workspace/package-1": "^0.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "@my-workspace/package-5",
"dependencies": {
"@my-workspace/package-1": "^1.0.0"
},
"optionalDependencies": {
"@my-workspace/package-3": "^1.0.0"
},
"private": true,
"version": "1.0.0"
}
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
"@types/write-file-atomic": "^4.0.0",
"@types/write-json-file": "^3.2.1",
"@types/write-pkg": "^4.0.0",
"npm-registry-fetch": "^13.3.1",
"npm-registry-fetch": "^14.0.0",
"yargs": "^17.6.0",
"yargs-parser": "^21.1.1"
},
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/utils/pulse-till-done.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import log from 'npmlog';
let pulsers = 0;
let pulse: any;

function pulseStart(prefix: string | Promise<string>) {
function pulseStart(prefix: string | Promise<unknown>) {
pulsers += 1;

if (pulsers > 1) {
Expand All @@ -23,7 +23,7 @@ function pulseStop() {
clearInterval(pulse);
}

export function pulseTillDone(prefix: string | Promise<string>, promise?: Promise<any> | string) {
export function pulseTillDone(prefix: string | Promise<unknown>, promise?: Promise<any> | string) {
if (!promise) {
/* eslint-disable no-param-reassign */
promise = prefix;
Expand Down
7 changes: 4 additions & 3 deletions packages/publish/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"dependencies": {
"@lerna-lite/core": "workspace:*",
"@lerna-lite/version": "workspace:*",
"@npmcli/arborist": "^5.6.2",
"byte-size": "^7.0.1",
"chalk": "^4.1.2",
"columnify": "^1.6.0",
Expand All @@ -41,12 +42,12 @@
"libnpmaccess": "^6.0.4",
"libnpmpublish": "^6.0.5",
"npm-package-arg": "^9.1.2",
"npm-packlist": "^6.0.1",
"npm-registry-fetch": "^13.3.1",
"npm-packlist": "^7.0.0",
"npm-registry-fetch": "^14.0.0",
"npmlog": "^6.0.2",
"p-map": "^4.0.0",
"p-pipe": "^3.1.0",
"pacote": "^13.6.2",
"pacote": "^15.0.0",
"path": "^0.12.7",
"pify": "^5.0.0",
"read-package-json": "^5.0.2",
Expand Down
56 changes: 50 additions & 6 deletions packages/publish/src/__tests__/publish-command.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,51 @@ describe('PublishCommand', () => {
);
});

it('publishes changed packages including workspace name prefix', async () => {
const testDir = await initFixture('normal-workspace-name-prefixed');

await new PublishCommand(createArgv(testDir));
// await lernaPublish(testDir)();

expect(promptConfirmation).toHaveBeenLastCalledWith('Are you sure you want to publish these packages?');
expect((packDirectory as any).registry).toMatchInlineSnapshot(`
Set {
"@my-workspace/package-1",
"@my-workspace/package-4",
"@my-workspace/package-2",
"@my-workspace/package-3",
}
`);
expect((npmPublish as typeof npmPublishMock).registry).toMatchInlineSnapshot(`
Map {
"@my-workspace/package-1" => "latest",
"@my-workspace/package-4" => "latest",
"@my-workspace/package-2" => "latest",
"@my-workspace/package-3" => "latest",
}
`);
expect((npmPublish as typeof npmPublishMock).order()).toEqual([
'@my-workspace/package-1',
'@my-workspace/package-4',
'@my-workspace/package-2',
'@my-workspace/package-3',
// @my-workspace/package-5 is private
]);
expect(npmDistTag.remove).not.toHaveBeenCalled();
expect(npmDistTag.add).not.toHaveBeenCalled();

expect(getNpmUsername).not.toHaveBeenCalled();
expect(verifyNpmPackageAccess).not.toHaveBeenCalled();

expect(gitCheckout).toHaveBeenCalledWith(
// the list of changed files has been asserted many times already
expect.any(Array),
{ granularPathspec: true },
{ cwd: testDir },
undefined
);
});

it('publishes changed independent packages', async () => {
const testDir = await initFixture('independent');

Expand Down Expand Up @@ -396,16 +441,15 @@ describe('PublishCommand', () => {
});

describe('--registry', () => {
it('passes registry to npm commands', async () => {
const testDir = await initFixture('normal');
it('passes registry to npm commands that also includes workspace in the name prefix', async () => {
const testDir = await initFixture('normal-workspace-name-prefixed');
const registry = 'https://my-private-registry';

// await lernaPublish(testDir)("--registry", registry);
await new PublishCommand(createArgv(testDir, '--registry', registry));
await lernaPublish(testDir)('--registry', registry);

expect(npmPublish).toHaveBeenCalledWith(
expect.objectContaining({ name: 'package-1' }),
'/TEMP_DIR/package-1-MOCKED.tgz',
expect.objectContaining({ name: '@my-workspace/package-1' }),
'/TEMP_DIR/@my-workspace/package-1-MOCKED.tgz',
expect.objectContaining({ registry }),
expect.objectContaining({ otp: undefined })
);
Expand Down
28 changes: 28 additions & 0 deletions packages/publish/src/__tests__/publish-from-git.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,34 @@ describe('publish from-git', () => {
]);
});

it('publishes tagged packages that includes workspace in the name prefix', async () => {
const cwd = await initFixture('normal-workspace-name-prefixed');

await gitTag(cwd, 'v1.0.0');
await new PublishCommand(createArgv(cwd, '--bump', 'from-git'));

// called from chained describeRef()
expect(throwIfUncommitted).toHaveBeenCalled();

expect(promptConfirmation).toHaveBeenLastCalledWith('Are you sure you want to publish these packages?');
expect((logOutput as any).logged()).toMatch('Found 4 packages to publish:');
expect((npmPublish as typeof npmPublishMock).order()).toEqual([
'@my-workspace/package-1',
'@my-workspace/package-4',
'@my-workspace/package-2',
'@my-workspace/package-3',
// @my-workspace/package-5 is private
]);

// check that @my-workspace/package-1 is properly escaped in the tarball tgz name
expect(npmPublish).toHaveBeenCalledWith(
expect.objectContaining({ name: '@my-workspace/package-1', version: '1.0.0' }),
expect.stringContaining('my-workspace-package-1-1.0.0.tgz'),
expect.any(Object),
expect.any(Object)
);
});

it('publishes tagged packages in dry-run mode', async () => {
const cwd = await initFixture('normal');

Expand Down
70 changes: 34 additions & 36 deletions packages/publish/src/lib/pack-directory.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Arborist from '@npmcli/arborist';
import path from 'path';
import packlist from 'npm-packlist';
import log from 'npmlog';
Expand All @@ -14,7 +15,7 @@ import { Tarball } from '../models';
* @param {string} dir to pack
* @param {PackConfig} options
*/
export function packDirectory(_pkg: Package, dir: string, options: PackConfig) {
export async function packDirectory(_pkg: Package, dir: string, options: PackConfig) {
const pkg = Package.lazy(_pkg, dir);
const opts: LifecycleConfig = {
// @ts-ignore
Expand All @@ -24,51 +25,48 @@ export function packDirectory(_pkg: Package, dir: string, options: PackConfig) {

opts.log.verbose('pack-directory', path.relative('.', pkg.contents));

let chain: Promise<any> = Promise.resolve();

if (opts.ignorePrepublish !== true) {
chain = chain.then(() => runLifecycle(pkg, 'prepublish', opts));
await runLifecycle(pkg, 'prepublish', opts);
}

chain = chain.then(() => runLifecycle(pkg, 'prepare', opts));
await runLifecycle(pkg, 'prepare', opts);

if (opts.lernaCommand === 'publish') {
opts.stdio = 'inherit';
chain = chain.then(() => pkg.refresh());
chain = chain.then(() => runLifecycle(pkg, 'prepublishOnly', opts));
chain = chain.then(() => pkg.refresh());
await pkg.refresh();
await runLifecycle(pkg, 'prepublishOnly', opts);
await pkg.refresh();
}

chain = chain.then(() => runLifecycle(pkg, 'prepack', opts));
chain = chain.then(() => pkg.refresh());
chain = chain.then(() => packlist({ path: pkg.contents }));
chain = chain.then((files: string[]) =>
tar.create(
{
cwd: pkg.contents,
prefix: 'package/',
portable: true,
// Provide a specific date in the 1980s for the benefit of zip,
// which is confounded by files dated at the Unix epoch 0.
mtime: new Date('1985-10-26T08:15:00.000Z'),
gzip: true,
},
// NOTE: node-tar does some Magic Stuff depending on prefixes for files
// specifically with @ signs, so we just neutralize that one
// and any such future 'features' by prepending `./`
files.map((f) => `./${f}`)
)
);
chain = chain.then((stream: DataView & Readable) => tempWrite(stream, getTarballName(pkg)));
chain = chain.then((tarFilePath) =>
getPacked(pkg, tarFilePath).then((packed: Tarball) =>
Promise.resolve()
.then(() => runLifecycle(pkg, 'postpack', opts))
.then(() => packed)
)
await runLifecycle(pkg, 'prepack', opts);
await pkg.refresh();

const arborist = new Arborist({ path: pkg.contents });
const tree = await arborist.loadActual();
const files: string[] = await packlist(tree);
const stream: DataView & Readable = tar.create(
{
cwd: pkg.contents,
prefix: 'package/',
portable: true,
// Provide a specific date in the 1980s for the benefit of zip,
// which is confounded by files dated at the Unix epoch 0.
mtime: new Date('1985-10-26T08:15:00.000Z'),
gzip: true,
},
// NOTE: node-tar does some Magic Stuff depending on prefixes for files
// specifically with @ signs, so we just neutralize that one
// and any such future 'features' by prepending `./`
files.map((f) => `./${f}`)
);

return chain;
const tarFilePath = await tempWrite(stream, getTarballName(pkg));

return getPacked(pkg, tarFilePath).then((packed: Tarball) =>
Promise.resolve()
.then(() => runLifecycle(pkg, 'postpack', opts))
.then(() => packed)
);
}

function getTarballName(pkg: Package) {
Expand Down