diff --git a/scripts/angular-support-upgrades/build-migrations.ts b/scripts/angular-support-upgrades/build-migrations.ts index 6290b86b38..ce121411f7 100644 --- a/scripts/angular-support-upgrades/build-migrations.ts +++ b/scripts/angular-support-upgrades/build-migrations.ts @@ -1,11 +1,13 @@ +import axios from 'axios'; import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; +import { join } from 'path'; +import { gt, major, minor, parse } from 'semver'; import { getAngularCliMigrationGenerator, getAngularCliMigrationGeneratorSpec, } from './files/angular-cli-upgrade-migration'; -import { join } from 'path'; -function addMigrationPackageGroup( +async function addMigrationPackageGroup( angularPackageMigrations: Record, targetNxVersion: string, targetNxMigrationVersion: string, @@ -16,6 +18,24 @@ function addMigrationPackageGroup( packages: {}, }; + const promptAndRequirements = await getPromptAndRequiredVersions( + packageVersionMap + ); + if (!promptAndRequirements) { + console.warn( + '❗️ - The `@angular/core` latest version is greater than the next version. Skipping generating migration prompt and requirements.\n' + + ' Please review the migrations and manually add the prompt and requirements if needed.' + ); + } else { + angularPackageMigrations.packageJsonUpdates[targetNxVersion][ + 'x-prompt' + ] = `Do you want to update the Angular version to v${promptAndRequirements.promptVersion}?`; + angularPackageMigrations.packageJsonUpdates[targetNxVersion].requires = { + '@angular/core': promptAndRequirements.angularCoreRequirement, + typescript: promptAndRequirements.typescriptRequirement, + }; + } + for (const [pkgName, version] of packageVersionMap.entries()) { if ( pkgName.startsWith('@angular/') && @@ -33,7 +53,47 @@ function addMigrationPackageGroup( } } -export function buildMigrations( +async function getPromptAndRequiredVersions( + packageVersionMap: Map +): Promise<{ + angularCoreRequirement: string; + promptVersion: string; + typescriptRequirement: string; +} | null> { + // @angular/core + const angularCoreMetadata = await axios.get( + 'https://registry.npmjs.org/@angular/core' + ); + const { latest, next } = angularCoreMetadata.data['dist-tags']; + if (gt(latest, next)) { + return null; + } + const angularCoreRequirement = `>=${major(latest)}.${minor( + latest + )}.0 <${next}`; + + // prompt version (e.g. v16 or v16.1) + const angularCoreVersion = packageVersionMap.get('@angular/core'); + const { major: majorVersion, minor: minorVersion } = + parse(angularCoreVersion)!; + const promptVersion = `v${majorVersion}${ + minorVersion !== 0 ? `.${minorVersion}` : '' + }`; + + // typescript + const angularCompilerCliVersion = packageVersionMap.get( + '@angular/compiler-cli' + ); + const angularCompilerCliMetadata = await axios.get( + `https://registry.npmjs.org/@angular/compiler-cli/${angularCompilerCliVersion}` + ); + const typescriptRequirement = + angularCompilerCliMetadata.data.peerDependencies.typescript; + + return { angularCoreRequirement, promptVersion, typescriptRequirement }; +} + +export async function buildMigrations( packageVersionMap: Map, targetNxVersion: string, targetNxMigrationVersion: string @@ -44,7 +104,7 @@ export function buildMigrations( readFileSync(pathToMigrationsJsonFile, { encoding: 'utf-8' }) ); - addMigrationPackageGroup( + await addMigrationPackageGroup( angularPackageMigrations, targetNxVersion, targetNxMigrationVersion, @@ -55,7 +115,7 @@ export function buildMigrations( const angularCliMigrationGeneratorContents = getAngularCliMigrationGenerator(angularCLIVersion); const angularCliMigrationGeneratorSpecContents = - getAngularCliMigrationGeneratorSpec(angularCLIVersion); + getAngularCliMigrationGeneratorSpec(); // Create the directory update-targetNxVersion.dasherize() // Write the generator @@ -69,9 +129,13 @@ export function buildMigrations( '-' )}`; - angularPackageMigrations.schematics[generatorName] = { + const angularCoreVersion = packageVersionMap.get('@angular/core'); + angularPackageMigrations.generators[generatorName] = { cli: 'nx', version: targetNxMigrationVersion, + requires: { + '@angular/core': `>=${angularCoreVersion}`, + }, description: `Update the @angular/cli package version to ~${angularCLIVersion}.`, factory: `./src/migrations/${migrationGeneratorFolderName}/${migrationFileName}`, }; diff --git a/scripts/angular-support-upgrades/fetch-versions-from-registry.ts b/scripts/angular-support-upgrades/fetch-versions-from-registry.ts index d672edd87c..b4ba49d415 100644 --- a/scripts/angular-support-upgrades/fetch-versions-from-registry.ts +++ b/scripts/angular-support-upgrades/fetch-versions-from-registry.ts @@ -15,6 +15,9 @@ const packagesToUpdate = [ '@angular/router', '@angular/material', '@angular/cdk', + '@nguniversal/builders', + '@nguniversal/common', + '@nguniversal/express-engine', '@schematics/angular', 'ng-packagr', ]; @@ -30,6 +33,7 @@ export async function fetchVersionsFromRegistry( const latestVersion = distTags['latest']; if (targetVersion === 'latest') { packageVersionMap.set(pkgName, latestVersion); + console.log(` ${pkgName}: ${latestVersion}`); } else { const nextVersion = distTags['next']; const coercedNextVersion = coerce(nextVersion) as SemVer; @@ -38,12 +42,9 @@ export async function fetchVersionsFromRegistry( ? nextVersion : latestVersion; packageVersionMap.set(pkgName, versionToUse); + console.log(` ${pkgName}: ${versionToUse}`); } } - console.log( - `✅ - Fetched versions from registry (${packageVersionMap.get( - '@angular/cli' - )})` - ); + console.log('✅ - Finished fetching versions from registry'); return packageVersionMap; } diff --git a/scripts/angular-support-upgrades/files/angular-cli-upgrade-migration.ts b/scripts/angular-support-upgrades/files/angular-cli-upgrade-migration.ts index 51ea12d57e..8988502e5e 100644 --- a/scripts/angular-support-upgrades/files/angular-cli-upgrade-migration.ts +++ b/scripts/angular-support-upgrades/files/angular-cli-upgrade-migration.ts @@ -2,7 +2,7 @@ export const getAngularCliMigrationGenerator = ( version: string ) => `import { formatFiles, Tree, updateJson } from '@nx/devkit'; -const angularCliVersion = '~${version}'; +export const angularCliVersion = '~${version}'; export default async function (tree: Tree) { let shouldFormat = false; @@ -25,11 +25,10 @@ export default async function (tree: Tree) { } `; -export const getAngularCliMigrationGeneratorSpec = ( - version: string -) => `import { readJson, Tree, writeJson } from '@nx/devkit'; +export const getAngularCliMigrationGeneratorSpec = + () => `import { readJson, Tree, writeJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import updateAngularCli from './update-angular-cli'; +import updateAngularCli, { angularCliVersion } from './update-angular-cli'; describe('update-angular-cli migration', () => { let tree: Tree; @@ -46,7 +45,7 @@ describe('update-angular-cli migration', () => { await updateAngularCli(tree); const { devDependencies } = readJson(tree, 'package.json'); - expect(devDependencies['@angular/cli']).toEqual('~${version}'); + expect(devDependencies['@angular/cli']).toBe(angularCliVersion); }); it('should update @angular/cli version when defined as a dependency', async () => { @@ -57,10 +56,10 @@ describe('update-angular-cli migration', () => { await updateAngularCli(tree); const { dependencies } = readJson(tree, 'package.json'); - expect(dependencies['@angular/cli']).toEqual('~${version}'); + expect(dependencies['@angular/cli']).toBe(angularCliVersion); }); - it('should add @angular/cli to package.json when it is not set', async () => { + it('should not add @angular/cli to package.json when it is not set', async () => { const initialPackageJson = readJson(tree, 'package.json'); await updateAngularCli(tree); diff --git a/scripts/angular-support-upgrades/init-upgrade.ts b/scripts/angular-support-upgrades/init-upgrade.ts index 1cef45a55d..fa9523c9e3 100644 --- a/scripts/angular-support-upgrades/init-upgrade.ts +++ b/scripts/angular-support-upgrades/init-upgrade.ts @@ -9,9 +9,10 @@ * npx ts-node scripts/angular-support-upgrades/init-upgrade.ts --angularVersion=next --targetNxVersion=15.5.0 --targetNxMigrationVersion=15.5.0-beta.0 * */ +import { execSync } from 'child_process'; +import { buildMigrations } from './build-migrations'; import { fetchVersionsFromRegistry } from './fetch-versions-from-registry'; import { updatePackageJsonForAngular } from './update-package-jsons'; -import { buildMigrations } from './build-migrations'; import { updateVersionUtils } from './update-version-utils'; const yargs = require('yargs/yargs'); @@ -33,12 +34,20 @@ async function run() { argv.angularVersion ); await updatePackageJsonForAngular(packageVersionMap); - buildMigrations( + await buildMigrations( packageVersionMap, argv.targetNxVersion, argv.targetNxMigrationVersion ); updateVersionUtils(packageVersionMap); + + console.log('⏳ - Formatting files...'); + execSync('pnpm nx format', { stdio: 'inherit', encoding: 'utf8' }); + console.log('✅ - Finished formatting files'); + + console.log('⏳ - Installing packages...'); + execSync('pnpm install', { stdio: 'inherit', encoding: 'utf8' }); + console.log('✅ - Finished creating migrations!'); } run();