Skip to content

Commit aaec6f9

Browse files
clydinalexeagle
authored andcommitted
fix(@angular/cli): resolve update migrations from referenced package root
This ensures that migration fields that reference other packages use the package version specified in the migrating package's dependencies and not the version that a package manager happens to hoist to the root of the workspace.
1 parent aaa240e commit aaec6f9

File tree

1 file changed

+43
-10
lines changed

1 file changed

+43
-10
lines changed

packages/angular/cli/commands/update-impl.ts

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import { execSync } from 'child_process';
9+
import * as fs from 'fs';
910
import * as path from 'path';
1011
import * as semver from 'semver';
1112
import { Arguments, Option } from '../models/interface';
@@ -22,10 +23,7 @@ import { Schema as UpdateCommandSchema } from './update';
2223

2324
const npa = require('npm-package-arg');
2425

25-
const oldConfigFileNames = [
26-
'.angular-cli.json',
27-
'angular-cli.json',
28-
];
26+
const oldConfigFileNames = ['.angular-cli.json', 'angular-cli.json'];
2927

3028
export class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {
3129
public readonly allowMissingWorkspace = true;
@@ -184,12 +182,45 @@ export class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {
184182
} else if (typeof migrations !== 'string') {
185183
this.logger.error('Package contains a malformed migrations field.');
186184

185+
return 1;
186+
} else if (path.posix.isAbsolute(migrations) || path.win32.isAbsolute(migrations)) {
187+
this.logger.error(
188+
'Package contains an invalid migrations field. Absolute paths are not permitted.',
189+
);
190+
187191
return 1;
188192
}
189193

190-
// if not non-relative, add package name
191-
if (migrations.startsWith('.') || migrations.startsWith('/')) {
192-
migrations = path.join(packageName, migrations);
194+
// Normalize slashes
195+
migrations = migrations.replace(/\\/g, '/');
196+
197+
if (migrations.startsWith('../')) {
198+
this.logger.error(
199+
'Package contains an invalid migrations field. ' +
200+
'Paths outside the package root are not permitted.',
201+
);
202+
203+
return 1;
204+
}
205+
206+
// Check if it is a package-local location
207+
const localMigrations = path.join(packageNode.path, migrations);
208+
if (fs.existsSync(localMigrations)) {
209+
migrations = localMigrations;
210+
} else {
211+
// Try to resolve from package location.
212+
// This avoids issues with package hoisting.
213+
try {
214+
migrations = require.resolve(migrations, { paths: [packageNode.path] });
215+
} catch (e) {
216+
if (e.code === 'MODULE_NOT_FOUND') {
217+
this.logger.error('Migrations for package were not found.');
218+
} else {
219+
this.logger.error(`Unable to resolve migrations for package. [${e.message}]`);
220+
}
221+
222+
return 1;
223+
}
193224
}
194225

195226
return this.runSchematic({
@@ -219,9 +250,11 @@ export class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {
219250
}
220251

221252
// If a specific version is requested and matches the installed version, skip.
222-
if (pkg.type === 'version' &&
223-
typeof node === 'object' &&
224-
node.package.version === pkg.fetchSpec) {
253+
if (
254+
pkg.type === 'version' &&
255+
typeof node === 'object' &&
256+
node.package.version === pkg.fetchSpec
257+
) {
225258
this.logger.info(`Package '${pkg.name}' is already at '${pkg.fetchSpec}'.`);
226259
continue;
227260
}

0 commit comments

Comments
 (0)