diff --git a/__fixtures__/lockfile-leaf-v2/lerna.json b/__fixtures__/lockfile-leaf-v2/lerna.json new file mode 100644 index 00000000..688e9398 --- /dev/null +++ b/__fixtures__/lockfile-leaf-v2/lerna.json @@ -0,0 +1,3 @@ +{ + "version": "1.0.0" +} \ No newline at end of file diff --git a/__fixtures__/lockfile-leaf-v2/package.json b/__fixtures__/lockfile-leaf-v2/package.json new file mode 100644 index 00000000..e012aed1 --- /dev/null +++ b/__fixtures__/lockfile-leaf-v2/package.json @@ -0,0 +1,5 @@ +{ + "name": "leaf-lockfile", + "version": "0.0.0-lerna", + "private": true +} \ No newline at end of file diff --git a/__fixtures__/lockfile-leaf-v2/packages/package-1/package-lock.json b/__fixtures__/lockfile-leaf-v2/packages/package-1/package-lock.json new file mode 100644 index 00000000..2f6bdfb9 --- /dev/null +++ b/__fixtures__/lockfile-leaf-v2/packages/package-1/package-lock.json @@ -0,0 +1,27 @@ +{ + "name": "package-1", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "package-1", + "version": "1.0.0", + "dependencies": { + "tiny-tarball": "^1.0.0" + } + }, + "node_modules/tiny-tarball": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tiny-tarball/-/tiny-tarball-1.0.0.tgz", + "integrity": "sha1-u/EC1a5zr+LFUyleD7AiMCFvZbE=" + } + }, + "dependencies": { + "tiny-tarball": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tiny-tarball/-/tiny-tarball-1.0.0.tgz", + "integrity": "sha1-u/EC1a5zr+LFUyleD7AiMCFvZbE=" + } + } +} \ No newline at end of file diff --git a/__fixtures__/lockfile-leaf-v2/packages/package-1/package.json b/__fixtures__/lockfile-leaf-v2/packages/package-1/package.json new file mode 100644 index 00000000..439cea86 --- /dev/null +++ b/__fixtures__/lockfile-leaf-v2/packages/package-1/package.json @@ -0,0 +1,7 @@ +{ + "name": "package-1", + "version": "1.0.0", + "dependencies": { + "tiny-tarball": "^1.0.0" + } +} \ No newline at end of file diff --git a/__fixtures__/lockfile-version2/lerna.json b/__fixtures__/lockfile-version2/lerna.json new file mode 100644 index 00000000..d6d55873 --- /dev/null +++ b/__fixtures__/lockfile-version2/lerna.json @@ -0,0 +1,3 @@ +{ + "version": "2.3.4" +} \ No newline at end of file diff --git a/__fixtures__/lockfile-version2/package-lock.json b/__fixtures__/lockfile-version2/package-lock.json new file mode 100644 index 00000000..51711ea4 --- /dev/null +++ b/__fixtures__/lockfile-version2/package-lock.json @@ -0,0 +1,55 @@ +{ + "name": "my-workspace", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "my-workspace", + "license": "MIT", + "workspaces": [ + "./packages/package-1", + "./packages/package-2" + ] + }, + "node_modules/package-1": { + "resolved": "packages/package-1", + "link": true + }, + "node_modules/package-2": { + "resolved": "packages/package-2", + "link": true + }, + "packages/package-1": { + "name": "@my-workspace/package-1", + "version": "2.3.4", + "license": "MIT", + "tiny-tarball": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tiny-tarball/-/tiny-tarball-1.0.0.tgz", + "integrity": "sha1-u/EC1a5zr+LFUyleD7AiMCFvZbE=" + } + }, + "packages/package-2": { + "name": "@my-workspace/package-2", + "version": "2.3.4", + "license": "MIT", + "dependencies": { + "@my-workspace/package-1": "^2.3.4" + } + } + }, + "dependencies": { + "@my-workspace/package-1": { + "version": "file:packages/package-1", + "requires": { + "tiny-tarball": "^1.0.0" + } + }, + "@my-workspace/package-2": { + "version": "file:packages/package-2", + "requires": { + "@my-workspace/package-1": "^2.3.4" + } + } + } +} \ No newline at end of file diff --git a/__fixtures__/lockfile-version2/package.json b/__fixtures__/lockfile-version2/package.json new file mode 100644 index 00000000..1564259e --- /dev/null +++ b/__fixtures__/lockfile-version2/package.json @@ -0,0 +1,5 @@ +{ + "name": "my-workspace", + "version": "0.0.0-lerna", + "private": true +} \ No newline at end of file diff --git a/__fixtures__/lockfile-version2/packages/package-1/package.json b/__fixtures__/lockfile-version2/packages/package-1/package.json new file mode 100644 index 00000000..a242925a --- /dev/null +++ b/__fixtures__/lockfile-version2/packages/package-1/package.json @@ -0,0 +1,7 @@ +{ + "name": "@my-workspace/package-1", + "version": "2.3.4", + "dependencies": { + "tiny-tarball": "^2.3.4" + } +} \ No newline at end of file diff --git a/__fixtures__/lockfile-version2/packages/package-2/package.json b/__fixtures__/lockfile-version2/packages/package-2/package.json new file mode 100644 index 00000000..78c58f5e --- /dev/null +++ b/__fixtures__/lockfile-version2/packages/package-2/package.json @@ -0,0 +1,7 @@ +{ + "name": "@my-workspace/package-2", + "version": "2.3.4", + "dependencies": { + "@my-workspace/package-1": "^2.3.4" + } +} \ No newline at end of file diff --git a/packages/version/src/__tests__/__snapshots__/update-lockfile-version.spec.js.snap b/packages/version/src/__tests__/__snapshots__/update-lockfile-version.spec.js.snap new file mode 100644 index 00000000..cfb6e86a --- /dev/null +++ b/packages/version/src/__tests__/__snapshots__/update-lockfile-version.spec.js.snap @@ -0,0 +1,59 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`npm modern lock file updateModernLockfileVersion v2 in project root 1`] = ` +Object { + "dependencies": Object { + "@my-workspace/package-1": Object { + "requires": Object { + "tiny-tarball": "^1.0.0", + }, + "version": "file:packages/package-1", + }, + "@my-workspace/package-2": Object { + "requires": Object { + "@my-workspace/package-1": "^2.4.0", + }, + "version": "file:packages/package-2", + }, + }, + "lockfileVersion": 2, + "name": "my-workspace", + "packages": Object { + "": Object { + "license": "MIT", + "name": "my-workspace", + "workspaces": Array [ + "./packages/package-1", + "./packages/package-2", + ], + }, + "node_modules/package-1": Object { + "link": true, + "resolved": "packages/package-1", + }, + "node_modules/package-2": Object { + "link": true, + "resolved": "packages/package-2", + }, + "packages/package-1": Object { + "license": "MIT", + "name": "@my-workspace/package-1", + "tiny-tarball": Object { + "integrity": "sha1-u/EC1a5zr+LFUyleD7AiMCFvZbE=", + "resolved": "https://registry.npmjs.org/tiny-tarball/-/tiny-tarball-1.0.0.tgz", + "version": "1.0.0", + }, + "version": "2.4.0", + }, + "packages/package-2": Object { + "dependencies": Object { + "@my-workspace/package-1": "^2.4.0", + }, + "license": "MIT", + "name": "@my-workspace/package-2", + "version": "2.4.0", + }, + }, + "requires": true, +} +`; diff --git a/packages/version/src/__tests__/update-lockfile-version.spec.js b/packages/version/src/__tests__/update-lockfile-version.spec.js index a50d2dea..3866dccc 100644 --- a/packages/version/src/__tests__/update-lockfile-version.spec.js +++ b/packages/version/src/__tests__/update-lockfile-version.spec.js @@ -10,31 +10,66 @@ const loadJsonFile = require("load-json-file"); const { getPackages } = require('../../../core/src/project'); const initFixture = require("@lerna-test/init-fixture")(__dirname); -const { updateLockfileVersion } = require("../lib/update-lockfile-version"); +const { updateClassicLockfileVersion, updateModernLockfileVersion } = require("../lib/update-lockfile-version"); -test("updateLockfileVersion", async () => { - const cwd = await initFixture("lockfile-leaf"); - const [pkg] = await getPackages(cwd); +describe('npm classic lock file', () => { + test("updateLockfileVersion with lockfile v1", async () => { + const cwd = await initFixture("lockfile-leaf"); + const [pkg] = await getPackages(cwd); - pkg.version = "2.0.0"; + pkg.version = "2.0.0"; - const returnedLockfilePath = await updateLockfileVersion(pkg); + const returnedLockfilePath = await updateClassicLockfileVersion(pkg); - expect(returnedLockfilePath).toBe(path.join(pkg.location, "package-lock.json")); - expect(Array.from(loadJsonFile.registry.keys())).toStrictEqual(["/packages/package-1"]); - expect(fs.readJSONSync(returnedLockfilePath)).toHaveProperty("version", "2.0.0"); -}); + expect(returnedLockfilePath).toBe(path.join(pkg.location, "package-lock.json")); + expect(Array.from(loadJsonFile.registry.keys())).toStrictEqual(["/packages/package-1"]); + expect(fs.readJSONSync(returnedLockfilePath)).toHaveProperty("version", "2.0.0"); + }); + + test("updateClassicLockfileVersion with lockfile v2", async () => { + const cwd = await initFixture("lockfile-leaf-v2"); + const [pkg] = await getPackages(cwd); + + pkg.version = "2.0.0"; + + const returnedLockfilePath = await updateClassicLockfileVersion(pkg); -test("updateLockfileVersion without sibling lockfile", async () => { - const cwd = await initFixture("lifecycle", false); - const [pkg] = await getPackages(cwd); + expect(returnedLockfilePath).toBe(path.join(pkg.location, "package-lock.json")); + expect(Array.from(loadJsonFile.registry.keys())).toStrictEqual(["/packages/package-1"]); + const updatedLockfile = fs.readJSONSync(returnedLockfilePath); + expect(updatedLockfile).toHaveProperty("version", "2.0.0"); + expect(updatedLockfile).toHaveProperty(["packages", "", "version"], "2.0.0"); + }); - pkg.version = "1.1.0"; + test("updateClassicLockfileVersion without sibling lockfile", async () => { + const cwd = await initFixture("lifecycle", false); + const [pkg] = await getPackages(cwd); - loadJsonFile.mockImplementationOnce(() => Promise.reject(new Error("file not found"))); + pkg.version = "1.1.0"; - const returnedLockfilePath = await updateLockfileVersion(pkg); + loadJsonFile.mockImplementationOnce(() => Promise.reject(new Error("file not found"))); - expect(returnedLockfilePath).toBeUndefined(); - expect(fs.pathExistsSync(path.join(pkg.location, "package-lock.json"))).toBe(false); + const returnedLockfilePath = await updateClassicLockfileVersion(pkg); + + expect(returnedLockfilePath).toBeUndefined(); + expect(fs.pathExistsSync(path.join(pkg.location, "package-lock.json"))).toBe(false); + }); }); + +describe('npm modern lock file', () => { + test("updateModernLockfileVersion v2 in project root", async () => { + const mockVersion = "2.4.0"; + const cwd = await initFixture("lockfile-version2"); + const rootLockFilePath = path.join(cwd, "package-lock.json"); + const packages = await getPackages(cwd); + + for (const pkg of packages) { + pkg.version = mockVersion; + const returnedLockfilePath = await updateModernLockfileVersion(pkg, { rootPath: cwd }); + expect(returnedLockfilePath).toBe(rootLockFilePath); + } + + expect(Array.from(loadJsonFile.registry.keys())).toStrictEqual(["/packages/package-1", "/packages/package-2", "/"]); + expect(fs.readJSONSync(rootLockFilePath)).toMatchSnapshot(); + }); +}); \ No newline at end of file diff --git a/packages/version/src/lib/update-lockfile-version.ts b/packages/version/src/lib/update-lockfile-version.ts index 59b4d32e..576139f1 100644 --- a/packages/version/src/lib/update-lockfile-version.ts +++ b/packages/version/src/lib/update-lockfile-version.ts @@ -10,7 +10,7 @@ import { Package, Project } from '@lerna-lite/core'; * @param {Object} project * @returns Promise */ -export async function updateLockfileVersion(pkg: Package, project: Project): Promise { +export async function updateClassicLockfileVersion(pkg: Package): Promise { try { // "lockfileVersion" = 1, package lock file might be located in the package folder const lockFilePath = path.join(pkg.location, 'package-lock.json'); @@ -31,9 +31,11 @@ export async function updateLockfileVersion(pkg: Package, project: Project): Pro return lockFilePath; } } catch (error) { } // eslint-disable-line +} +export async function updateModernLockfileVersion(pkg: Package, project: Project): Promise { try { - // OR "lockfileVersion" >= 2, will have a global package lock file located in the root folder and is formatted + // OR "lockfileVersion" >= 2 in the project root, will have a global package lock file located in the root folder and is formatted const projFilePath = path.join(project.rootPath, 'package-lock.json'); const projLockFileObj: any = await loadJsonFile(projFilePath); @@ -45,10 +47,7 @@ export async function updateLockfileVersion(pkg: Package, project: Project): Pro }); return projFilePath; } - } catch (error) { - return undefined; - } - return undefined; + } catch (error) { } // eslint-disable-line } /** diff --git a/packages/version/src/version-command.ts b/packages/version/src/version-command.ts index 2f7e9b71..55447221 100644 --- a/packages/version/src/version-command.ts +++ b/packages/version/src/version-command.ts @@ -37,7 +37,7 @@ import { gitCommit } from './lib/git-commit'; import { gitTag } from './lib/git-tag'; import { gitPush } from './lib/git-push'; import { makePromptVersion } from './lib/prompt-version'; -import { updateLockfileVersion } from './lib/update-lockfile-version'; +import { updateClassicLockfileVersion, updateModernLockfileVersion } from './lib/update-lockfile-version'; export function factory(argv) { return new VersionCommand(argv); @@ -539,13 +539,20 @@ export class VersionCommand extends Command { } } - return Promise.all([updateLockfileVersion(pkg, this.project), pkg.serialize()]).then(([lockfilePath]) => { + return Promise.all([ + updateClassicLockfileVersion(pkg), + updateModernLockfileVersion(pkg, this.project), + pkg.serialize() + ]).then(([lockfilePath, rootLockfilePath]) => { // commit the updated manifest changedFiles.add(pkg.manifestLocation); if (lockfilePath) { changedFiles.add(lockfilePath); } + if (rootLockfilePath) { + changedFiles.add(rootLockfilePath); + } return pkg; });