feat(release): update lockfile after version command (#21107)
This commit is contained in:
parent
6164481d57
commit
096cefb109
@ -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
|
||||
|
||||
187
e2e/release/src/lock-file-updates.test.ts
Normal file
187
e2e/release/src/lock-file-updates.test.ts
Normal file
@ -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
|
||||
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -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`,
|
||||
|
||||
@ -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",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
|
||||
@ -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<ReleaseVersionGeneratorResult> {
|
||||
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({
|
||||
|
||||
@ -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<string, unknown>;
|
||||
}
|
||||
) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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<string, unknown>;
|
||||
}
|
||||
) => Promise<string[]>;
|
||||
};
|
||||
|
||||
export type VersionData = Record<
|
||||
string,
|
||||
{
|
||||
|
||||
@ -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<string>();
|
||||
const generatorCallbacks: (() => Promise<void>)[] = [];
|
||||
|
||||
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<ReleaseVersionGeneratorResult['callback']> {
|
||||
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) {
|
||||
|
||||
@ -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',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user