@angular/cli 21.1.0-next.1 → 21.1.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/lib/code-examples.db +0 -0
  2. package/package.json +16 -16
  3. package/src/commands/add/cli.js +129 -87
  4. package/src/commands/add/cli.js.map +1 -1
  5. package/src/commands/mcp/cli.js +4 -1
  6. package/src/commands/mcp/cli.js.map +1 -1
  7. package/src/commands/mcp/{dev-server.d.ts → devserver.d.ts} +4 -4
  8. package/src/commands/mcp/{dev-server.js → devserver.js} +14 -14
  9. package/src/commands/mcp/devserver.js.map +1 -0
  10. package/src/commands/mcp/mcp-server.d.ts +30 -0
  11. package/src/commands/mcp/mcp-server.js +22 -7
  12. package/src/commands/mcp/mcp-server.js.map +1 -1
  13. package/src/commands/mcp/tools/best-practices.js.map +1 -1
  14. package/src/commands/mcp/tools/build.js +2 -2
  15. package/src/commands/mcp/tools/build.js.map +1 -1
  16. package/src/commands/mcp/tools/devserver/{start-devserver.d.ts → devserver-start.d.ts} +6 -7
  17. package/src/commands/mcp/tools/devserver/{start-devserver.js → devserver-start.js} +26 -27
  18. package/src/commands/mcp/tools/devserver/devserver-start.js.map +1 -0
  19. package/src/commands/mcp/tools/devserver/{stop-devserver.d.ts → devserver-stop.d.ts} +6 -6
  20. package/src/commands/mcp/tools/devserver/{stop-devserver.js → devserver-stop.js} +13 -13
  21. package/src/commands/mcp/tools/devserver/{stop-devserver.js.map → devserver-stop.js.map} +1 -1
  22. package/src/commands/mcp/tools/devserver/{wait-for-devserver-build.d.ts → devserver-wait-for-build.d.ts} +6 -6
  23. package/src/commands/mcp/tools/devserver/{wait-for-devserver-build.js → devserver-wait-for-build.js} +16 -16
  24. package/src/commands/mcp/tools/devserver/{wait-for-devserver-build.js.map → devserver-wait-for-build.js.map} +1 -1
  25. package/src/commands/mcp/tools/modernize.js +1 -1
  26. package/src/commands/mcp/tools/modernize.js.map +1 -1
  27. package/src/commands/mcp/tools/tool-registry.d.ts +2 -2
  28. package/src/commands/mcp/tools/tool-registry.js.map +1 -1
  29. package/src/commands/update/cli.d.ts +0 -24
  30. package/src/commands/update/cli.js +39 -447
  31. package/src/commands/update/cli.js.map +1 -1
  32. package/src/commands/update/utilities/cli-version.d.ts +48 -0
  33. package/src/commands/update/utilities/cli-version.js +196 -0
  34. package/src/commands/update/utilities/cli-version.js.map +1 -0
  35. package/src/commands/update/utilities/constants.d.ts +12 -0
  36. package/src/commands/update/utilities/constants.js +16 -0
  37. package/src/commands/update/utilities/constants.js.map +1 -0
  38. package/src/commands/update/utilities/git.d.ts +34 -0
  39. package/src/commands/update/utilities/git.js +115 -0
  40. package/src/commands/update/utilities/git.js.map +1 -0
  41. package/src/commands/update/utilities/migration.d.ts +32 -0
  42. package/src/commands/update/utilities/migration.js +257 -0
  43. package/src/commands/update/utilities/migration.js.map +1 -0
  44. package/src/package-managers/error.d.ts +12 -0
  45. package/src/package-managers/host.js +7 -3
  46. package/src/package-managers/host.js.map +1 -1
  47. package/src/package-managers/package-manager-descriptor.d.ts +28 -4
  48. package/src/package-managers/package-manager-descriptor.js +24 -4
  49. package/src/package-managers/package-manager-descriptor.js.map +1 -1
  50. package/src/package-managers/package-manager.js +61 -7
  51. package/src/package-managers/package-manager.js.map +1 -1
  52. package/src/package-managers/parsers.d.ts +69 -4
  53. package/src/package-managers/parsers.js +231 -32
  54. package/src/package-managers/parsers.js.map +1 -1
  55. package/src/utilities/version.js +1 -1
  56. package/src/commands/mcp/dev-server.js.map +0 -1
  57. package/src/commands/mcp/tools/devserver/start-devserver.js.map +0 -1
@@ -28,31 +28,7 @@ export default class UpdateCommandModule extends CommandModule<UpdateCommandArgs
28
28
  longDescriptionPath: string;
29
29
  builder(localYargs: Argv): Argv<UpdateCommandArgs>;
