Skip to content

Commit

Permalink
fix(@schematics/angular): Allow skipping existing dependencies in E2E…
Browse files Browse the repository at this point in the history
… schematic

The E2E schematic will now (as it did previously) skip adding dependencies
if they already exist within the `package.json` regardless of the specifier.
This is accomplished with the `existing` option for the `addDependency` rule
which allows defining the behavior for when a dependency already exists.
Currently the two option behaviors are skip and replace with replace being
the default to retain behavior for existing rule usages.

(cherry picked from commit c9b2aa4)
  • Loading branch information
clydin committed Jul 19, 2022
1 parent cf83bfd commit a8fe4fc
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 5 deletions.
6 changes: 5 additions & 1 deletion packages/schematics/angular/e2e/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import {
AngularBuilder,
DependencyType,
ExistingBehavior,
addDependency,
updateWorkspace,
} from '@schematics/angular/utility';
Expand Down Expand Up @@ -92,7 +93,10 @@ export default function (options: E2eOptions): Rule {
]),
),
...E2E_DEV_DEPENDENCIES.map((name) =>
addDependency(name, latestVersions[name], { type: DependencyType.Dev }),
addDependency(name, latestVersions[name], {
type: DependencyType.Dev,
existing: ExistingBehavior.Skip,
}),
),
addScriptsToPackageJson(),
]);
Expand Down
31 changes: 30 additions & 1 deletion packages/schematics/angular/utility/dependency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@ export enum InstallBehavior {
Always,
}

/**
* An enum used to specify the existing dependency behavior for the {@link addDependency}
* schematics rule. The existing behavior affects whether the named dependency will be added
* to the `package.json` when the dependency is already present with a differing specifier.
*/
export enum ExistingBehavior {
/**
* The dependency will not be added or otherwise changed if it already exists.
*/
Skip,
/**
* The dependency's existing specifier will be replaced with the specifier provided in the
* {@link addDependency} call. A warning will also be shown during schematic execution to
* notify the user of the replacement.
*/
Replace,
}

/**
* Adds a package as a dependency to a `package.json`. By default the `package.json` located
* at the schematic's root will be used. The `manifestPath` option can be used to explicitly specify
Expand Down Expand Up @@ -88,12 +106,18 @@ export function addDependency(
* Defaults to {@link InstallBehavior.Auto}.
*/
install?: InstallBehavior;
/**
* The behavior to use when the dependency already exists within the `package.json`.
* Defaults to {@link ExistingBehavior.Replace}.
*/
existing?: ExistingBehavior;
} = {},
): Rule {
const {
type = DependencyType.Default,
packageJsonPath = '/package.json',
install = InstallBehavior.Auto,
existing = ExistingBehavior.Replace,
} = options;

return (tree, context) => {
Expand All @@ -113,7 +137,12 @@ export function addDependency(

if (existingSpecifier) {
// Already present but different specifier
// This warning may become an error in the future

if (existing === ExistingBehavior.Skip) {
return;
}

// ExistingBehavior.Replace is the only other behavior currently
context.logger.warn(
`Package dependency "${name}" already exists with a different specifier. ` +
`"${existingSpecifier}" will be replaced with "${specifier}".`,
Expand Down
62 changes: 60 additions & 2 deletions packages/schematics/angular/utility/dependency_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
callRule,
chain,
} from '@angular-devkit/schematics';
import { DependencyType, InstallBehavior, addDependency } from './dependency';
import { DependencyType, ExistingBehavior, InstallBehavior, addDependency } from './dependency';

interface LogEntry {
type: 'warn';
Expand Down Expand Up @@ -63,7 +63,7 @@ describe('addDependency', () => {
});
});

it('warns if a package is already present with a different specifier', async () => {
it('warns if a package is already present with a different specifier by default', async () => {
const tree = new EmptyTree();
tree.create(
'/package.json',
Expand All @@ -85,6 +85,64 @@ describe('addDependency', () => {
);
});

it('warns if a package is already present with a different specifier with replace behavior', async () => {
const tree = new EmptyTree();
tree.create(
'/package.json',
JSON.stringify({
dependencies: { '@angular/core': '^13.0.0' },
}),
);

const rule = addDependency('@angular/core', '^14.0.0', { existing: ExistingBehavior.Replace });

const { logs } = await testRule(rule, tree);
expect(logs).toContain(
jasmine.objectContaining({
type: 'warn',
message:
'Package dependency "@angular/core" already exists with a different specifier. ' +
'"^13.0.0" will be replaced with "^14.0.0".',
}),
);
});

it('replaces the specifier if a package is already present with a different specifier with replace behavior', async () => {
const tree = new EmptyTree();
tree.create(
'/package.json',
JSON.stringify({
dependencies: { '@angular/core': '^13.0.0' },
}),
);

const rule = addDependency('@angular/core', '^14.0.0', { existing: ExistingBehavior.Replace });

await testRule(rule, tree);

expect(tree.readJson('/package.json')).toEqual({
dependencies: { '@angular/core': '^14.0.0' },
});
});

it('does not replace the specifier if a package is already present with a different specifier with skip behavior', async () => {
const tree = new EmptyTree();
tree.create(
'/package.json',
JSON.stringify({
dependencies: { '@angular/core': '^13.0.0' },
}),
);

const rule = addDependency('@angular/core', '^14.0.0', { existing: ExistingBehavior.Skip });

await testRule(rule, tree);

expect(tree.readJson('/package.json')).toEqual({
dependencies: { '@angular/core': '^13.0.0' },
});
});

it('adds a package version with other packages in alphabetical order', async () => {
const tree = new EmptyTree();
tree.create(
Expand Down
2 changes: 1 addition & 1 deletion packages/schematics/angular/utility/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ export {
export { Builders as AngularBuilder } from './workspace-models';

// Package dependency related rules and types
export { DependencyType, InstallBehavior, addDependency } from './dependency';
export { DependencyType, ExistingBehavior, InstallBehavior, addDependency } from './dependency';

0 comments on commit a8fe4fc

Please sign in to comment.