feat(core): respect packageGroup in nx migrate (#9667)
* cleanup(core): refactor migrate.ts * feat(core): respect packageGroup in nx migrate ISSUES CLOSED: #4575 * fix build * chore(repo): trigger CI * chore(core): fix review comments, without packageGroup extension * chore(core): revert `withTempNpmDirectory` changes * chore(repo): trigger ci * chore(core): fix unit tests * chore(core): remove view and pack from pmc * chore(repo): kick off CI * chore(core): add tests for recursive packageGroup * chore(core): add another test for cyclic packageGroup * chore(repo): kickoff CI Co-authored-by: Craigory Coppola <craigorycoppola@gmail.com>
This commit is contained in:
parent
0e68c616fe
commit
32b49b6f7c
@ -15,7 +15,7 @@ import { packagesWeCareAbout } from 'nx/src/command-line/report';
|
||||
describe('Cli', () => {
|
||||
beforeEach(() => newProject());
|
||||
|
||||
it('vvvshould execute long running tasks', async () => {
|
||||
it('should execute long running tasks', async () => {
|
||||
const myapp = uniq('myapp');
|
||||
runCLI(`generate @nrwl/web:app ${myapp}`);
|
||||
updateProjectConfig(myapp, (c) => {
|
||||
@ -156,7 +156,7 @@ describe('list', () => {
|
||||
describe('migrate', () => {
|
||||
beforeEach(() => newProject());
|
||||
|
||||
it('clear-cacheshould run migrations', () => {
|
||||
it('should run migrations', () => {
|
||||
updateFile(
|
||||
`./node_modules/migrate-parent-package/package.json`,
|
||||
JSON.stringify({
|
||||
|
||||
@ -32,13 +32,13 @@ export async function determineMigration(
|
||||
): Promise<MigrationDefinition> {
|
||||
const angularVersion = getInstalledAngularVersion();
|
||||
const majorAngularVersion = major(angularVersion);
|
||||
latestWorkspaceVersionWithMigration = resolvePackageVersion(
|
||||
latestWorkspaceVersionWithMigration = await resolvePackageVersion(
|
||||
'@nrwl/angular',
|
||||
latestWorkspaceRangeVersionWithMigration
|
||||
);
|
||||
|
||||
if (version) {
|
||||
const normalizedVersion = normalizeVersion(version);
|
||||
const normalizedVersion = await normalizeVersion(version);
|
||||
if (lte(normalizedVersion, latestWorkspaceVersionWithMigration)) {
|
||||
// specified version should use @nrwl/workspace:ng-add
|
||||
return { packageName: '@nrwl/workspace', version: normalizedVersion };
|
||||
@ -66,10 +66,11 @@ export async function determineMigration(
|
||||
);
|
||||
}
|
||||
|
||||
const latestNxCompatibleVersion = getNxVersionBasedOnInstalledAngularVersion(
|
||||
angularVersion,
|
||||
majorAngularVersion
|
||||
);
|
||||
const latestNxCompatibleVersion =
|
||||
await getNxVersionBasedOnInstalledAngularVersion(
|
||||
angularVersion,
|
||||
majorAngularVersion
|
||||
);
|
||||
|
||||
// should use @nrwl/workspace:ng-add if the version is less than the
|
||||
// latest workspace version that has the migration, otherwise use
|
||||
@ -105,10 +106,11 @@ async function findAndSuggestVersionToUse(
|
||||
majorAngularVersion: number,
|
||||
userSpecifiedVersion: string
|
||||
): Promise<MigrationDefinition> {
|
||||
const latestNxCompatibleVersion = getNxVersionBasedOnInstalledAngularVersion(
|
||||
angularVersion,
|
||||
majorAngularVersion
|
||||
);
|
||||
const latestNxCompatibleVersion =
|
||||
await getNxVersionBasedOnInstalledAngularVersion(
|
||||
angularVersion,
|
||||
majorAngularVersion
|
||||
);
|
||||
const useSuggestedVersion = await promptForVersion(latestNxCompatibleVersion);
|
||||
if (useSuggestedVersion) {
|
||||
// should use @nrwl/workspace:ng-add if the version is less than the
|
||||
@ -134,10 +136,10 @@ async function findAndSuggestVersionToUse(
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function getNxVersionBasedOnInstalledAngularVersion(
|
||||
async function getNxVersionBasedOnInstalledAngularVersion(
|
||||
angularVersion: string,
|
||||
majorAngularVersion: number
|
||||
): string {
|
||||
): Promise<string> {
|
||||
if (lt(angularVersion, '13.0.0')) {
|
||||
// the @nrwl/angular:ng-add generator is only available for versions supporting
|
||||
// Angular >= 13.0.0, fall back to @nrwl/workspace:ng-add
|
||||
@ -154,7 +156,7 @@ function getNxVersionBasedOnInstalledAngularVersion(
|
||||
}
|
||||
|
||||
// use latest, only the last version in the map should not contain a max
|
||||
return resolvePackageVersion('@nrwl/angular', 'latest');
|
||||
return await resolvePackageVersion('@nrwl/angular', 'latest');
|
||||
}
|
||||
|
||||
async function promptForVersion(version: string): Promise<boolean> {
|
||||
@ -177,13 +179,13 @@ function getInstalledAngularVersion(): string {
|
||||
return readJsonFile(packageJsonPath).version;
|
||||
}
|
||||
|
||||
function normalizeVersion(version: string): string {
|
||||
async function normalizeVersion(version: string): Promise<string> {
|
||||
if (
|
||||
version.startsWith('^') ||
|
||||
version.startsWith('~') ||
|
||||
version.split('.').length < 3
|
||||
) {
|
||||
return resolvePackageVersion('@nrwl/angular', version);
|
||||
return await resolvePackageVersion('@nrwl/angular', version);
|
||||
}
|
||||
|
||||
return version;
|
||||
|
||||
@ -55,13 +55,13 @@ export function installDependencies(
|
||||
});
|
||||
}
|
||||
|
||||
export function resolvePackageVersion(
|
||||
export async function resolvePackageVersion(
|
||||
packageName: string,
|
||||
version: string
|
||||
): string {
|
||||
): Promise<string> {
|
||||
try {
|
||||
return resolvePackageVersionUsingRegistry(packageName, version);
|
||||
return await resolvePackageVersionUsingRegistry(packageName, version);
|
||||
} catch {
|
||||
return resolvePackageVersionUsingInstallation(packageName, version);
|
||||
return await resolvePackageVersionUsingInstallation(packageName, version);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,32 +1,36 @@
|
||||
import { PackageJson } from '../utils/package-json';
|
||||
import { Migrator, normalizeVersion, parseMigrationsOptions } from './migrate';
|
||||
|
||||
const createPackageJson = (
|
||||
overrides: Partial<PackageJson> = {}
|
||||
): PackageJson => ({
|
||||
name: 'some-workspace',
|
||||
version: '0.0.0',
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe('Migration', () => {
|
||||
describe('packageJson patch', () => {
|
||||
it('should throw an error when the target package is not available', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: {},
|
||||
packageJson: createPackageJson(),
|
||||
versions: () => '1.0',
|
||||
fetch: (_p, _v) => {
|
||||
throw new Error('cannot fetch');
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
|
||||
try {
|
||||
await migrator.updatePackageJson('mypackage', 'myversion');
|
||||
throw new Error('fail');
|
||||
} catch (e) {
|
||||
expect(e.message).toEqual(`cannot fetch`);
|
||||
}
|
||||
await expect(
|
||||
migrator.updatePackageJson('mypackage', 'myversion')
|
||||
).rejects.toThrowError(/cannot fetch/);
|
||||
});
|
||||
|
||||
it('should return a patch to the new version', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: {},
|
||||
packageJson: createPackageJson(),
|
||||
versions: () => '1.0.0',
|
||||
fetch: (_p, _v) => Promise.resolve({ version: '2.0.0' }),
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
|
||||
@ -40,7 +44,7 @@ describe('Migration', () => {
|
||||
|
||||
it('should collect the information recursively from upserts', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: { dependencies: { child: '1.0.0' } },
|
||||
packageJson: createPackageJson({ dependencies: { child: '1.0.0' } }),
|
||||
versions: () => '1.0.0',
|
||||
fetch: (p, _v) => {
|
||||
if (p === 'parent') {
|
||||
@ -68,7 +72,6 @@ describe('Migration', () => {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
|
||||
@ -84,7 +87,7 @@ describe('Migration', () => {
|
||||
|
||||
it('should support the deprecated "alwaysAddToPackageJson" option', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: { dependencies: { child1: '1.0.0' } },
|
||||
packageJson: createPackageJson({ dependencies: { child1: '1.0.0' } }),
|
||||
versions: () => '1.0.0',
|
||||
fetch: (p, _v) => {
|
||||
if (p === 'mypackage') {
|
||||
@ -108,7 +111,6 @@ describe('Migration', () => {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
|
||||
@ -124,7 +126,7 @@ describe('Migration', () => {
|
||||
|
||||
it('should stop recursive calls when exact version', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: { dependencies: { child: '1.0.0' } },
|
||||
packageJson: createPackageJson({ dependencies: { child: '1.0.0' } }),
|
||||
versions: () => '1.0.0',
|
||||
fetch: (p, _v) => {
|
||||
if (p === 'parent') {
|
||||
@ -157,7 +159,6 @@ describe('Migration', () => {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
|
||||
@ -172,13 +173,13 @@ describe('Migration', () => {
|
||||
|
||||
it('should set the version of a dependency to the newest', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: {
|
||||
packageJson: createPackageJson({
|
||||
dependencies: {
|
||||
child1: '1.0.0',
|
||||
child2: '1.0.0',
|
||||
grandchild: '1.0.0',
|
||||
},
|
||||
},
|
||||
}),
|
||||
versions: () => '1.0.0',
|
||||
fetch: (p, _v) => {
|
||||
if (p === 'parent') {
|
||||
@ -225,7 +226,6 @@ describe('Migration', () => {
|
||||
return Promise.resolve({ version: '4.0.0' });
|
||||
}
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
|
||||
@ -242,7 +242,9 @@ describe('Migration', () => {
|
||||
|
||||
it('should skip the versions <= currently installed', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: { dependencies: { child: '1.0.0', grandchild: '2.0.0' } },
|
||||
packageJson: createPackageJson({
|
||||
dependencies: { child: '1.0.0', grandchild: '2.0.0' },
|
||||
}),
|
||||
versions: () => '1.0.0',
|
||||
fetch: (p, _v) => {
|
||||
if (p === 'parent') {
|
||||
@ -275,7 +277,6 @@ describe('Migration', () => {
|
||||
return Promise.resolve({ version: '2.0.0' });
|
||||
}
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
|
||||
@ -290,7 +291,9 @@ describe('Migration', () => {
|
||||
|
||||
it('should conditionally process packages if they are installed', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: { dependencies: { child1: '1.0.0', child2: '1.0.0' } },
|
||||
packageJson: createPackageJson({
|
||||
dependencies: { child1: '1.0.0', child2: '1.0.0' },
|
||||
}),
|
||||
versions: (p) => (p !== 'not-installed' ? '1.0.0' : null),
|
||||
fetch: (p, _v) => {
|
||||
if (p === 'parent') {
|
||||
@ -318,7 +321,6 @@ describe('Migration', () => {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
|
||||
@ -331,78 +333,155 @@ describe('Migration', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// this is temporary. if nx gets used by other projects,
|
||||
// we will extract the special casing
|
||||
it('should special case @nrwl/workspace', async () => {
|
||||
it('should migrate related libraries using packageGroup', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: {
|
||||
name: 'some-workspace',
|
||||
version: '0.0.0',
|
||||
|
||||
devDependencies: {
|
||||
'@nrwl/workspace': '0.9.0',
|
||||
'@nrwl/cli': '0.9.0',
|
||||
'@nrwl/angular': '0.9.0',
|
||||
'@nrwl/cypress': '0.9.0',
|
||||
'@nrwl/devkit': '0.9.0',
|
||||
'@nrwl/eslint-plugin-nx': '0.9.0',
|
||||
'@nrwl/express': '0.9.0',
|
||||
'@nrwl/jest': '0.9.0',
|
||||
'@nrwl/js': '0.9.0',
|
||||
'@nrwl/linter': '0.9.0',
|
||||
'@nrwl/nest': '0.9.0',
|
||||
'@nrwl/next': '0.9.0',
|
||||
'@nrwl/node': '0.9.0',
|
||||
'@nrwl/nx-cloud': '0.9.0',
|
||||
'@nrwl/nx-plugin': '0.9.0',
|
||||
'@nrwl/react': '0.9.0',
|
||||
'@nrwl/storybook': '0.9.0',
|
||||
'@nrwl/web': '0.9.0',
|
||||
'@my-company/nx-workspace': '0.9.0',
|
||||
'@my-company/lib-1': '0.9.0',
|
||||
'@my-company/lib-2': '0.9.0',
|
||||
'@my-company/lib-3': '0.9.0',
|
||||
'@my-company/lib-3-child': '0.9.0',
|
||||
'@my-company/lib-4': '0.9.0',
|
||||
'@my-company/lib-5': '0.9.0',
|
||||
'@my-company/lib-6': '0.9.0',
|
||||
},
|
||||
},
|
||||
versions: () => '1.0.0',
|
||||
fetch: (_p, _v) => Promise.resolve({ version: '2.0.0' }),
|
||||
from: {},
|
||||
fetch: async (pkg, version) => {
|
||||
if (pkg === '@my-company/nx-workspace') {
|
||||
return {
|
||||
version: '2.0.0',
|
||||
packageGroup: [
|
||||
'@my-company/lib-1',
|
||||
'@my-company/lib-2',
|
||||
'@my-company/lib-3',
|
||||
{ package: '@my-company/lib-4', version: 'latest' },
|
||||
],
|
||||
};
|
||||
}
|
||||
if (pkg === '@my-company/lib-6') {
|
||||
return {
|
||||
version: '2.0.0',
|
||||
packageGroup: ['@my-company/nx-workspace'],
|
||||
};
|
||||
}
|
||||
if (pkg === '@my-company/lib-3') {
|
||||
return {
|
||||
version: '2.0.0',
|
||||
packageGroup: ['@my-company/lib-3-child'],
|
||||
};
|
||||
}
|
||||
if (version === 'latest') {
|
||||
return { version: '2.0.1' };
|
||||
}
|
||||
return { version: '2.0.0' };
|
||||
},
|
||||
to: {},
|
||||
});
|
||||
|
||||
expect(
|
||||
await migrator.updatePackageJson('@nrwl/workspace', '2.0.0')
|
||||
).toEqual({
|
||||
await migrator.updatePackageJson('@my-company/nx-workspace', '2.0.0')
|
||||
).toStrictEqual({
|
||||
migrations: [],
|
||||
packageJson: {
|
||||
'@nrwl/workspace': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/angular': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/cypress': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/devkit': { addToPackageJson: false, version: '2.0.0' },
|
||||
'@nrwl/eslint-plugin-nx': {
|
||||
'@my-company/nx-workspace': {
|
||||
version: '2.0.0',
|
||||
addToPackageJson: false,
|
||||
},
|
||||
'@nrwl/express': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/jest': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/js': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/linter': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/nest': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/next': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/node': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/nx-cloud': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/nx-plugin': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/react': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/storybook': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/web': { version: '2.0.0', addToPackageJson: false },
|
||||
'@nrwl/cli': { version: '2.0.0', addToPackageJson: false },
|
||||
'@my-company/lib-1': { version: '2.0.0', addToPackageJson: false },
|
||||
'@my-company/lib-2': { version: '2.0.0', addToPackageJson: false },
|
||||
'@my-company/lib-3': { version: '2.0.0', addToPackageJson: false },
|
||||
'@my-company/lib-3-child': {
|
||||
version: '2.0.0',
|
||||
addToPackageJson: false,
|
||||
},
|
||||
'@my-company/lib-4': { version: '2.0.1', addToPackageJson: false },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should properly handle cyclic dependency in nested packageGroup', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: {
|
||||
name: 'some-workspace',
|
||||
version: '0.0.0',
|
||||
|
||||
devDependencies: {
|
||||
'@my-company/nx-workspace': '0.9.0',
|
||||
'@my-company/lib-1': '0.9.0',
|
||||
'@my-company/lib-2': '0.9.0',
|
||||
},
|
||||
},
|
||||
versions: () => '1.0.0',
|
||||
fetch: async (pkg, version) => {
|
||||
if (pkg === '@my-company/nx-workspace' && version === '2.0.0') {
|
||||
return {
|
||||
version: '2.0.0',
|
||||
packageGroup: [
|
||||
{ package: '@my-company/lib-1', version: 'latest' },
|
||||
],
|
||||
};
|
||||
}
|
||||
if (pkg === '@my-company/nx-workspace' && version === '3.0.0') {
|
||||
return {
|
||||
version: '3.0.0',
|
||||
packageGroup: ['@my-company/lib-1', '@my-company/lib-2'],
|
||||
};
|
||||
}
|
||||
if (pkg === '@my-company/lib-1' && version === 'latest') {
|
||||
return {
|
||||
version: '3.0.0',
|
||||
packageGroup: ['@my-company/nx-workspace'],
|
||||
};
|
||||
}
|
||||
if (pkg === '@my-company/lib-1' && version === '3.0.0') {
|
||||
return {
|
||||
version: '3.0.0',
|
||||
packageGroup: ['@my-company/nx-workspace'],
|
||||
};
|
||||
}
|
||||
if (pkg === '@my-company/lib-2' && version === '3.0.0') {
|
||||
return {
|
||||
version: '3.0.0',
|
||||
packageGroup: [
|
||||
// this should be ignored because it's a smaller version
|
||||
{ package: '@my-company/nx-workspace', version: '2.99.0' },
|
||||
],
|
||||
};
|
||||
}
|
||||
throw new Error(`Should not call fetch for ${pkg}@${version}`);
|
||||
},
|
||||
to: {},
|
||||
});
|
||||
|
||||
expect(
|
||||
await migrator.updatePackageJson('@my-company/nx-workspace', '2.0.0')
|
||||
).toStrictEqual({
|
||||
migrations: [],
|
||||
packageJson: {
|
||||
'@my-company/nx-workspace': {
|
||||
version: '3.0.0',
|
||||
addToPackageJson: false,
|
||||
},
|
||||
'@my-company/lib-1': { version: '3.0.0', addToPackageJson: false },
|
||||
'@my-company/lib-2': { version: '3.0.0', addToPackageJson: false },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should not throw when packages are missing', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: {},
|
||||
packageJson: createPackageJson(),
|
||||
versions: (p) => (p === '@nrwl/nest' ? null : '1.0.0'),
|
||||
fetch: (_p, _v) =>
|
||||
Promise.resolve({
|
||||
version: '2.0.0',
|
||||
packageJsonUpdates: { one: { version: '2.0.0', packages: {} } },
|
||||
}),
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
await migrator.updatePackageJson('@nrwl/workspace', '2.0.0');
|
||||
@ -410,7 +489,7 @@ describe('Migration', () => {
|
||||
|
||||
it('should only fetch packages that are installed', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: {},
|
||||
packageJson: createPackageJson(),
|
||||
versions: (p) => (p === '@nrwl/nest' ? null : '1.0.0'),
|
||||
fetch: (p, _v) => {
|
||||
if (p === '@nrwl/nest') {
|
||||
@ -421,7 +500,6 @@ describe('Migration', () => {
|
||||
packageJsonUpdates: { one: { version: '2.0.0', packages: {} } },
|
||||
});
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
await migrator.updatePackageJson('@nrwl/workspace', '2.0.0');
|
||||
@ -429,7 +507,9 @@ describe('Migration', () => {
|
||||
|
||||
it('should only fetch packages that are top-level deps', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: { devDependencies: { parent: '1.0.0', child1: '1.0.0' } },
|
||||
packageJson: createPackageJson({
|
||||
devDependencies: { parent: '1.0.0', child1: '1.0.0' },
|
||||
}),
|
||||
versions: () => '1.0.0',
|
||||
fetch: (p, _v) => {
|
||||
if (p === 'parent') {
|
||||
@ -455,7 +535,6 @@ describe('Migration', () => {
|
||||
throw new Error('Boom');
|
||||
}
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
|
||||
@ -466,7 +545,9 @@ describe('Migration', () => {
|
||||
describe('migrations', () => {
|
||||
it('should create a list of migrations to run', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: { dependencies: { child: '1.0.0', newChild: '1.0.0' } },
|
||||
packageJson: createPackageJson({
|
||||
dependencies: { child: '1.0.0', newChild: '1.0.0' },
|
||||
}),
|
||||
versions: (p) => {
|
||||
if (p === 'parent') return '1.0.0';
|
||||
if (p === 'child') return '1.0.0';
|
||||
@ -518,7 +599,6 @@ describe('Migration', () => {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
expect(await migrator.updatePackageJson('parent', '2.0.0')).toEqual({
|
||||
@ -546,7 +626,7 @@ describe('Migration', () => {
|
||||
|
||||
it('should not generate migrations for non top-level packages', async () => {
|
||||
const migrator = new Migrator({
|
||||
packageJson: { dependencies: { child: '1.0.0' } },
|
||||
packageJson: createPackageJson({ dependencies: { child: '1.0.0' } }),
|
||||
versions: (p) => {
|
||||
if (p === 'parent') return '1.0.0';
|
||||
if (p === 'child') return '1.0.0';
|
||||
@ -599,7 +679,6 @@ describe('Migration', () => {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
},
|
||||
from: {},
|
||||
to: {},
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -119,7 +119,7 @@ export async function extractFileFromTarball(
|
||||
file: string,
|
||||
destinationFilePath: string
|
||||
) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
ensureDirSync(dirname(destinationFilePath));
|
||||
var tarExtractStream = tar.extract();
|
||||
const destinationFileStream = createWriteStream(destinationFilePath);
|
||||
@ -130,7 +130,7 @@ export async function extractFileFromTarball(
|
||||
stream.pipe(destinationFileStream);
|
||||
stream.on('end', () => {
|
||||
isFileExtracted = true;
|
||||
resolve();
|
||||
resolve(destinationFilePath);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -9,9 +9,15 @@ export interface NxProjectPackageJsonConfiguration {
|
||||
targets?: Record<string, PackageJsonTargetConfiguration>;
|
||||
}
|
||||
|
||||
export interface NxMigrationsConfiguration {
|
||||
migrations?: string;
|
||||
packageGroup?: (string | { package: string; version: string })[];
|
||||
}
|
||||
|
||||
export interface PackageJson {
|
||||
// Generic Package.Json Configuration
|
||||
name: string;
|
||||
version: string;
|
||||
scripts?: Record<string, string>;
|
||||
dependencies?: Record<string, string>;
|
||||
devDependencies?: Record<string, string>;
|
||||
@ -30,7 +36,8 @@ export interface PackageJson {
|
||||
schematics?: string;
|
||||
builders?: string;
|
||||
executors?: string;
|
||||
'nx-migrations'?: string;
|
||||
'nx-migrations'?: string | NxMigrationsConfiguration;
|
||||
'ng-update'?: string | NxMigrationsConfiguration;
|
||||
}
|
||||
|
||||
export function buildTargetFromScript(
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
import { execSync } from 'child_process';
|
||||
import { copyFileSync, existsSync, unlinkSync } from 'fs';
|
||||
import { exec, execSync } from 'child_process';
|
||||
import { copyFileSync, existsSync } from 'fs';
|
||||
import { remove } from 'fs-extra';
|
||||
import { dirname, join } from 'path';
|
||||
import { dirSync } from 'tmp';
|
||||
import { promisify } from 'util';
|
||||
import { readJsonFile, writeJsonFile } from './fileutils';
|
||||
import { PackageJson } from './package-json';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
export type PackageManager = 'yarn' | 'pnpm' | 'npm';
|
||||
|
||||
@ -114,25 +119,37 @@ export function checkForNPMRC(
|
||||
return existsSync(path) ? path : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary directory where you can run package manager commands safely.
|
||||
*
|
||||
* For cases where you'd want to install packages that require an `.npmrc` set up,
|
||||
* this function looks up for the nearest `.npmrc` (if exists) and copies it over to the
|
||||
* temp directory.
|
||||
*/
|
||||
export function createTempNpmDirectory(): string {
|
||||
const dir = dirSync().name;
|
||||
|
||||
// A package.json is needed for pnpm pack and for .npmrc to resolve
|
||||
writeJsonFile(`${dir}/package.json`, {});
|
||||
const npmrc = checkForNPMRC();
|
||||
if (npmrc) {
|
||||
// Copy npmrc if it exists, so that npm still follows it.
|
||||
copyFileSync(npmrc, `${dir}/.npmrc`);
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resolved version for a given package and version tag using the
|
||||
* NPM registry (when using Yarn it will fall back to NPM to fetch the info).
|
||||
*/
|
||||
export function resolvePackageVersionUsingRegistry(
|
||||
export async function resolvePackageVersionUsingRegistry(
|
||||
packageName: string,
|
||||
version: string
|
||||
): string {
|
||||
let pm = detectPackageManager();
|
||||
if (pm === 'yarn') {
|
||||
pm = 'npm';
|
||||
}
|
||||
|
||||
): Promise<string> {
|
||||
try {
|
||||
const result = execSync(`${pm} view ${packageName}@${version} version`, {
|
||||
stdio: [],
|
||||
})
|
||||
.toString()
|
||||
.trim();
|
||||
const result = await packageRegistryView(packageName, version, 'version');
|
||||
|
||||
if (!result) {
|
||||
throw new Error(`Unable to resolve version ${packageName}@${version}.`);
|
||||
@ -157,32 +174,69 @@ export function resolvePackageVersionUsingRegistry(
|
||||
* installing it in a temporary directory and fetching the version from the
|
||||
* package.json.
|
||||
*/
|
||||
export function resolvePackageVersionUsingInstallation(
|
||||
export async function resolvePackageVersionUsingInstallation(
|
||||
packageName: string,
|
||||
version: string
|
||||
): string {
|
||||
const dir = dirSync().name;
|
||||
const npmrc = checkForNPMRC();
|
||||
|
||||
writeJsonFile(`${dir}/package.json`, {});
|
||||
if (npmrc) {
|
||||
// Copy npmrc if it exists, so that npm still follows it.
|
||||
copyFileSync(npmrc, `${dir}/.npmrc`);
|
||||
}
|
||||
|
||||
const pmc = getPackageManagerCommand();
|
||||
execSync(`${pmc.add} ${packageName}@${version}`, { stdio: [], cwd: dir });
|
||||
|
||||
const packageJsonPath = require.resolve(`${packageName}/package.json`, {
|
||||
paths: [dir],
|
||||
});
|
||||
const { version: resolvedVersion } = readJsonFile(packageJsonPath);
|
||||
): Promise<string> {
|
||||
const dir = createTempNpmDirectory();
|
||||
|
||||
try {
|
||||
unlinkSync(dir);
|
||||
} catch {
|
||||
// It's okay if this fails, the OS will clean it up eventually
|
||||
const pmc = getPackageManagerCommand();
|
||||
await execAsync(`${pmc.add} ${packageName}@${version}`, { cwd: dir });
|
||||
|
||||
const packageJsonPath = require.resolve(`${packageName}/package.json`, {
|
||||
paths: [dir],
|
||||
});
|
||||
|
||||
return readJsonFile<PackageJson>(packageJsonPath).version;
|
||||
} finally {
|
||||
try {
|
||||
await remove(dir);
|
||||
} catch {
|
||||
// It's okay if this fails, the OS will clean it up eventually
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function packageRegistryView(
|
||||
pkg: string,
|
||||
version: string,
|
||||
args: string
|
||||
): Promise<string> {
|
||||
let pm = detectPackageManager();
|
||||
if (pm === 'yarn') {
|
||||
/**
|
||||
* yarn has `yarn info` but it behaves differently than (p)npm,
|
||||
* which makes it's usage unreliable
|
||||
*
|
||||
* @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
|
||||
*/
|
||||
pm = 'npm';
|
||||
}
|
||||
|
||||
return resolvedVersion;
|
||||
const { stdout } = await execAsync(`${pm} view ${pkg}@${version} ${args}`);
|
||||
return stdout.toString().trim();
|
||||
}
|
||||
|
||||
export async function packageRegistryPack(
|
||||
cwd: string,
|
||||
pkg: string,
|
||||
version: string
|
||||
): Promise<{ tarballPath: string }> {
|
||||
let pm = detectPackageManager();
|
||||
if (pm === 'yarn') {
|
||||
/**
|
||||
* `(p)npm pack` will download a tarball of the specified version,
|
||||
* whereas `yarn` pack creates a tarball of the active workspace, so it
|
||||
* does not work for getting the content of a library.
|
||||
*
|
||||
* @see https://github.com/nrwl/nx/pull/9667#discussion_r842553994
|
||||
*/
|
||||
pm = 'npm';
|
||||
}
|
||||
|
||||
const { stdout } = await execAsync(`${pm} pack ${pkg}@${version}`, { cwd });
|
||||
|
||||
const tarballPath = stdout.trim();
|
||||
return { tarballPath };
|
||||
}
|
||||
|
||||
@ -107,6 +107,7 @@ describe('project graph utils', () => {
|
||||
describe('mergeNpmScriptsWithTargets', () => {
|
||||
const packageJson: PackageJson = {
|
||||
name: 'my-app',
|
||||
version: '0.0.0',
|
||||
scripts: {
|
||||
build: 'echo 1',
|
||||
},
|
||||
|
||||
@ -47,7 +47,12 @@
|
||||
"@nrwl/nx-plugin",
|
||||
"@nrwl/react",
|
||||
"@nrwl/storybook",
|
||||
"@nrwl/web"
|
||||
"@nrwl/web",
|
||||
"@nrwl/js",
|
||||
"@nrwl/cli",
|
||||
"@nrwl/nx-cloud",
|
||||
"@nrwl/react-native",
|
||||
"@nrwl/detox"
|
||||
]
|
||||
},
|
||||
"peerDependencies": {
|
||||
@ -82,6 +87,32 @@
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"nx-migrations": {
|
||||
"migrations": "./migrations.json"
|
||||
"migrations": "./migrations.json",
|
||||
"packageGroup": [
|
||||
"@nrwl/workspace",
|
||||
"@nrwl/angular",
|
||||
"nx",
|
||||
"@nrwl/cypress",
|
||||
"@nrwl/devkit",
|
||||
"@nrwl/eslint-plugin-nx",
|
||||
"@nrwl/express",
|
||||
"@nrwl/jest",
|
||||
"@nrwl/linter",
|
||||
"@nrwl/nest",
|
||||
"@nrwl/next",
|
||||
"@nrwl/node",
|
||||
"@nrwl/nx-plugin",
|
||||
"@nrwl/react",
|
||||
"@nrwl/storybook",
|
||||
"@nrwl/web",
|
||||
"@nrwl/js",
|
||||
"@nrwl/cli",
|
||||
"@nrwl/react-native",
|
||||
"@nrwl/detox",
|
||||
{
|
||||
"package": "@nrwl/nx-cloud",
|
||||
"version": "latest"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user