From 096cefb109609a7aadfdb949f81e128df5ae266c Mon Sep 17 00:00:00 2001 From: Austin Fahsl Date: Tue, 23 Jan 2024 11:22:16 -0700 Subject: [PATCH] feat(release): update lockfile after version command (#21107) --- e2e/release/src/independent-projects.test.ts | 39 +++- e2e/release/src/lock-file-updates.test.ts | 187 ++++++++++++++++++ e2e/release/src/release.test.ts | 19 +- .../release-version/release-version.spec.ts | 57 +++--- .../release-version/release-version.ts | 36 +++- .../release-version/utils/update-lock-file.ts | 103 ++++++++++ .../src/command-line/release/utils/shared.ts | 13 ++ .../nx/src/command-line/release/version.ts | 68 +++++-- packages/nx/src/utils/package-manager.ts | 10 +- 9 files changed, 475 insertions(+), 57 deletions(-) create mode 100644 e2e/release/src/lock-file-updates.test.ts create mode 100644 packages/js/src/generators/release-version/utils/update-lock-file.ts diff --git a/e2e/release/src/independent-projects.test.ts b/e2e/release/src/independent-projects.test.ts index 57203a91c837a..469d10061ef02 100644 --- a/e2e/release/src/independent-projects.test.ts +++ b/e2e/release/src/independent-projects.test.ts @@ -2,6 +2,7 @@ import { joinPathFragments } from '@nx/devkit'; import { cleanupProject, exists, + getSelectedPackageManager, newProject, readFile, runCLI, @@ -34,6 +35,16 @@ expect.addSnapshotSerializer({ .replaceAll(/\d*\.\d*\s?kB/g, 'XXX.XXX kb') // Normalize the version title date .replaceAll(/\(\d{4}-\d{2}-\d{2}\)/g, '(YYYY-MM-DD)') + .replaceAll('package-lock.json', '{lock-file}') + .replaceAll('yarn.lock', '{lock-file}') + .replaceAll('pnpm-lock.yaml', '{lock-file}') + .replaceAll('npm install --package-lock-only', '{lock-file-command}') + .replaceAll( + 'yarn install --mode update-lockfile', + '{lock-file-command}' + ) + .replaceAll('pnpm install --lockfile-only', '{lock-file-command}') + .replaceAll(getSelectedPackageManager(), '{package-manager}') // We trim each line to reduce the chances of snapshot flakiness .split('\n') .map((r) => r.trim()) @@ -127,6 +138,9 @@ describe('nx release - independent projects', () => { "scripts": { + > NX Updating {package-manager} lock file + + > NX Staging changed files with git @@ -159,6 +173,9 @@ describe('nx release - independent projects', () => { + + > NX Updating {package-manager} lock file + + > NX Staging changed files with git @@ -198,6 +215,9 @@ describe('nx release - independent projects', () => { } + > NX Updating {package-manager} lock file + + > NX Staging changed files with git @@ -237,10 +257,15 @@ describe('nx release - independent projects', () => { "scripts": { + > NX Updating {package-manager} lock file + + Updating {lock-file} with the following command: + {lock-file-command} + > NX Committing changes with git Staging files in git with the following command: - git add {project-name}/package.json + git add {project-name}/package.json {lock-file} Committing files in git with the following command: git commit --message chore(release): publish --message - project: {project-name} 999.9.9-version-git-operations-test.2 @@ -340,10 +365,20 @@ describe('nx release - independent projects', () => { "scripts": { + > NX Updating {package-manager} lock file + + Updating {lock-file} with the following command: + {lock-file-command} + + > NX Updating {package-manager} lock file + + Updating {lock-file} with the following command: + {lock-file-command} + > NX Committing changes with git Staging files in git with the following command: - git add {project-name}/package.json {project-name}/package.json {project-name}/package.json + git add {project-name}/package.json {project-name}/package.json {project-name}/package.json {lock-file} Committing files in git with the following command: git commit --message chore(release): publish --message - project: {project-name} 999.9.9-version-git-operations-test.3 --message - project: {project-name} 999.9.9-version-git-operations-test.3 --message - release-group: fixed 999.9.9-version-git-operations-test.3 diff --git a/e2e/release/src/lock-file-updates.test.ts b/e2e/release/src/lock-file-updates.test.ts new file mode 100644 index 0000000000000..526e3f8450ed8 --- /dev/null +++ b/e2e/release/src/lock-file-updates.test.ts @@ -0,0 +1,187 @@ +import { + cleanupProject, + newProject, + runCLI, + runCommand, + uniq, + updateFile, + updateJson, +} from '@nx/e2e/utils'; + +expect.addSnapshotSerializer({ + serialize(str: string) { + return ( + str + // Remove all output unique to specific projects to ensure deterministic snapshots + .replaceAll(/my-pkg-\d+/g, '{project-name}') + .replaceAll( + /integrity:\s*.*/g, + 'integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + ) + .replaceAll(/\b[0-9a-f]{40}\b/g, '{SHASUM}') + .replaceAll(/\d*B index\.js/g, 'XXB index.js') + .replaceAll(/\d*B project\.json/g, 'XXB project.json') + .replaceAll(/\d*B package\.json/g, 'XXXB package.json') + .replaceAll(/size:\s*\d*\s?B/g, 'size: XXXB') + .replaceAll(/\d*\.\d*\s?kB/g, 'XXX.XXX kb') + .replaceAll(/[a-fA-F0-9]{7}/g, '{COMMIT_SHA}') + .replaceAll(/Test @[\w\d]+/g, 'Test @{COMMIT_AUTHOR}') + // Normalize the version title date. + .replaceAll(/\(\d{4}-\d{2}-\d{2}\)/g, '(YYYY-MM-DD)') + // We trim each line to reduce the chances of snapshot flakiness + .split('\n') + .map((r) => r.trim()) + .join('\n') + ); + }, + test(val: string) { + return val != null && typeof val === 'string'; + }, +}); + +describe('nx release lock file updates', () => { + let pkg1: string; + let pkg2: string; + let pkg3: string; + let previousPackageManager: string; + let previousYarnEnableImmutableInstalls: string; + let previousNodeOptions: string; + + beforeAll(() => { + previousPackageManager = process.env.SELECTED_PM; + previousYarnEnableImmutableInstalls = + process.env.YARN_ENABLE_IMMUTABLE_INSTALLS; + previousNodeOptions = process.env.NODE_OPTIONS; + }); + + // project will be created by each test individually + // in order to test different package managers + const initializeProject = (packageManager: 'npm' | 'yarn' | 'pnpm') => { + process.env.SELECTED_PM = packageManager; + + newProject({ + unsetProjectNameAndRootFormat: false, + packages: ['@nx/js'], + packageManager, + }); + + pkg1 = uniq('my-pkg-1'); + runCLI(`generate @nx/workspace:npm-package ${pkg1}`); + + pkg2 = uniq('my-pkg-2'); + runCLI(`generate @nx/workspace:npm-package ${pkg2}`); + + pkg3 = uniq('my-pkg-3'); + runCLI(`generate @nx/workspace:npm-package ${pkg3}`); + + // Update pkg2 to depend on pkg1 + updateJson(`${pkg2}/package.json`, (json) => { + json.dependencies ??= {}; + json.dependencies[`@proj/${pkg1}`] = '0.0.0'; + return json; + }); + }; + + afterEach(() => { + cleanupProject(); + }); + + afterAll(() => { + process.env.SELECTED_PM = previousPackageManager; + process.env.YARN_ENABLE_IMMUTABLE_INSTALLS = + previousYarnEnableImmutableInstalls; + process.env.NODE_OPTIONS = previousNodeOptions; + }); + + it('should update package-lock.json when package manager is npm', async () => { + initializeProject('npm'); + + runCommand(`npm install`); + + // workaround for NXC-143 + runCLI('reset'); + + runCommand(`git add .`); + runCommand(`git commit -m "chore: initial commit"`); + + const versionOutput = runCLI(`release version 999.9.9`); + + expect(versionOutput.match(/NX Updating npm lock file/g).length).toBe(1); + + const filesChanges = runCommand('git diff --name-only HEAD'); + + expect(filesChanges).toMatchInlineSnapshot(` + {project-name}/package.json + {project-name}/package.json + {project-name}/package.json + package-lock.json + + `); + }); + + it.skip('should update yarn.lock when package manager is yarn', async () => { + process.env.YARN_ENABLE_IMMUTABLE_INSTALLS = 'false'; + process.env.NODE_OPTIONS = '--no-enable-network-family-autoselection'; + + initializeProject('yarn'); + + updateJson('package.json', (json) => { + json.workspaces = [pkg1, pkg2, pkg3]; + return json; + }); + + runCommand(`yarn install`); + + // workaround for NXC-143 + runCLI('reset'); + + runCommand(`git add .`); + runCommand(`git commit -m "chore: initial commit"`); + + const versionOutput = runCLI(`release version 999.9.9`); + + expect(versionOutput.match(/NX Updating yarn lock file/g).length).toBe(1); + + const filesChanges = runCommand('git diff --name-only HEAD'); + + expect(filesChanges).toMatchInlineSnapshot(` + .yarn/install-state.gz + {project-name}/package.json + {project-name}/package.json + {project-name}/package.json + yarn.lock + + `); + }); + + it('should update pnpm-lock.yaml when package manager is pnpm', async () => { + initializeProject('pnpm'); + + updateFile( + 'pnpm-workspace.yaml', + `packages:\n - ${pkg1}\n - ${pkg2}\n - ${pkg3}\n` + ); + + // workaround for NXC-143 + runCLI('reset'); + + runCommand(`pnpm install`); + + runCommand(`git add .`); + runCommand(`git commit -m "chore: initial commit"`); + + const versionOutput = runCLI(`release version 999.9.9`); + + expect(versionOutput.match(/NX Updating pnpm lock file/g).length).toBe(1); + + const filesChanges = runCommand('git diff --name-only HEAD'); + + expect(filesChanges).toMatchInlineSnapshot(` + {project-name}/package.json + {project-name}/package.json + {project-name}/package.json + pnpm-lock.yaml + + `); + }); +}); diff --git a/e2e/release/src/release.test.ts b/e2e/release/src/release.test.ts index b8bca8e5f9f91..9e5a0333ab193 100644 --- a/e2e/release/src/release.test.ts +++ b/e2e/release/src/release.test.ts @@ -1146,17 +1146,14 @@ ${JSON.stringify( silenceError: true, }); - expect(releaseOutput6a).toMatchInlineSnapshot(` - - > NX Running release version for project: {project-name} - - {project-name} 🔍 Reading data for package "@proj/{project-name}" from {project-name}/package.json - - > NX Unable to resolve the current version from the registry ${e2eRegistryUrl}. Please ensure that the package exists in the registry in order to use the "registry" currentVersionResolver. Alternatively, you can set the "version.generatorOptions.fallbackCurrentVersionResolver" to "disk" in order to fallback to the version on disk when the registry lookup fails. - - - Resolving the current version for tag "other" on ${e2eRegistryUrl} - - `); + expect( + releaseOutput6a.match( + new RegExp( + `> NX Unable to resolve the current version from the registry ${e2eRegistryUrl}. Please ensure that the package exists in the registry in order to use the "registry" currentVersionResolver. Alternatively, you can set the "version.generatorOptions.fallbackCurrentVersionResolver" to "disk" in order to fallback to the version on disk when the registry lookup fails.`, + 'g' + ) + ).length + ).toEqual(1); const releaseOutput6b = runCLI( `release patch --skip-publish --first-release`, diff --git a/packages/js/src/generators/release-version/release-version.spec.ts b/packages/js/src/generators/release-version/release-version.spec.ts index 76b7e3378a3cc..d8b2f8ac427b6 100644 --- a/packages/js/src/generators/release-version/release-version.spec.ts +++ b/packages/js/src/generators/release-version/release-version.spec.ts @@ -88,33 +88,36 @@ describe('release-version', () => { }) ).toMatchInlineSnapshot(` { - "my-lib": { - "currentVersion": "0.0.1", - "dependentProjects": [ - { - "dependencyCollection": "dependencies", - "source": "project-with-dependency-on-my-pkg", - "target": "my-lib", - "type": "static", - }, - { - "dependencyCollection": "devDependencies", - "source": "project-with-devDependency-on-my-pkg", - "target": "my-lib", - "type": "static", - }, - ], - "newVersion": "1.0.0", - }, - "project-with-dependency-on-my-pkg": { - "currentVersion": "0.0.1", - "dependentProjects": [], - "newVersion": "1.0.0", - }, - "project-with-devDependency-on-my-pkg": { - "currentVersion": "0.0.1", - "dependentProjects": [], - "newVersion": "1.0.0", + "callback": [Function], + "data": { + "my-lib": { + "currentVersion": "0.0.1", + "dependentProjects": [ + { + "dependencyCollection": "dependencies", + "source": "project-with-dependency-on-my-pkg", + "target": "my-lib", + "type": "static", + }, + { + "dependencyCollection": "devDependencies", + "source": "project-with-devDependency-on-my-pkg", + "target": "my-lib", + "type": "static", + }, + ], + "newVersion": "1.0.0", + }, + "project-with-dependency-on-my-pkg": { + "currentVersion": "0.0.1", + "dependentProjects": [], + "newVersion": "1.0.0", + }, + "project-with-devDependency-on-my-pkg": { + "currentVersion": "0.0.1", + "dependentProjects": [], + "newVersion": "1.0.0", + }, }, } `); diff --git a/packages/js/src/generators/release-version/release-version.ts b/packages/js/src/generators/release-version/release-version.ts index c6d2fd519a777..92541724900df 100644 --- a/packages/js/src/generators/release-version/release-version.ts +++ b/packages/js/src/generators/release-version/release-version.ts @@ -19,21 +19,24 @@ import { } from 'nx/src/command-line/release/utils/resolve-semver-specifier'; import { isValidSemverSpecifier } from 'nx/src/command-line/release/utils/semver'; import { + ReleaseVersionGeneratorResult, VersionData, deriveNewSemverVersion, validReleaseVersionPrefixes, } from 'nx/src/command-line/release/version'; +import { daemonClient } from 'nx/src/daemon/client/client'; import { interpolate } from 'nx/src/tasks-runner/utils'; import * as ora from 'ora'; import { relative } from 'path'; import { prerelease } from 'semver'; import { ReleaseVersionGeneratorSchema } from './schema'; import { resolveLocalPackageDependencies } from './utils/resolve-local-package-dependencies'; +import { updateLockFile } from './utils/update-lock-file'; export async function releaseVersionGenerator( tree: Tree, options: ReleaseVersionGeneratorSchema -) { +): Promise { try { const versionData: VersionData = {}; @@ -473,7 +476,36 @@ To fix this you will either need to add a package.json file at that location, or await formatFiles(tree); // Return the version data so that it can be leveraged by the overall version command - return versionData; + return { + data: versionData, + callback: async (tree, opts) => { + const cwd = tree.root; + + const isDaemonEnabled = daemonClient.enabled(); + if (isDaemonEnabled) { + // temporarily stop the daemon, as it will error if the lock file is updated + await daemonClient.stop(); + } + + const updatedFiles = updateLockFile(cwd, opts); + + if (isDaemonEnabled) { + try { + await daemonClient.startInBackground(); + } catch (e) { + // If the daemon fails to start, we don't want to prevent the user from continuing, so we just log the error and move on + if (opts.verbose) { + output.warn({ + title: + 'Unable to restart the Nx Daemon. It will be disabled until you run "nx reset"', + bodyLines: [e.message], + }); + } + } + } + return updatedFiles; + }, + }; } catch (e) { if (process.env.NX_VERBOSE_LOGGING === 'true') { output.error({ diff --git a/packages/js/src/generators/release-version/utils/update-lock-file.ts b/packages/js/src/generators/release-version/utils/update-lock-file.ts new file mode 100644 index 0000000000000..976c7e445d193 --- /dev/null +++ b/packages/js/src/generators/release-version/utils/update-lock-file.ts @@ -0,0 +1,103 @@ +import { + detectPackageManager, + getPackageManagerCommand, + getPackageManagerVersion, + output, +} from '@nx/devkit'; +import { execSync } from 'child_process'; +// eslint-disable-next-line @typescript-eslint/no-restricted-imports +import { getLockFileName } from 'nx/src/plugins/js/lock-file/lock-file'; +import { gte } from 'semver'; + +export function updateLockFile( + cwd: string, + { + dryRun, + verbose, + generatorOptions, + }: { + dryRun?: boolean; + verbose?: boolean; + generatorOptions?: Record; + } +) { + if (generatorOptions?.skipLockFileUpdate) { + if (verbose) { + console.log( + '\nSkipped lock file update because skipLockFileUpdate was set.' + ); + } + return []; + } + + const packageManager = detectPackageManager(cwd); + const packageManagerCommands = getPackageManagerCommand(packageManager); + + let installArgs = generatorOptions?.installArgs || ''; + + output.logSingleLine(`Updating ${packageManager} lock file`); + + let env: object = {}; + + if (generatorOptions?.installIgnoreScripts) { + if ( + packageManager === 'yarn' && + gte(getPackageManagerVersion(packageManager), '2.0.0') + ) { + env = { YARN_ENABLE_SCRIPTS: 'false' }; + } else { + // npm, pnpm, and yarn classic all use the same --ignore-scripts option + installArgs = `${installArgs} --ignore-scripts`.trim(); + } + } + + const lockFile = getLockFileName(packageManager); + const command = + `${packageManagerCommands.updateLockFile} ${installArgs}`.trim(); + + if (verbose) { + if (dryRun) { + console.log( + `Would update ${lockFile} with the following command, but --dry-run was set:` + ); + } else { + console.log(`Updating ${lockFile} with the following command:`); + } + console.log(command); + } + + if (dryRun) { + return []; + } + + execLockFileUpdate(command, cwd, env); + + return [lockFile]; +} + +function execLockFileUpdate( + command: string, + cwd: string, + env: object = {} +): void { + try { + execSync(command, { + cwd, + env: { + ...process.env, + ...env, + }, + }); + } catch (e) { + output.error({ + title: `Error updating lock file with command '${command}'`, + bodyLines: [ + `Verify that '${command}' succeeds when run from the workspace root.`, + `To configure a string of arguments to be passed to this command, set the 'release.version.generatorOptions.installArgs' property in nx.json.`, + `To ignore install lifecycle scripts, set 'release.version.generatorOptions.installIgnoreScripts' to true in nx.json.`, + `To disable this step entirely, set 'release.version.skipLockFileUpdate' to true in nx.json.`, + ], + }); + throw e; + } +} diff --git a/packages/nx/src/command-line/release/utils/shared.ts b/packages/nx/src/command-line/release/utils/shared.ts index 50ec76d7e9ec0..3113d826c898f 100644 --- a/packages/nx/src/command-line/release/utils/shared.ts +++ b/packages/nx/src/command-line/release/utils/shared.ts @@ -1,11 +1,24 @@ import { prerelease } from 'semver'; import { ProjectGraph } from '../../../config/project-graph'; +import { Tree } from '../../../generators/tree'; import { createFileMapUsingProjectGraph } from '../../../project-graph/file-map-utils'; import { interpolate } from '../../../tasks-runner/utils'; import { output } from '../../../utils/output'; import type { ReleaseGroupWithName } from '../config/filter-release-groups'; import { GitCommit, gitAdd, gitCommit } from './git'; +export type ReleaseVersionGeneratorResult = { + data: VersionData; + callback: ( + tree: Tree, + opts: { + dryRun?: boolean; + verbose?: boolean; + generatorOptions?: Record; + } + ) => Promise; +}; + export type VersionData = Record< string, { diff --git a/packages/nx/src/command-line/release/version.ts b/packages/nx/src/command-line/release/version.ts index 01ffacb54ebb0..51a9ac76c6963 100644 --- a/packages/nx/src/command-line/release/version.ts +++ b/packages/nx/src/command-line/release/version.ts @@ -34,6 +34,7 @@ import { import { gitAdd, gitTag } from './utils/git'; import { printDiff } from './utils/print-changes'; import { + ReleaseVersionGeneratorResult, VersionData, commitChanges, createCommitMessageValues, @@ -43,7 +44,10 @@ import { // Reexport some utils for use in plugin release-version generator implementations export { deriveNewSemverVersion } from './utils/semver'; -export type { VersionData } from './utils/shared'; +export type { + ReleaseVersionGeneratorResult, + VersionData, +} from './utils/shared'; export const validReleaseVersionPrefixes = ['auto', '', '~', '^']; @@ -128,6 +132,8 @@ export async function releaseVersion( const versionData: VersionData = {}; const commitMessage: string | undefined = args.gitCommitMessage || nxReleaseConfig.version.git.commitMessage; + const changedLockFiles = new Set(); + const generatorCallbacks: (() => Promise)[] = []; if (args.projects?.length) { /** @@ -150,7 +156,7 @@ export async function releaseVersion( releaseGroupToFilteredProjects.get(releaseGroup) ); - await runVersionOnProjects( + const generatorCallback = await runVersionOnProjects( projectGraph, nxJson, args, @@ -160,6 +166,16 @@ export async function releaseVersion( releaseGroup, versionData ); + + generatorCallbacks.push(async () => + ( + await generatorCallback(tree, { + dryRun: !!args.dryRun, + verbose: !!args.verbose, + generatorOptions: releaseGroup.version.generatorOptions, + }) + ).forEach((f) => changedLockFiles.add(f)) + ); } // Resolve any git tags as early as possible so that we can hard error in case of any duplicates before reaching the actual git command @@ -175,7 +191,14 @@ export async function releaseVersion( printAndFlushChanges(tree, !!args.dryRun); - const changedFiles = tree.listChanges().map((f) => f.path); + for (const generatorCallback of generatorCallbacks) { + await generatorCallback(); + } + + const changedFiles = [ + ...tree.listChanges().map((f) => f.path), + ...changedLockFiles, + ]; // No further actions are necessary in this scenario (e.g. if conventional commits detected no changes) if (!changedFiles.length) { @@ -188,7 +211,7 @@ export async function releaseVersion( if (args.gitCommit ?? nxReleaseConfig.version.git.commit) { await commitChanges( - tree.listChanges().map((f) => f.path), + changedFiles, !!args.dryRun, !!args.verbose, createCommitMessageValues( @@ -249,7 +272,7 @@ export async function releaseVersion( projects, }); - await runVersionOnProjects( + const callback = await runVersionOnProjects( projectGraph, nxJson, args, @@ -259,6 +282,16 @@ export async function releaseVersion( releaseGroup, versionData ); + + generatorCallbacks.push(async () => + ( + await callback(tree, { + dryRun: !!args.dryRun, + verbose: !!args.verbose, + generatorOptions: releaseGroup.version.generatorOptions, + }) + ).forEach((f) => changedLockFiles.add(f)) + ); } // Resolve any git tags as early as possible so that we can hard error in case of any duplicates before reaching the actual git command @@ -274,6 +307,10 @@ export async function releaseVersion( printAndFlushChanges(tree, !!args.dryRun); + for (const generatorCallback of generatorCallbacks) { + await generatorCallback(); + } + // Only applicable when there is a single release group with a fixed relationship let workspaceVersion: string | null | undefined = undefined; if (releaseGroups.length === 1) { @@ -286,7 +323,10 @@ export async function releaseVersion( } } - const changedFiles = tree.listChanges().map((f) => f.path); + const changedFiles = [ + ...tree.listChanges().map((f) => f.path), + ...changedLockFiles, + ]; // No further actions are necessary in this scenario (e.g. if conventional commits detected no changes) if (!changedFiles.length) { @@ -366,7 +406,7 @@ async function runVersionOnProjects( projectNames: string[], releaseGroup: ReleaseGroupWithName, versionData: VersionData -) { +): Promise { const generatorOptions: ReleaseVersionGeneratorSchema = { // Always ensure a string to avoid generator schema validation errors specifier: args.specifier ?? '', @@ -395,20 +435,22 @@ async function runVersionOnProjects( const releaseVersionGenerator = generatorData.implementationFactory(); - // We expect all version generator implementations to return a VersionData object, rather than a GeneratorCallback - const versionDataForProjects = (await releaseVersionGenerator( + // We expect all version generator implementations to return a ReleaseVersionGeneratorResult object, rather than a GeneratorCallback + const versionResult = (await releaseVersionGenerator( tree, combinedOpts - )) as unknown as VersionData; + )) as unknown as ReleaseVersionGeneratorResult; - if (typeof versionDataForProjects === 'function') { + if (typeof versionResult === 'function') { throw new Error( - `The version generator ${generatorData.collectionName}:${generatorData.normalizedGeneratorName} returned a function instead of an expected VersionData object` + `The version generator ${generatorData.collectionName}:${generatorData.normalizedGeneratorName} returned a function instead of an expected ReleaseVersionGeneratorResult` ); } // Merge the extra version data into the existing - appendVersionData(versionData, versionDataForProjects); + appendVersionData(versionData, versionResult.data); + + return versionResult.callback; } function printAndFlushChanges(tree: Tree, isDryRun: boolean) { diff --git a/packages/nx/src/utils/package-manager.ts b/packages/nx/src/utils/package-manager.ts index e1c3ad5d08602..5075cd959f4b7 100644 --- a/packages/nx/src/utils/package-manager.ts +++ b/packages/nx/src/utils/package-manager.ts @@ -2,13 +2,13 @@ import { exec, execSync } from 'child_process'; import { copyFileSync, existsSync, writeFileSync } from 'fs'; import { remove } from 'fs-extra'; import { dirname, join, relative } from 'path'; +import { gte, lt } from 'semver'; import { dirSync } from 'tmp'; import { promisify } from 'util'; +import { readNxJson } from '../config/configuration'; import { readFileIfExisting, writeJsonFile } from './fileutils'; import { readModulePackageJson } from './package-json'; -import { gte, lt } from 'semver'; import { workspaceRoot } from './workspace-root'; -import { readNxJson } from '../config/configuration'; const execAsync = promisify(exec); @@ -18,6 +18,7 @@ export interface PackageManagerCommands { preInstall?: string; install: string; ciInstall: string; + updateLockFile: string; add: string; addDev: string; rm: string; @@ -71,6 +72,9 @@ export function getPackageManagerCommand( ciInstall: useBerry ? 'yarn install --immutable' : 'yarn install --frozen-lockfile', + updateLockFile: useBerry + ? 'yarn install --mode update-lockfile' + : 'yarn install', add: useBerry ? 'yarn add' : 'yarn add -W', addDev: useBerry ? 'yarn add -D' : 'yarn add -D -W', rm: 'yarn remove', @@ -89,6 +93,7 @@ export function getPackageManagerCommand( return { install: 'pnpm install --no-frozen-lockfile', // explicitly disable in case of CI ciInstall: 'pnpm install --frozen-lockfile', + updateLockFile: 'pnpm install --lockfile-only', add: isPnpmWorkspace ? 'pnpm add -w' : 'pnpm add', addDev: isPnpmWorkspace ? 'pnpm add -Dw' : 'pnpm add -D', rm: 'pnpm rm', @@ -108,6 +113,7 @@ export function getPackageManagerCommand( return { install: 'npm install', ciInstall: 'npm ci', + updateLockFile: 'npm install --package-lock-only', add: 'npm install', addDev: 'npm install -D', rm: 'npm rm',