@@ -37,11 +37,6 @@ import {
37
37
} from '../utilities/package-tree' ;
38
38
import { Schema as UpdateCommandSchema } from './update' ;
39
39
40
- const NG_VERSION_9_POST_MSG = colors . cyan (
41
- '\nYour project has been updated to Angular version 9!\n' +
42
- 'For more info, please see: https://v9.angular.io/guide/updating-to-version-9' ,
43
- ) ;
44
-
45
40
const UPDATE_SCHEMATIC_COLLECTION = path . join (
46
41
__dirname ,
47
42
'../src/commands/update/schematic/collection.json' ,
@@ -57,6 +52,8 @@ const disableVersionCheck =
57
52
disableVersionCheckEnv !== '0' &&
58
53
disableVersionCheckEnv . toLowerCase ( ) !== 'false' ;
59
54
55
+ const ANGULAR_PACKAGES_REGEXP = / ^ @ (?: a n g u l a r | n g u n i v e r s a l ) \/ / ;
56
+
60
57
export class UpdateCommand extends Command < UpdateCommandSchema > {
61
58
public override readonly allowMissingWorkspace = true ;
62
59
private workflow ! : NodeWorkflow ;
@@ -272,19 +269,26 @@ export class UpdateCommand extends Command<UpdateCommandSchema> {
272
269
async run ( options : UpdateCommandSchema & Arguments ) {
273
270
await ensureCompatibleNpm ( this . context . root ) ;
274
271
275
- // Check if the current installed CLI version is older than the latest version.
276
- if ( ! disableVersionCheck && ( await this . checkCLILatestVersion ( options . verbose , options . next ) ) ) {
277
- this . logger . warn (
278
- `The installed local Angular CLI version is older than the latest ${
279
- options . next ? 'pre-release' : 'stable'
280
- } version.\n` + 'Installing a temporary version to perform the update.' ,
272
+ // Check if the current installed CLI version is older than the latest compatible version.
273
+ if ( ! disableVersionCheck ) {
274
+ const cliVersionToInstall = await this . checkCLIVersion (
275
+ options [ '--' ] ,
276
+ options . verbose ,
277
+ options . next ,
281
278
) ;
282
279
283
- return runTempPackageBin (
284
- `@angular/cli@${ options . next ? 'next' : 'latest' } ` ,
285
- this . packageManager ,
286
- process . argv . slice ( 2 ) ,
287
- ) ;
280
+ if ( cliVersionToInstall ) {
281
+ this . logger . warn (
282
+ 'The installed Angular CLI version is outdated.\n' +
283
+ `Installing a temporary Angular CLI versioned ${ cliVersionToInstall } to perform the update.` ,
284
+ ) ;
285
+
286
+ return runTempPackageBin (
287
+ `@angular/cli@${ cliVersionToInstall } ` ,
288
+ this . packageManager ,
289
+ process . argv . slice ( 2 ) ,
290
+ ) ;
291
+ }
288
292
}
289
293
290
294
const logVerbose = ( message : string ) => {
@@ -452,8 +456,7 @@ export class UpdateCommand extends Command<UpdateCommandSchema> {
452
456
453
457
if ( migrations . startsWith ( '../' ) ) {
454
458
this . logger . error (
455
- 'Package contains an invalid migrations field. ' +
456
- 'Paths outside the package root are not permitted.' ,
459
+ 'Package contains an invalid migrations field. Paths outside the package root are not permitted.' ,
457
460
) ;
458
461
459
462
return 1 ;
@@ -479,9 +482,8 @@ export class UpdateCommand extends Command<UpdateCommandSchema> {
479
482
}
480
483
}
481
484
482
- let success = false ;
483
485
if ( typeof options . migrateOnly == 'string' ) {
484
- success = await this . executeMigration (
486
+ await this . executeMigration (
485
487
packageName ,
486
488
migrations ,
487
489
options . migrateOnly ,
@@ -495,7 +497,7 @@ export class UpdateCommand extends Command<UpdateCommandSchema> {
495
497
return 1 ;
496
498
}
497
499
498
- success = await this . executeMigrations (
500
+ await this . executeMigrations (
499
501
packageName ,
500
502
migrations ,
501
503
from ,
@@ -504,19 +506,6 @@ export class UpdateCommand extends Command<UpdateCommandSchema> {
504
506
) ;
505
507
}
506
508
507
- if ( success ) {
508
- if (
509
- packageName === '@angular/core' &&
510
- options . from &&
511
- + options . from . split ( '.' ) [ 0 ] < 9 &&
512
- ( options . to || packageNode . version ) . split ( '.' ) [ 0 ] === '9'
513
- ) {
514
- this . logger . info ( NG_VERSION_9_POST_MSG ) ;
515
- }
516
-
517
- return 0 ;
518
- }
519
-
520
509
return 1 ;
521
510
}
522
511
@@ -612,7 +601,7 @@ export class UpdateCommand extends Command<UpdateCommandSchema> {
612
601
continue ;
613
602
}
614
603
615
- if ( node . package && / ^ @ (?: a n g u l a r | n g u n i v e r s a l ) \/ / . test ( node . package . name ) ) {
604
+ if ( node . package && ANGULAR_PACKAGES_REGEXP . test ( node . package . name ) ) {
616
605
const { name, version } = node . package ;
617
606
const toBeInstalledMajorVersion = + manifest . version . split ( '.' ) [ 0 ] ;
618
607
const currentMajorVersion = + version . split ( '.' ) [ 0 ] ;
@@ -791,17 +780,6 @@ export class UpdateCommand extends Command<UpdateCommandSchema> {
791
780
return 0 ;
792
781
}
793
782
}
794
-
795
- if (
796
- migrations . some (
797
- ( m ) =>
798
- m . package === '@angular/core' &&
799
- m . to . split ( '.' ) [ 0 ] === '9' &&
800
- + m . from . split ( '.' ) [ 0 ] < 9 ,
801
- )
802
- ) {
803
- this . logger . info ( NG_VERSION_9_POST_MSG ) ;
804
- }
805
783
}
806
784
807
785
return success ? 0 : 1 ;
@@ -879,22 +857,55 @@ export class UpdateCommand extends Command<UpdateCommandSchema> {
879
857
}
880
858
881
859
/**
882
- * Checks if the current installed CLI version is older than the latest version.
883
- * @returns `true` when the installed version is older .
860
+ * Checks if the current installed CLI version is older or newer than a compatible version.
861
+ * @returns the version to install or null when there is no update to install .
884
862
*/
885
- private async checkCLILatestVersion ( verbose = false , next = false ) : Promise < boolean > {
886
- const installedCLIVersion = VERSION . full ;
887
-
888
- const LatestCLIManifest = await fetchPackageManifest (
889
- `@angular/cli@${ next ? 'next' : 'latest' } ` ,
863
+ private async checkCLIVersion (
864
+ packagesToUpdate : string [ ] | undefined ,
865
+ verbose = false ,
866
+ next = false ,
867
+ ) : Promise < string | null > {
868
+ const { version } = await fetchPackageManifest (
869
+ `@angular/cli@${ this . getCLIUpdateRunnerVersion ( packagesToUpdate , next ) } ` ,
890
870
this . logger ,
891
871
{
892
872
verbose,
893
873
usingYarn : this . packageManager === PackageManager . Yarn ,
894
874
} ,
895
875
) ;
896
876
897
- return semver . lt ( installedCLIVersion , LatestCLIManifest . version ) ;
877
+ return VERSION . full === version ? null : version ;
878
+ }
879
+
880
+ private getCLIUpdateRunnerVersion (
881
+ packagesToUpdate : string [ ] | undefined ,
882
+ next : boolean ,
883
+ ) : string | number {
884
+ if ( next ) {
885
+ return 'next' ;
886
+ }
887
+
888
+ const updatingAngularPackage = packagesToUpdate ?. find ( ( r ) => ANGULAR_PACKAGES_REGEXP . test ( r ) ) ;
889
+ if ( updatingAngularPackage ) {
890
+ // If we are updating any Angular package we can update the CLI to the target version because
891
+ // migrations for @angular /core@13 can be executed using Angular/cli@13.
892
+ // This is same behaviour as `npx @angular/cli@13 update @angular/core@13`.
893
+
894
+ // `@angular/cli@13` -> ['', 'angular/cli', '13']
895
+ // `@angular/cli` -> ['', 'angular/cli']
896
+ const tempVersion = coerceVersionNumber ( updatingAngularPackage . split ( '@' ) [ 2 ] ) ;
897
+
898
+ return semver . parse ( tempVersion ) ?. major ?? 'latest' ;
899
+ }
900
+
901
+ // When not updating an Angular package we cannot determine which schematic runtime the migration should to be executed in.
902
+ // Typically, we can assume that the `@angular/cli` was updated previously.
903
+ // Example: Angular official packages are typically updated prior to NGRX etc...
904
+ // Therefore, we only update to the latest patch version of the installed major version of the Angular CLI.
905
+
906
+ // This is important because we might end up in a scenario where locally Angular v12 is installed, updating NGRX from 11 to 12.
907
+ // We end up using Angular ClI v13 to run the migrations if we run the migrations using the CLI installed major version + 1 logic.
908
+ return VERSION . major ;
898
909
}
899
910
}
900
911
0 commit comments