30
30
  run(options: Options<UpdateCommandArgs>): Promise<number | void>;
31
- private executeSchematic;
32
- /**
33
- * @return Whether or not the migration was performed successfully.
34
- */
35
- private executeMigration;
36
- /**
37
- * @return Whether or not the migrations were performed successfully.
38
- */
39
- private executeMigrations;
40
- private executePackageMigrations;
41
31
  private migrateOnly;
42
32
  private updatePackagesAndMigrate;
43
- /**
44
- * @return Whether or not the commit was successful.
45
- */
46
- private commit;
47
- private checkCleanGit;
48
- /**
49
- * Checks if the current installed CLI version is older or newer than a compatible version.
50
- * @returns the version to install or null when there is no update to install.
51
- */
52
- private checkCLIVersion;
53
- private getCLIUpdateRunnerVersion;
54
- private runTempBinary;
55
- private packageManagerForce;
56
- private getOptionalMigrationsToRun;
57
33
  }
58
34
  export {};
@@ -43,32 +43,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
43
43
  return (mod && mod.__esModule) ? mod : { "default": mod };
44
44
  };
45
45
  Object.defineProperty(exports, "__esModule", { value: true });
46
- const schematics_1 = require("@angular-devkit/schematics");
47
46
  const tools_1 = require("@angular-devkit/schematics/tools");
48
47
  const listr2_1 = require("listr2");
49
- const node_child_process_1 = require("node:child_process");
50
48
  const node_fs_1 = require("node:fs");
51
49
  const node_module_1 = require("node:module");
52
50
  const path = __importStar(require("node:path"));
53
- const node_path_1 = require("node:path");
54
51
  const npm_package_arg_1 = __importDefault(require("npm-package-arg"));
55
- const semver = __importStar(require("semver"));
56
- const workspace_schema_1 = require("../../../lib/config/workspace-schema");
57
52
  const command_module_1 = require("../../command-builder/command-module");
58
53
  const schematic_engine_host_1 = require("../../command-builder/utilities/schematic-engine-host");
59
- const schematic_workflow_1 = require("../../command-builder/utilities/schematic-workflow");
54
+ const package_managers_1 = require("../../package-managers");
60
55
  const color_1 = require("../../utilities/color");
61
56
  const environment_options_1 = require("../../utilities/environment-options");
62
57
  const error_1 = require("../../utilities/error");
63
- const log_file_1 = require("../../utilities/log-file");
64
- const package_metadata_1 = require("../../utilities/package-metadata");
65
58
  const package_tree_1 = require("../../utilities/package-tree");
66
- const prompt_1 = require("../../utilities/prompt");
67
- const tty_1 = require("../../utilities/tty");
68
- const version_1 = require("../../utilities/version");
59
+ const cli_version_1 = require("./utilities/cli-version");
60
+ const constants_1 = require("./utilities/constants");
61
+ const git_1 = require("./utilities/git");
62
+ const migration_1 = require("./utilities/migration");
69
63
  class CommandError extends Error {
70
64
  }
71
- const ANGULAR_PACKAGES_REGEXP = /^@(?:angular|nguniversal)\//;
72
65
  const UPDATE_SCHEMATIC_COLLECTION = path.join(__dirname, 'schematic/collection.json');
