Skip to content

Commit

Permalink
fix(@angular/cli): correctly account for linked packages in update
Browse files Browse the repository at this point in the history
Fixes #15511
Fixes #15294
  • Loading branch information
clydin authored and Keen Yee Liau committed Sep 11, 2019
1 parent 7a75c4c commit 8cc0a11
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 56 deletions.
29 changes: 13 additions & 16 deletions packages/angular/cli/commands/update-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,10 @@ import { getPackageManager } from '../utilities/package-manager';
import {
PackageIdentifier,
PackageManifest,
PackageMetadata,
fetchPackageMetadata,
} from '../utilities/package-metadata';
import {
PackageTreeActual,
findNodeDependencies,
readPackageTree,
} from '../utilities/package-tree';
import { PackageTreeNode, findNodeDependencies, readPackageTree } from '../utilities/package-tree';
import { Schema as UpdateCommandSchema } from './update';

const npa = require('npm-package-arg');
Expand Down Expand Up @@ -158,26 +155,26 @@ export class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {
}

const packageName = packages[0].name;
let packageNode = rootDependencies[packageName];
if (typeof packageNode === 'string') {
const packageDependency = rootDependencies[packageName];
let packageNode = packageDependency && packageDependency.node;
if (packageDependency && !packageNode) {
this.logger.error('Package found in package.json but is not installed.');

return 1;
} else if (!packageNode) {
} else if (!packageDependency) {
// Allow running migrations on transitively installed dependencies
// There can technically be nested multiple versions
// TODO: If multiple, this should find all versions and ask which one to use
const child = packageTree.children.find(c => c.name === packageName);
if (child) {
// A link represents a symlinked package so use the actual in this case
packageNode = child.isLink ? child.target : child;
packageNode = child;
}
}

if (!packageNode) {
this.logger.error('Package is not installed.');
if (!packageNode) {
this.logger.error('Package is not installed.');

return 1;
}
return 1;
}

const updateMetadata = packageNode.package['ng-update'];
Expand Down Expand Up @@ -248,12 +245,12 @@ export class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {

const requests: {
identifier: PackageIdentifier;
node: PackageTreeActual | string;
node: PackageTreeNode | string;
}[] = [];

// Validate packages actually are part of the workspace
for (const pkg of packages) {
const node = rootDependencies[pkg.name];
const node = rootDependencies[pkg.name] && rootDependencies[pkg.name].node;
if (!node) {
this.logger.error(`Package '${pkg.name}' is not a dependency.`);

Expand Down
46 changes: 18 additions & 28 deletions packages/angular/cli/utilities/package-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,10 @@ export interface PackageManifest {
peerDependencies: PackageDependencies;
optionalDependencies: PackageDependencies;

'ng-add'?: {

};
'ng-add'?: {};
'ng-update'?: {
migrations: string,
packageGroup: { [name: string]: string },
migrations: string;
packageGroup: { [name: string]: string };
};
}

Expand All @@ -61,12 +59,12 @@ function ensureNpmrc(logger: logging.LoggerApi, usingYarn: boolean, verbose: boo
if (!npmrc) {
try {
npmrc = readOptions(logger, false, verbose);
} catch { }
} catch {}

if (usingYarn) {
try {
npmrc = { ...npmrc, ...readOptions(logger, true, verbose) };
} catch { }
} catch {}
}
}
}
Expand Down Expand Up @@ -95,9 +93,7 @@ function readOptions(
path.join(homedir(), dotFilename),
];

const projectConfigLocations: string[] = [
path.join(cwd, dotFilename),
];
const projectConfigLocations: string[] = [path.join(cwd, dotFilename)];
const root = path.parse(cwd).root;
for (let curDir = path.dirname(cwd); curDir && curDir !== root; curDir = path.dirname(curDir)) {
projectConfigLocations.unshift(path.join(curDir, dotFilename));
Expand Down Expand Up @@ -125,7 +121,7 @@ function readOptions(
delete options.cafile;
try {
options.ca = readFileSync(cafile, 'utf8').replace(/\r?\n/, '\\n');
} catch { }
} catch {}
}
} else if (showPotentials) {
logger.info(`Trying '${location}'...not found.`);
Expand All @@ -151,7 +147,7 @@ function normalizeManifest(rawManifest: {}): PackageManifest {
peerDependencies: {},
optionalDependencies: {},
// tslint:disable-next-line:no-any
...rawManifest as any,
...(rawManifest as any),
};
}

Expand All @@ -173,14 +169,11 @@ export async function fetchPackageMetadata(

ensureNpmrc(logger, usingYarn, verbose);

const response = await pacote.packument(
name,
{
'full-metadata': true,
...npmrc,
...(registry ? { registry } : {}),
},
);
const response = await pacote.packument(name, {
'full-metadata': true,
...npmrc,
...(registry ? { registry } : {}),
});

// Normalize the response
const metadata: PackageMetadata = {
Expand Down Expand Up @@ -227,14 +220,11 @@ export async function fetchPackageManifest(

ensureNpmrc(logger, usingYarn, verbose);

const response = await pacote.manifest(
name,
{
'full-metadata': true,
...npmrc,
...(registry ? { registry } : {}),
},
);
const response = await pacote.manifest(name, {
'full-metadata': true,
...npmrc,
...(registry ? { registry } : {}),
});

return normalizeManifest(response);
}
34 changes: 22 additions & 12 deletions packages/angular/cli/utilities/package-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ export interface PackageTreeNodeBase {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
peerDependencies?: Record<string, string>;
optionalDependencies?: Record<string, string>;
'ng-update'?: {
migrations?: string;
};
};
parent?: PackageTreeNode;
children: PackageTreeNode[];
}

export interface PackageTreeActual extends PackageTreeNodeBase {
isLink: false;
parent?: PackageTreeActual;
}

export interface PackageTreeLink extends PackageTreeNodeBase {
isLink: true;
parent: null;
target: PackageTreeActual;
}

Expand All @@ -52,25 +52,35 @@ export function readPackageTree(path: string): Promise<PackageTreeNode> {
});
}

export function findNodeDependencies(root: PackageTreeNode, node = root) {
const actual = node.isLink ? node.target : node;
export interface NodeDependency {
version: string;
node?: PackageTreeNode;
}

export function findNodeDependencies(node: PackageTreeNode) {
const rawDeps: Record<string, string> = {
...actual.package.dependencies,
...actual.package.devDependencies,
...actual.package.peerDependencies,
...node.package.dependencies,
...node.package.devDependencies,
...node.package.peerDependencies,
...node.package.optionalDependencies,
};

return Object.entries(rawDeps).reduce(
(deps, [name, version]) => {
const depNode = root.children.find(child => {
return child.name === name && !child.isLink && child.parent === node;
}) as PackageTreeActual | undefined;
let dependencyNode;
let parent: PackageTreeNode | undefined | null = node;
while (!dependencyNode && parent) {
dependencyNode = parent.children.find(child => child.name === name);
parent = parent.parent;
}

deps[name] = depNode || version;
deps[name] = {
node: dependencyNode,
version,
};

return deps;
},
{} as Record<string, string | PackageTreeActual | undefined>,
Object.create(null) as Record<string, NodeDependency>,
);
}

0 comments on commit 8cc0a11

Please sign in to comment.