From 39e584f9cba6b9a829b067e4b074f14d2b69595c Mon Sep 17 00:00:00 2001 From: Mike Brocchi Date: Tue, 26 Jan 2021 15:24:07 -0500 Subject: [PATCH] fix(@angular-devkit/schematics): Fix merge that causes an overwrite This fixes #11337 to allow for merging of a tree with another when the the file already exists in the tree being merged into. --- .../schematics/src/tree/host-tree.ts | 4 +- .../schematics/src/tree/host-tree_spec.ts | 38 +++++++++++++++++++ .../generate/component/component-duplicate.ts | 4 +- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/angular_devkit/schematics/src/tree/host-tree.ts b/packages/angular_devkit/schematics/src/tree/host-tree.ts index fa0579cfc449..e3b7f19aa2c0 100644 --- a/packages/angular_devkit/schematics/src/tree/host-tree.ts +++ b/packages/angular_devkit/schematics/src/tree/host-tree.ts @@ -56,7 +56,7 @@ export class HostDirEntry implements DirEntry { readonly path: Path, protected _host: virtualFs.SyncDelegateHost, protected _tree: Tree, - ) {} + ) { } get subdirs(): PathFragment[] { return this._host.list(this.path) @@ -180,7 +180,7 @@ export class HostTree implements Tree { case 'c': { const { path, content } = action; - if ((this._willCreate(path) || this._willOverwrite(path))) { + if (this._willCreate(path) || this._willOverwrite(path) || this.exists(path)) { const existingContent = this.read(path); if (existingContent && content.equals(existingContent)) { // Identical outcome; no action required diff --git a/packages/angular_devkit/schematics/src/tree/host-tree_spec.ts b/packages/angular_devkit/schematics/src/tree/host-tree_spec.ts index 476046d6c88b..a6d0c6c231cf 100644 --- a/packages/angular_devkit/schematics/src/tree/host-tree_spec.ts +++ b/packages/angular_devkit/schematics/src/tree/host-tree_spec.ts @@ -7,9 +7,47 @@ */ import { normalize, virtualFs } from '@angular-devkit/core'; import { FilterHostTree, HostTree } from './host-tree'; +import { MergeStrategy } from './interface'; describe('HostTree', () => { + describe('merge', () => { + it('should create files from each tree', () => { + const tree = new HostTree(); + tree.create('/file1', 'a'); + const tree2 = new HostTree(); + tree2.create('/file2', 'a'); + tree.merge(tree2); + expect(tree.actions[0].kind).toEqual('c'); + expect(tree.actions[1].kind).toEqual('c'); + }); + + it('should overwrite if the file exists in one tree', () => { + const tree = new HostTree(); + tree.create('/file1', 'a'); + const tree2 = new HostTree(); + tree2.create('/file1', 'b'); + tree.merge(tree2, MergeStrategy.Overwrite); + expect(tree.actions[0].kind).toEqual('c'); + }); + it('should throw if the file exists in one tree with the correct MergeStrategy', () => { + const tree = new HostTree(); + tree.create('/file1', 'a'); + const tree2 = new HostTree(); + tree2.create('/file1', 'b'); + expect(() => tree.merge(tree2)).toThrow(); + }); + + it('should not have a second action if the file content is the same', () => { + const tree = new HostTree(); + tree.create('/file1', 'a'); + const tree2 = new HostTree(); + tree2.create('/file1', 'a'); + tree.merge(tree2, MergeStrategy.Overwrite); + expect(tree.actions[0].kind).toEqual('c'); + expect(tree.actions.length).toEqual(1); + }); + }); }); describe('FilterHostTree', () => { diff --git a/tests/legacy-cli/e2e/tests/generate/component/component-duplicate.ts b/tests/legacy-cli/e2e/tests/generate/component/component-duplicate.ts index 94d73a23fcb3..7c8e4074bb07 100644 --- a/tests/legacy-cli/e2e/tests/generate/component/component-duplicate.ts +++ b/tests/legacy-cli/e2e/tests/generate/component/component-duplicate.ts @@ -1,6 +1,7 @@ +import { oneLine } from 'common-tags'; +import { appendToFile } from '../../../utils/fs'; import { ng } from '../../../utils/process'; import { expectToFail } from '../../../utils/utils'; -import { oneLine } from 'common-tags'; export default function () { return ng('generate', 'component', 'test-component') @@ -12,5 +13,6 @@ export default function () { in ${output.stdout}.`); } }) + .then(() => appendToFile('src/app/test-component/test-component.component.ts', '\n// new content')) .then(() => expectToFail(() => ng('generate', 'component', 'test-component'))); }