73
66
  class UpdateCommandModule extends command_module_1.CommandModule {
74
67
  scope = command_module_1.CommandScope.In;
@@ -76,7 +69,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
76
69
  resolvePaths = [__dirname, this.context.root];
77
70
  command = 'update [packages..]';
78
71
  describe = 'Updates your workspace and its dependencies. See https://update.angular.dev/.';
79
- longDescriptionPath = (0, node_path_1.join)(__dirname, 'long-description.md');
72
+ longDescriptionPath = path.join(__dirname, 'long-description.md');
80
73
  builder(localYargs) {
81
74
  return localYargs
82
75
  .positional('packages', {
@@ -143,7 +136,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
143
136
  .check(({ packages, 'allow-dirty': allowDirty, 'migrate-only': migrateOnly }) => {
144
137
  const { logger } = this.context;
145
138
  // This allows the user to easily reset any changes from the update.
146
- if (packages?.length && !this.checkCleanGit()) {
139
+ if (packages?.length && !(0, git_1.checkCleanGit)(this.context.root)) {
147
140
  if (allowDirty) {
148
141
  logger.warn('Repository is not clean. Update changes will be mixed with pre-existing changes.');
149
142
  }
@@ -161,15 +154,21 @@ class UpdateCommandModule extends command_module_1.CommandModule {
161
154
  .strict();
162
155
  }
163
156
  async run(options) {
164
- const { logger, packageManager } = this.context;
157
+ const { logger } = this.context;
158
+ // Instantiate the package manager
159
+ const packageManager = await (0, package_managers_1.createPackageManager)({
160
+ cwd: this.context.root,
161
+ logger,
162
+ configuredPackageManager: this.context.packageManager.name,
163
+ });
165
164
  // Check if the current installed CLI version is older than the latest compatible version.
166
165
  // Skip when running `ng update` without a package name as this will not trigger an actual update.
167
166
  if (!environment_options_1.disableVersionCheck && options.packages?.length) {
168
- const cliVersionToInstall = await this.checkCLIVersion(options.packages, options.verbose, options.next);
167
+ const cliVersionToInstall = await (0, cli_version_1.checkCLIVersion)(options.packages, logger, packageManager, options.next);
169
168
  if (cliVersionToInstall) {
170
169
  logger.warn('The installed Angular CLI version is outdated.\n' +
171
170
  `Installing a temporary Angular CLI versioned ${cliVersionToInstall} to perform the update.`);
172
- return this.runTempBinary(`@angular/cli@${cliVersionToInstall}`, process.argv.slice(2));
171
+ return (0, cli_version_1.runTempBinary)(`@angular/cli@${cliVersionToInstall}`, packageManager, process.argv.slice(2));
173
172
  }
174
173
  }
175
174
  const packages = [];
@@ -208,7 +207,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
208
207
  logger.info(`Found ${rootDependencies.size} dependencies.`);
209
208
  const workflow = new tools_1.NodeWorkflow(this.context.root, {
210
209
  packageManager: packageManager.name,
211
- packageManagerForce: this.packageManagerForce(options.verbose),
210
+ packageManagerForce: await (0, cli_version_1.shouldForcePackageManager)(packageManager, logger, options.verbose),
212
211
  // __dirname -> favor @schematics/update from this package
213
212
  // Otherwise, use packages from the active workspace (migrations)
214
213
  resolvePaths: this.resolvePaths,
@@ -217,7 +216,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
217
216
  });
218
217
  if (packages.length === 0) {
219
218
  // Show status
220
- const { success } = await this.executeSchematic(workflow, UPDATE_SCHEMATIC_COLLECTION, 'update', {
219
+ const { success } = await (0, migration_1.executeSchematic)(workflow, logger, UPDATE_SCHEMATIC_COLLECTION, 'update', {
221
220
  force: options.force,
222
221
  next: options.next,
223
222
  verbose: options.verbose,
@@ -228,136 +227,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
228
227
  }
229
228
  return options.migrateOnly
230
229
  ? this.migrateOnly(workflow, (options.packages ?? [])[0], rootDependencies, options)
231
- : this.updatePackagesAndMigrate(workflow, rootDependencies, options, packages);
232
- }
233
- async executeSchematic(workflow, collection, schematic, options = {}) {
234
- const { logger } = this.context;
235
- const workflowSubscription = (0, schematic_workflow_1.subscribeToWorkflow)(workflow, logger);
236
- // TODO: Allow passing a schematic instance directly
237
- try {
238
- await workflow
239
- .execute({
240
- collection,
241
- schematic,
242
- options,
243
- logger,
244
- })
245
- .toPromise();
246
- return { success: !workflowSubscription.error, files: workflowSubscription.files };
247
- }
248
- catch (e) {
249
- if (e instanceof schematics_1.UnsuccessfulWorkflowExecution) {
250
- logger.error(`${color_1.figures.cross} Migration failed. See above for further details.\n`);
251
- }
252
- else {
253
- (0, error_1.assertIsError)(e);
254
- const logPath = (0, log_file_1.writeErrorToLogFile)(e);
255
- logger.fatal(`${color_1.figures.cross} Migration failed: ${e.message}\n` +
256
- ` See "${logPath}" for further details.\n`);
257
- }
258
- return { success: false, files: workflowSubscription.files };
259
- }
260
- finally {
261
- workflowSubscription.unsubscribe();
262
- }
263
- }
264
- /**
265
- * @return Whether or not the migration was performed successfully.
266
- */
267
- async executeMigration(workflow, packageName, collectionPath, migrationName, commit) {
268
- const { logger } = this.context;
269
- const collection = workflow.engine.createCollection(collectionPath);
270
- const name = collection.listSchematicNames().find((name) => name === migrationName);
271
- if (!name) {
272
- logger.error(`Cannot find migration '${migrationName}' in '${packageName}'.`);
273
- return 1;
274
- }
275
- logger.info(color_1.colors.cyan(`** Executing '${migrationName}' of package '${packageName}' **\n`));
276
- const schematic = workflow.engine.createSchematic(name, collection);
277
- return this.executePackageMigrations(workflow, [schematic.description], packageName, commit);
278
- }
279
- /**
280
- * @return Whether or not the migrations were performed successfully.
281
- */
282
- async executeMigrations(workflow, packageName, collectionPath, from, to, commit) {
283
- const collection = workflow.engine.createCollection(collectionPath);
284
- const migrationRange = new semver.Range('>' + (semver.prerelease(from) ? from.split('-')[0] + '-0' : from) + ' <=' + to.split('-')[0]);
285
- const requiredMigrations = [];
286
- const optionalMigrations = [];
287
- for (const name of collection.listSchematicNames()) {
288
- const schematic = workflow.engine.createSchematic(name, collection);
289
- const description = schematic.description;
290
- description.version = coerceVersionNumber(description.version);
291
- if (!description.version) {
292
- continue;
293
- }
294
- if (semver.satisfies(description.version, migrationRange, { includePrerelease: true })) {
295
- (description.optional ? optionalMigrations : requiredMigrations).push(description);
296
- }
297
- }
298
- if (requiredMigrations.length === 0 && optionalMigrations.length === 0) {
299
- return 0;
300
- }
301
- // Required migrations
302
- if (requiredMigrations.length) {
303
- this.context.logger.info(color_1.colors.cyan(`** Executing migrations of package '${packageName}' **\n`));
304
- requiredMigrations.sort((a, b) => semver.compare(a.version, b.version) || a.name.localeCompare(b.name));
305
- const result = await this.executePackageMigrations(workflow, requiredMigrations, packageName, commit);
306
- if (result === 1) {
307
- return 1;
308
- }
309
- }
310
- // Optional migrations
311
- if (optionalMigrations.length) {
312
- this.context.logger.info(color_1.colors.magenta(`** Optional migrations of package '${packageName}' **\n`));
313
- optionalMigrations.sort((a, b) => semver.compare(a.version, b.version) || a.name.localeCompare(b.name));
314
- const migrationsToRun = await this.getOptionalMigrationsToRun(optionalMigrations, packageName);
315
- if (migrationsToRun?.length) {
316
- return this.executePackageMigrations(workflow, migrationsToRun, packageName, commit);
317
- }
318
- }
319
- return 0;
320
- }
321
- async executePackageMigrations(workflow, migrations, packageName, commit = false) {
322
- const { logger } = this.context;
323
- for (const migration of migrations) {
324
- const { title, description } = getMigrationTitleAndDescription(migration);
325
- logger.info(color_1.colors.cyan(color_1.figures.pointer) + ' ' + color_1.colors.bold(title));
326
- if (description) {
327
- logger.info(' ' + description);
328
- }
329
- const { success, files } = await this.executeSchematic(workflow, migration.collection.name, migration.name);
330
- if (!success) {
331
- return 1;
332
- }
333
- let modifiedFilesText;
334
- switch (files.size) {
335
- case 0:
336
- modifiedFilesText = 'No changes made';
337
- break;
338
- case 1:
339
- modifiedFilesText = '1 file modified';
340
- break;
341
- default:
342
- modifiedFilesText = `${files.size} files modified`;
343
- break;
344
- }
345
- logger.info(` Migration completed (${modifiedFilesText}).`);
346
- // Commit migration
347
- if (commit) {
348
- const commitPrefix = `${packageName} migration - ${migration.name}`;
349
- const commitMessage = migration.description
350
- ? `${commitPrefix}\n\n${migration.description}`
351
- : commitPrefix;
352
- const committed = this.commit(commitMessage);
353
- if (!committed) {
354
- // Failed to commit, something went wrong. Abort the update.
355
- return 1;
356
- }
357
- }
358
- logger.info(''); // Extra trailing newline.
359
- }
360
- return 0;
230
+ : this.updatePackagesAndMigrate(workflow, rootDependencies, options, packages, packageManager);
361
231
  }
362
232
  async migrateOnly(workflow, packageName, rootDependencies, options) {
363
233
  const { logger } = this.context;
@@ -426,17 +296,17 @@ class UpdateCommandModule extends command_module_1.CommandModule {
426
296
  }
427
297
  }
428
298
  if (options.name) {
429
- return this.executeMigration(workflow, packageName, migrations, options.name, options.createCommits);
299
+ return (0, migration_1.executeMigration)(workflow, logger, packageName, migrations, options.name, options.createCommits);
430
300
  }
431
- const from = coerceVersionNumber(options.from);
301
+ const from = (0, cli_version_1.coerceVersionNumber)(options.from);
432
302
  if (!from) {
433
303
  logger.error(`"from" value [${options.from}] is not a valid version.`);
434
304
  return 1;
435
305
  }
436
- return this.executeMigrations(workflow, packageName, migrations, from, options.to || packageNode.version, options.createCommits);
306
+ return (0, migration_1.executeMigrations)(workflow, logger, packageName, migrations, from, options.to || packageNode.version, options.createCommits);
437
307
  }
438
308
  // eslint-disable-next-line max-lines-per-function
439
- async updatePackagesAndMigrate(workflow, rootDependencies, options, packages) {
309
+ async updatePackagesAndMigrate(workflow, rootDependencies, options, packages, packageManager) {
440
310
  const { logger } = this.context;
441
311
  const logVerbose = (message) => {
442
312
  if (options.verbose) {
@@ -446,6 +316,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
446
316
  const requests = [];
447
317
  // Validate packages actually are part of the workspace
448
318
  for (const pkg of packages) {
319
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
449
320
  const node = rootDependencies.get(pkg.name);
450
321
  if (!node?.package) {
451
322
  logger.error(`Package '${pkg.name}' is not a dependency.`);
@@ -465,56 +336,15 @@ class UpdateCommandModule extends command_module_1.CommandModule {
465
336
  const packagesToUpdate = [];
466
337
  for (const { identifier: requestIdentifier, node } of requests) {
467
338
  const packageName = requestIdentifier.name;
468
- let metadata;
339
+ let manifest = null;
469
340
  try {
470
- // Metadata requests are internally cached; multiple requests for same name
471
- // does not result in additional network traffic
472
- metadata = await (0, package_metadata_1.fetchPackageMetadata)(packageName, logger, {
473
- verbose: options.verbose,
474
- });
341
+ manifest = await packageManager.getManifest(requestIdentifier);
475
342
  }
476
343
  catch (e) {
477
344
  (0, error_1.assertIsError)(e);
478
- logger.error(`Error fetching metadata for '${packageName}': ` + e.message);
345
+ logger.error(`Error fetching manifest for '${packageName}': ` + e.message);
479
346
  return 1;
480
347
  }
481
- // Try to find a package version based on the user requested package specifier
482
- // registry specifier types are either version, range, or tag
483
- let manifest;
484
- switch (requestIdentifier.type) {
485
- case 'tag':
486
- manifest = metadata.tags[requestIdentifier.fetchSpec];
487
- // If not found and next option was used and user did not provide a specifier, try latest.
488
- // Package may not have a next tag.
489
- if (!manifest &&
490
- requestIdentifier.fetchSpec === 'next' &&
491
- requestIdentifier.rawSpec === '*') {
492
- manifest = metadata.tags['latest'];
493
- }
494
- break;
495
- case 'version':
496
- manifest = metadata.versions[requestIdentifier.fetchSpec];
497
- break;
498
- case 'range':
499
- for (const potentialManifest of Object.values(metadata.versions)) {
500
- // Ignore deprecated package versions
501
- if (potentialManifest.deprecated) {
502
- continue;
503
- }
504
- // Only consider versions that are within the range
505
- if (!semver.satisfies(potentialManifest.version, requestIdentifier.fetchSpec, {
506
- loose: true,
507
- })) {
508
- continue;
509
- }
510
- // Update the used manifest if current potential is newer than existing or there is not one yet
511
- if (!manifest ||
512
- semver.gt(potentialManifest.version, manifest.version, { loose: true })) {
513
- manifest = potentialManifest;
514
- }
515
- }
516
- break;
517
- }
518
348
  if (!manifest) {
519
349
  logger.error(`Package specified by '${requestIdentifier.raw}' does not exist within the registry.`);
520
350
  return 1;
@@ -523,7 +353,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
523
353
  logger.info(`Package '${packageName}' is already up to date.`);
524
354
  continue;
525
355
  }
526
- if (node.package && ANGULAR_PACKAGES_REGEXP.test(node.package.name)) {
356
+ if (node.package && constants_1.ANGULAR_PACKAGES_REGEXP.test(node.package.name)) {
527
357
  const { name, version } = node.package;
528
358
  const toBeInstalledMajorVersion = +manifest.version.split('.')[0];
529
359
  const currentMajorVersion = +version.split('.')[0];
@@ -550,7 +380,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
550
380
  if (packagesToUpdate.length === 0) {
551
381
  return 0;
552
382
  }
553
- const { success } = await this.executeSchematic(workflow, UPDATE_SCHEMATIC_COLLECTION, 'update', {
383
+ const { success } = await (0, migration_1.executeSchematic)(workflow, logger, UPDATE_SCHEMATIC_COLLECTION, 'update', {
554
384
  verbose: options.verbose,
555
385
  force: options.force,
556
386
  next: options.next,
@@ -558,8 +388,8 @@ class UpdateCommandModule extends command_module_1.CommandModule {
558
388
  packages: packagesToUpdate,
559
389
  });
560
390
  if (success) {
561
- const { root: commandRoot, packageManager } = this.context;
562
- const installArgs = this.packageManagerForce(options.verbose) ? ['--force'] : [];
391
+ const { root: commandRoot } = this.context;
392
+ const force = await (0, cli_version_1.shouldForcePackageManager)(packageManager, logger, options.verbose);
563
393
  const tasks = new listr2_1.Listr([
564
394
  {
565
395
  title: 'Cleaning node modules directory',
@@ -582,8 +412,12 @@ class UpdateCommandModule extends command_module_1.CommandModule {
582
412
  {
583
413
  title: 'Installing packages',
584
414
  async task() {
585
- const installationSuccess = await packageManager.installAll(installArgs, commandRoot);
586
- if (!installationSuccess) {
415
+ try {
416
+ await packageManager.install({
417
+ force,
418
+ });
419
+ }
420
+ catch (e) {
587
421
  throw new CommandError('Unable to install packages');
588
422
  }
589
423
  },
@@ -600,7 +434,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
600
434
  }
601
435
  }
602
436
  if (success && options.createCommits) {
603
- if (!this.commit(`Angular CLI update for packages - ${packagesToUpdate.join(', ')}`)) {
437
+ if (!(0, migration_1.commitChanges)(logger, `Angular CLI update for packages - ${packagesToUpdate.join(', ')}`)) {
604
438
  return 1;
605
439
  }
606
440
  }
@@ -667,7 +501,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
667
501
  return 1;
668
502
  }
669
503
  }
670
- const result = await this.executeMigrations(workflow, migration.package, migrations, migration.from, migration.to, options.createCommits);
504
+ const result = await (0, migration_1.executeMigrations)(workflow, logger, migration.package, migrations, migration.from, migration.to, options.createCommits);
671
505
  // A non-zero value is a failure for the package's migrations
672
506
  if (result !== 0) {
673
507
  return result;
@@ -676,248 +510,6 @@ class UpdateCommandModule extends command_module_1.CommandModule {
676
510
  }
677
511
  return success ? 0 : 1;
678
512
  }
679
- /**
680
- * @return Whether or not the commit was successful.
681
- */
682
- commit(message) {
683
- const { logger } = this.context;
684
- // Check if a commit is needed.
685
- let commitNeeded;
686
- try {
687
- commitNeeded = hasChangesToCommit();
688
- }
689
- catch (err) {
690
- logger.error(` Failed to read Git tree:\n${err.stderr}`);
691
- return false;
692
- }
693
- if (!commitNeeded) {
694
- logger.info(' No changes to commit after migration.');
695
- return true;
696
- }
697
- // Commit changes and abort on error.
698
- try {
699
- createCommit(message);
700
- }
701
- catch (err) {
702
- logger.error(`Failed to commit update (${message}):\n${err.stderr}`);
703
- return false;
704
- }
705
- // Notify user of the commit.
706
- const hash = findCurrentGitSha();
707
- const shortMessage = message.split('\n')[0];
708
- if (hash) {
709
- logger.info(` Committed migration step (${getShortHash(hash)}): ${shortMessage}.`);
710
- }
711
- else {
712
- // Commit was successful, but reading the hash was not. Something weird happened,
713
- // but nothing that would stop the update. Just log the weirdness and continue.
714
- logger.info(` Committed migration step: ${shortMessage}.`);
715
- logger.warn(' Failed to look up hash of most recent commit, continuing anyways.');
716
- }
717
- return true;
718
- }
719
- checkCleanGit() {
720
- try {
721
- const topLevel = (0, node_child_process_1.execSync)('git rev-parse --show-toplevel', {
722
- encoding: 'utf8',
723
- stdio: 'pipe',
724
- });
725
- const result = (0, node_child_process_1.execSync)('git status --porcelain', { encoding: 'utf8', stdio: 'pipe' });
726
- if (result.trim().length === 0) {
727
- return true;
728
- }
729
- // Only files inside the workspace root are relevant
730
- for (const entry of result.split('\n')) {
731
- const relativeEntry = path.relative(path.resolve(this.context.root), path.resolve(topLevel.trim(), entry.slice(3).trim()));
732
- if (!relativeEntry.startsWith('..') && !path.isAbsolute(relativeEntry)) {
733
- return false;
734
- }
735
- }
736
- }
737
- catch { }
738
- return true;
739
- }
740
- /**
741
- * Checks if the current installed CLI version is older or newer than a compatible version.
742
- * @returns the version to install or null when there is no update to install.
743
- */
744
- async checkCLIVersion(packagesToUpdate, verbose = false, next = false) {
745
- const { version } = await (0, package_metadata_1.fetchPackageManifest)(`@angular/cli@${this.getCLIUpdateRunnerVersion(packagesToUpdate, next)}`, this.context.logger, {
746
- verbose,
747
- usingYarn: this.context.packageManager.name === workspace_schema_1.PackageManager.Yarn,
748
- });
749
- return version_1.VERSION.full === version ? null : version;
750
- }
751
- getCLIUpdateRunnerVersion(packagesToUpdate, next) {
752
- if (next) {
753
- return 'next';
754
- }
755
- const updatingAngularPackage = packagesToUpdate?.find((r) => ANGULAR_PACKAGES_REGEXP.test(r));
756
- if (updatingAngularPackage) {
757
- // If we are updating any Angular package we can update the CLI to the target version because
758
- // migrations for @angular/core@13 can be executed using Angular/cli@13.
759
- // This is same behaviour as `npx @angular/cli@13 update @angular/core@13`.
760
- // `@angular/cli@13` -> ['', 'angular/cli', '13']
761
- // `@angular/cli` -> ['', 'angular/cli']
762
- const tempVersion = coerceVersionNumber(updatingAngularPackage.split('@')[2]);
763
- return semver.parse(tempVersion)?.major ?? 'latest';
764
- }
765
- // When not updating an Angular package we cannot determine which schematic runtime the migration should to be executed in.
766
- // Typically, we can assume that the `@angular/cli` was updated previously.
767
- // Example: Angular official packages are typically updated prior to NGRX etc...
768
- // Therefore, we only update to the latest patch version of the installed major version of the Angular CLI.
769
- // This is important because we might end up in a scenario where locally Angular v12 is installed, updating NGRX from 11 to 12.
770
- // We end up using Angular ClI v13 to run the migrations if we run the migrations using the CLI installed major version + 1 logic.
771
- return version_1.VERSION.major;
772
- }
773
- async runTempBinary(packageName, args = []) {
774
- const { success, tempNodeModules } = await this.context.packageManager.installTemp(packageName);
775
- if (!success) {
776
- return 1;
777
- }
778
- // Remove version/tag etc... from package name
779
- // Ex: @angular/cli@latest -> @angular/cli
780
- const packageNameNoVersion = packageName.substring(0, packageName.lastIndexOf('@'));
781
- const pkgLocation = (0, node_path_1.join)(tempNodeModules, packageNameNoVersion);
782
- const packageJsonPath = (0, node_path_1.join)(pkgLocation, 'package.json');
783
- // Get a binary location for this package
784
- let binPath;
785
- if ((0, node_fs_1.existsSync)(packageJsonPath)) {
786
- const content = await node_fs_1.promises.readFile(packageJsonPath, 'utf-8');
787
- if (content) {
788
- const { bin = {} } = JSON.parse(content);
789
- const binKeys = Object.keys(bin);
790
- if (binKeys.length) {
791
- binPath = (0, node_path_1.resolve)(pkgLocation, bin[binKeys[0]]);
792
- }
793
- }
794
- }
795
- if (!binPath) {
796
- throw new Error(`Cannot locate bin for temporary package: ${packageNameNoVersion}.`);
797
- }
798
- const { status, error } = (0, node_child_process_1.spawnSync)(process.execPath, [binPath, ...args], {
799
- stdio: 'inherit',
800
- env: {
801
- ...process.env,
802
- NG_DISABLE_VERSION_CHECK: 'true',
803
- NG_CLI_ANALYTICS: 'false',
804
- },
805
- });
806
- if (status === null && error) {
807
- throw error;
808
- }
809
- return status ?? 0;
810
- }
811
- packageManagerForce(verbose) {
812
- // npm 7+ can fail due to it incorrectly resolving peer dependencies that have valid SemVer
813
- // ranges during an update. Update will set correct versions of dependencies within the
814
- // package.json file. The force option is set to workaround these errors.
815
- // Example error:
816
- // npm ERR! Conflicting peer dependency: @angular/compiler-cli@14.0.0-rc.0
817
- // npm ERR! node_modules/@angular/compiler-cli
818
- // npm ERR! peer @angular/compiler-cli@"^14.0.0 || ^14.0.0-rc" from @angular-devkit/build-angular@14.0.0-rc.0
819
- // npm ERR! node_modules/@angular-devkit/build-angular
820
- // npm ERR! dev @angular-devkit/build-angular@"~14.0.0-rc.0" from the root project
821
- if (this.context.packageManager.name === workspace_schema_1.PackageManager.Npm &&
822
- this.context.packageManager.version &&
823
- semver.gte(this.context.packageManager.version, '7.0.0')) {
824
- if (verbose) {
825
- this.context.logger.info('NPM 7+ detected -- enabling force option for package installation');
826
- }
827
- return true;
828
- }
829
- return false;
830
- }
831
- async getOptionalMigrationsToRun(optionalMigrations, packageName) {
832
- const { logger } = this.context;
833
- const numberOfMigrations = optionalMigrations.length;
834
- logger.info(`This package has ${numberOfMigrations} optional migration${numberOfMigrations > 1 ? 's' : ''} that can be executed.`);
835
- if (!(0, tty_1.isTTY)()) {
836
- for (const migration of optionalMigrations) {
837
- const { title } = getMigrationTitleAndDescription(migration);
838
- logger.info(color_1.colors.cyan(color_1.figures.pointer) + ' ' + color_1.colors.bold(title));
839
- logger.info(color_1.colors.gray(` ng update ${packageName} --name ${migration.name}`));
840
- logger.info(''); // Extra trailing newline.
841
- }
842
- return undefined;
843
- }
844
- logger.info('Optional migrations may be skipped and executed after the update process, if preferred.');
845
- logger.info(''); // Extra trailing newline.
846
- const answer = await (0, prompt_1.askChoices)(`Select the migrations that you'd like to run`, optionalMigrations.map((migration) => {
847
- const { title, documentation } = getMigrationTitleAndDescription(migration);
848
- return {
849
- name: `[${color_1.colors.white(migration.name)}] ${title}${documentation ? ` (${documentation})` : ''}`,
850
- value: migration.name,
851
- checked: migration.recommended,
852
- };
853
- }), null);
854
- logger.info(''); // Extra trailing newline.
855
- return optionalMigrations.filter(({ name }) => answer?.includes(name));
856
- }
857
513
  }
858
514
  exports.default = UpdateCommandModule;
859
- /**
860
- * @return Whether or not the working directory has Git changes to commit.
861
- */
862
- function hasChangesToCommit() {
863
- // List all modified files not covered by .gitignore.
864
- // If any files are returned, then there must be something to commit.
865
- return (0, node_child_process_1.execSync)('git ls-files -m -d -o --exclude-standard').toString() !== '';
866
- }
867
- /**
868
- * Precondition: Must have pending changes to commit, they do not need to be staged.
869
- * Postcondition: The Git working tree is committed and the repo is clean.
870
- * @param message The commit message to use.
871
- */
872
- function createCommit(message) {
873
- // Stage entire working tree for commit.
874
- (0, node_child_process_1.execSync)('git add -A', { encoding: 'utf8', stdio: 'pipe' });
875
- // Commit with the message passed via stdin to avoid bash escaping issues.
876
- (0, node_child_process_1.execSync)('git commit --no-verify -F -', { encoding: 'utf8', stdio: 'pipe', input: message });
877
- }
878
- /**
879
- * @return The Git SHA hash of the HEAD commit. Returns null if unable to retrieve the hash.
880
- */
881
- function findCurrentGitSha() {
882
- try {
883
- return (0, node_child_process_1.execSync)('git rev-parse HEAD', { encoding: 'utf8', stdio: 'pipe' }).trim();
884
- }
885
- catch {
886
- return null;
887
- }
888
- }
889
- function getShortHash(commitHash) {
890
- return commitHash.slice(0, 9);
891
- }
892
- function coerceVersionNumber(version) {
893
- if (!version) {
894
- return undefined;
895
- }
896
- if (!/^\d{1,30}\.\d{1,30}\.\d{1,30}/.test(version)) {
897
- const match = version.match(/^\d{1,30}(\.\d{1,30})*/);
898
- if (!match) {
899
- return undefined;
900
- }
901
- if (!match[1]) {
902
- version = version.substring(0, match[0].length) + '.0.0' + version.substring(match[0].length);
903
- }
904
- else if (!match[2]) {
905
- version = version.substring(0, match[0].length) + '.0' + version.substring(match[0].length);
906
- }
907
- else {
908
- return undefined;
909
- }
910
- }
911
- return semver.valid(version) ?? undefined;
912
- }
913
- function getMigrationTitleAndDescription(migration) {
914
- const [title, ...description] = migration.description.split('. ');
915
- return {
916
- title: title.endsWith('.') ? title : title + '.',
917
- description: description.join('.\n '),
918
- documentation: migration.documentation
919
- ? new URL(migration.documentation, 'https://angular.dev').href
920
- : undefined,
921
- };
922
- }
923
515
  //# sourceMappingURL=cli.js.map