From 9d258fc3f46989de2a89d429ca4994d5ed756eab Mon Sep 17 00:00:00 2001 From: Shane McLaughlin Date: Tue, 2 Nov 2021 15:05:30 -0500 Subject: [PATCH] feat: modify fileResponse for not found in org on Deletes (#472) * feat: modify fileResponse for not found in org on Deletes * test: verify for matchingContentType * refactor: pr feedback (jsdoc, named type for object) * refactor: handle various destructive filenames Co-authored-by: Steve Hetzel --- CHANGELOG.md | 6 ++--- src/client/metadataApiDeploy.ts | 37 +++++++++++++++++++++++++- src/collections/componentSet.ts | 22 ++++++++++++++++ test/client/metadataApiDeploy.test.ts | 38 +++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 480e07275c..03463aa1ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,17 +8,15 @@ All notable changes to this project will be documented in this file. See [standa ### [5.1.1](https://github.com/forcedotcom/source-deploy-retrieve/compare/v5.1.0...v5.1.1) (2021-10-28) - ### Bug Fixes -* ensure component.content is always assigned ([#485](https://github.com/forcedotcom/source-deploy-retrieve/issues/485)) ([d77f475](https://github.com/forcedotcom/source-deploy-retrieve/commit/d77f47502634206ac59181362b7f17da82ed01e7)) +- ensure component.content is always assigned ([#485](https://github.com/forcedotcom/source-deploy-retrieve/issues/485)) ([d77f475](https://github.com/forcedotcom/source-deploy-retrieve/commit/d77f47502634206ac59181362b7f17da82ed01e7)) ## [5.1.0](https://github.com/forcedotcom/source-deploy-retrieve/compare/v5.0.3...v5.1.0) (2021-10-28) - ### Features -* construct virtual tree from array of paths ([#480](https://github.com/forcedotcom/source-deploy-retrieve/issues/480)) ([99954dc](https://github.com/forcedotcom/source-deploy-retrieve/commit/99954dc731d078e99283eed940b98ee63688a024)) +- construct virtual tree from array of paths ([#480](https://github.com/forcedotcom/source-deploy-retrieve/issues/480)) ([99954dc](https://github.com/forcedotcom/source-deploy-retrieve/commit/99954dc731d078e99283eed940b98ee63688a024)) ### [5.0.3](https://github.com/forcedotcom/source-deploy-retrieve/compare/v5.0.2...v5.0.3) (2021-10-28) diff --git a/src/client/metadataApiDeploy.ts b/src/client/metadataApiDeploy.ts index 20c6b81fe1..aa6c660493 100644 --- a/src/client/metadataApiDeploy.ts +++ b/src/client/metadataApiDeploy.ts @@ -54,7 +54,7 @@ export class DeployResult implements MetadataTransferResult { } } - return fileResponses; + return fileResponses.concat(this.deleteNotFoundToFileResponses(messages)); } private createResponses(component: SourceComponent, messages: DeployMessage[]): FileResponse[] { @@ -146,6 +146,41 @@ export class DeployResult implements MetadataTransferResult { return messageMap; } + /** + * If a components fails to delete because it doesn't exist in the org, you get a message like + * key: 'ApexClass#destructiveChanges.xml' + * value:[{ + * fullName: 'destructiveChanges.xml', + * fileName: 'destructiveChanges.xml', + * componentType: 'ApexClass', + * problem: 'No ApexClass named: test1 found', + * problemType: 'Warning' + * }] + */ + private deleteNotFoundToFileResponses(messageMap: Map): FileResponse[] { + const fileResponses: FileResponse[] = []; + messageMap.forEach((messages, key) => { + if (key.includes('destructiveChanges') && key.endsWith('.xml')) { + messages.forEach((message) => { + if (message.problemType === 'Warning' && message.problem.startsWith(`No ${message.componentType} named: `)) { + const fullName = message.problem.replace(`No ${message.componentType} named: `, '').replace(' found', ''); + this.components + .getComponentFilenamesByNameAndType({ fullName, type: message.componentType }) + .forEach((fileName) => { + fileResponses.push({ + fullName, + type: message.componentType, + filePath: fileName, + state: ComponentStatus.Deleted, + }); + }); + } + }); + } + }); + return fileResponses; + } + /** * Fix any issues with the deploy message returned by the api. * TODO: remove cases if fixes are made in the api. diff --git a/src/collections/componentSet.ts b/src/collections/componentSet.ts index 6f9ee57daa..e9db2ed5f3 100644 --- a/src/collections/componentSet.ts +++ b/src/collections/componentSet.ts @@ -24,6 +24,7 @@ import { TreeContainer, } from '../resolve'; import { MetadataType, RegistryAccess } from '../registry'; +import { MetadataMember } from '../resolve/types'; import { DestructiveChangesType, FromManifestOptions, @@ -477,6 +478,27 @@ export class ComponentSet extends LazyCollection { return false; } + /** + * For a fullName and type, this returns the filenames the matching component, or an empty array if the component is not present + * + * @param param Object with fullName and type properties + * @returns string[] + */ + public getComponentFilenamesByNameAndType({ fullName, type }: MetadataMember): string[] { + const key = this.simpleKey({ fullName, type }); + const componentMap = this.components.get(key); + if (!componentMap) { + return []; + } + const output = new Set(); + componentMap.forEach((component) => { + [...component.walkContent(), component.content, component.xml] + .filter(Boolean) + .map((filename) => output.add(filename)); + }); + return Array.from(output); + } + public *[Symbol.iterator](): Iterator { for (const [key, sourceComponents] of this.components.entries()) { if (sourceComponents.size === 0) { diff --git a/test/client/metadataApiDeploy.test.ts b/test/client/metadataApiDeploy.test.ts index d872abe060..7e4c041400 100644 --- a/test/client/metadataApiDeploy.test.ts +++ b/test/client/metadataApiDeploy.test.ts @@ -25,6 +25,7 @@ import { DECOMPOSED_CHILD_COMPONENT_2, DECOMPOSED_COMPONENT, } from '../mock/registry/type-constants/decomposedConstants'; +import { COMPONENT } from '../mock/registry/type-constants/matchingContentFileConstants'; import { MissingJobIdError } from '../../src/errors'; const env = createSandbox(); @@ -714,6 +715,43 @@ describe('MetadataApiDeploy', () => { expect(responses).to.deep.equal(expected); }); + + it('should report "Deleted" when no component in org', () => { + const component = COMPONENT; + const deployedSet = new ComponentSet([component]); + const apiStatus: Partial = { + details: { + componentFailures: { + changed: 'false', + created: 'false', + deleted: 'false', + fullName: 'destructiveChanges.xml', + componentType: component.type.name, + problem: `No ${component.type.name} named: ${component.fullName} found`, + problemType: 'Warning', + } as DeployMessage, + }, + }; + const result = new DeployResult(apiStatus as MetadataApiDeployStatus, deployedSet); + + const responses = result.getFileResponses(); + const expected: FileResponse[] = [ + { + fullName: component.fullName, + type: component.type.name, + state: ComponentStatus.Deleted, + filePath: component.content, + }, + { + fullName: component.fullName, + type: component.type.name, + state: ComponentStatus.Deleted, + filePath: component.xml, + }, + ]; + + expect(responses).to.deep.equal(expected); + }); }); });