From 6ee0028209551ca4e94cc9b41eecc9c8b5b3dd95 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Wed, 29 May 2019 20:51:14 +0200 Subject: [PATCH] fix(@angular/cli): ng-update migrations not running with --migrate-only With Angular CLI version 8, migrations cannot be re-run with the `--migrate-only` flag as there was a recent regression introduced in https://github.com/angular/angular-cli/commit/e406f00909a72dff70cbaaff52a5495258ee77c3#diff-0d0a748fb9a38a7ccde08d9b42e70bce as it now passes a normalized platform path to the `engine.createCollection` call. This breaks as there is incorrect logic within `node-modules-engine-host` that causes the schematic collection to be searched within the `package.json#schematics` entry. This is incorrect as migration schematics specify their migration schematics in a separate schematic collection file which is part of `package.json#ng-update`. Fixes #14565 --- .../tools/node-module-engine-host.ts | 2 +- .../tools/node-module-engine-host_spec.ts | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 packages/angular_devkit/schematics/tools/node-module-engine-host_spec.ts diff --git a/packages/angular_devkit/schematics/tools/node-module-engine-host.ts b/packages/angular_devkit/schematics/tools/node-module-engine-host.ts index 2c0e681626bc..9475a87d3440 100644 --- a/packages/angular_devkit/schematics/tools/node-module-engine-host.ts +++ b/packages/angular_devkit/schematics/tools/node-module-engine-host.ts @@ -79,7 +79,7 @@ export class NodeModulesEngineHost extends FileSystemEngineHostBase { protected _resolveCollectionPath(name: string): string { let collectionPath: string | undefined = undefined; - if (name.replace(/\\/, '/').split('/').length > (name[0] == '@' ? 2 : 1)) { + if (name.replace(/\\/g, '/').split('/').length > (name[0] == '@' ? 2 : 1)) { try { collectionPath = this._resolvePath(name, process.cwd()); } catch { diff --git a/packages/angular_devkit/schematics/tools/node-module-engine-host_spec.ts b/packages/angular_devkit/schematics/tools/node-module-engine-host_spec.ts new file mode 100644 index 000000000000..4d33a745a2b6 --- /dev/null +++ b/packages/angular_devkit/schematics/tools/node-module-engine-host_spec.ts @@ -0,0 +1,54 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// tslint:disable:no-implicit-dependencies + +import { SchematicEngine } from '@angular-devkit/schematics'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { NodeModulesEngineHost } from './node-module-engine-host'; + +const TMP_DIR = process.env['$TEST_TMPDIR'] || os.tmpdir(); + +describe('NodeModulesEngineHost', () => { + let tmpDir!: string; + let previousDir!: string; + + beforeEach(() => { + tmpDir = fs.mkdtempSync(path.join(TMP_DIR, + 'angular-devkit-schematics-tools-node-module-engine-host')); + previousDir = process.cwd(); + process.chdir(tmpDir); + }); + + afterEach(() => process.chdir(previousDir)); + + /** Creates a fake NPM module that can be used to test the node module engine host. */ + function createFakeNpmModule() { + fs.mkdirSync(path.join(tmpDir, 'node_modules')); + fs.mkdirSync(path.join(tmpDir, 'node_modules/@angular/')); + fs.mkdirSync(path.join(tmpDir, 'node_modules/@angular/core')); + fs.mkdirSync(path.join(tmpDir, 'node_modules/@angular/core/schematics')); + fs.writeFileSync(path.join(tmpDir, 'node_modules/@angular/core/package.json'), + JSON.stringify({name: '@angular/core'})); + fs.writeFileSync(path.join(tmpDir, 'node_modules/@angular/core/schematics/migrations.json'), + JSON.stringify({schematics: {}})); + } + + it('should properly create collections with explicit collection path', () => { + createFakeNpmModule(); + + const engineHost = new NodeModulesEngineHost(); + const engine = new SchematicEngine(engineHost); + + expect(() => { + engine.createCollection(path.join('@angular/core', './schematics/migrations.json')); + }).not.toThrow(); + }); +});