From f878d65977cbed6d8a4d3dc1924f14084efcf141 Mon Sep 17 00:00:00 2001 From: Shane McLaughlin Date: Mon, 24 Jul 2023 15:10:13 -0500 Subject: [PATCH] fix: spread/push argument limits (#1046) --- src/client/metadataApiDeploy.ts | 72 ++++++++++++--------------- src/client/metadataApiRetrieve.ts | 15 ++---- src/resolve/metadataResolver.ts | 12 ++--- src/resolve/sourceComponent.ts | 49 +++++++++--------- test/client/metadataApiDeploy.test.ts | 7 ++- 5 files changed, 72 insertions(+), 83 deletions(-) diff --git a/src/client/metadataApiDeploy.ts b/src/client/metadataApiDeploy.ts index 2a66ffb7b8..8af572118f 100644 --- a/src/client/metadataApiDeploy.ts +++ b/src/client/metadataApiDeploy.ts @@ -45,49 +45,43 @@ export class DeployResult implements MetadataTransferResult { public getFileResponses(): FileResponse[] { // this involves FS operations, so only perform once! if (!this.fileResponses) { - // TODO: Log when messages can't be mapped to components - const responseMessages = this.getDeployMessages(this.response); - const fileResponses: FileResponse[] = []; - if (this.components) { - for (const deployedComponent of this.components.getSourceComponents()) { - if (deployedComponent.type.children) { - for (const child of deployedComponent.getChildren()) { - const childMessages = responseMessages.get(this.key(child)); - if (childMessages) { - fileResponses.push(...this.createResponses(child, childMessages)); - } - } - } - const componentMessages = responseMessages.get(this.key(deployedComponent)); - if (componentMessages) { - fileResponses.push(...this.createResponses(deployedComponent, componentMessages)); - } - } - - this.fileResponses = fileResponses.concat(this.deleteNotFoundToFileResponses(responseMessages)); + // TODO: Log when messages can't be mapped to components + const responseMessages = this.getDeployMessages(this.response); + + this.fileResponses = (this.components.getSourceComponents().toArray() ?? []) + .flatMap((deployedComponent) => + this.createResponses(deployedComponent, responseMessages.get(this.key(deployedComponent)) ?? []).concat( + deployedComponent.type.children + ? deployedComponent.getChildren().flatMap((child) => { + const childMessages = responseMessages.get(this.key(child)); + return childMessages ? this.createResponses(child, childMessages) : []; + }) + : [] + ) + ) + .concat(this.deleteNotFoundToFileResponses(responseMessages)); } else { // if no this.components, this was likely a metadata format deploy so we need to process // the componentSuccesses and componentFailures instead. - const successes = ensureArray(this.response.details?.componentSuccesses); - const failures = ensureArray(this.response.details?.componentFailures); - for (const component of [...successes, ...failures]) { - if (component.fullName === 'package.xml') continue; - const baseResponse: Partial = { - fullName: component.fullName, - type: component.componentType, - state: getState(component), - filePath: component.fileName.replace(`zip${sep}`, ''), - }; - - if (baseResponse.state === ComponentStatus.Failed) { - baseResponse.error = component.problem; - baseResponse.problemType = component.problemType; - } - - fileResponses.push(baseResponse as FileResponse); - } - this.fileResponses = fileResponses; + this.fileResponses = ensureArray(this.response.details?.componentSuccesses) + .concat(ensureArray(this.response.details?.componentFailures)) + .filter((c) => c.fullName !== 'package.xml') + .map( + (c) => + ({ + ...(getState(c) === ComponentStatus.Failed + ? { + error: c.problem, + problemType: c.problemType, + } + : {}), + fullName: c.fullName, + type: c.componentType, + state: getState(c), + filePath: c.fileName.replace(`zip${sep}`, ''), + } as FileResponse) + ); } } return this.fileResponses; diff --git a/src/client/metadataApiRetrieve.ts b/src/client/metadataApiRetrieve.ts index 98c2c8378e..48c6119907 100644 --- a/src/client/metadataApiRetrieve.ts +++ b/src/client/metadataApiRetrieve.ts @@ -23,7 +23,6 @@ import { MetadataTransferResult, PackageOption, RequestStatus, - RetrieveExtractOptions, RetrieveOptions, RetrieveRequest, } from './types'; @@ -282,16 +281,14 @@ export class MetadataApiRetrieve extends MetadataTransfer< } private async extract(zip: Buffer): Promise { - const components: SourceComponent[] = []; + let components: SourceComponent[] = []; const { merge, output, registry } = this.options; const converter = new MetadataConverter(registry); const tree = await ZipTreeContainer.create(zip); - const packages: RetrieveExtractOptions[] = [{ zipTreeLocation: 'unpackaged', outputDir: output }]; - const packageOpts = this.getPackageOptions(); - packageOpts?.forEach(({ name, outputDir }) => { - packages.push({ zipTreeLocation: name, outputDir }); - }); + const packages = [{ zipTreeLocation: 'unpackaged', outputDir: output }].concat( + this.getPackageOptions().map(({ name, outputDir }) => ({ zipTreeLocation: name, outputDir })) + ); for (const pkg of packages) { const outputConfig: ConvertOutputConfig = merge @@ -320,9 +317,7 @@ export class MetadataApiRetrieve extends MetadataTransfer< // this is intentional sequential // eslint-disable-next-line no-await-in-loop const convertResult = await converter.convert(zipComponents, 'source', outputConfig); - if (convertResult?.converted) { - components.push(...convertResult.converted); - } + components = components.concat(convertResult?.converted ?? []); } return new ComponentSet(components, registry); } diff --git a/src/resolve/metadataResolver.ts b/src/resolve/metadataResolver.ts index 79c7db3ecd..356d01771c 100644 --- a/src/resolve/metadataResolver.ts +++ b/src/resolve/metadataResolver.ts @@ -115,11 +115,7 @@ export class MetadataResolver { } } - for (const directory of dirQueue) { - components.push(...this.getComponentsFromPathRecursive(directory, inclusiveFilter)); - } - - return components; + return components.concat(dirQueue.flatMap((d) => this.getComponentsFromPathRecursive(d, inclusiveFilter))); } private resolveComponent(fsPath: string, isResolvingSource: boolean): SourceComponent | undefined { @@ -269,7 +265,7 @@ export class MetadataResolver { let guesses; if (metaSuffix) { - guesses = this.registry.guessTypeBySuffix(metaSuffix) + guesses = this.registry.guessTypeBySuffix(metaSuffix); } else if (!metaSuffix && closeMetaSuffix) { guesses = this.registry.guessTypeBySuffix(closeMetaSuffix[1]); } else { @@ -279,11 +275,11 @@ export class MetadataResolver { // If guesses were found, format an array of strings to be passed to SfError's actions return guesses && guesses.length > 0 ? [ - messages.getMessage('suggest_type_header', [ basename(fsPath) ]), + messages.getMessage('suggest_type_header', [basename(fsPath)]), ...guesses.map((guess) => messages.getMessage('suggest_type_did_you_mean', [ guess.suffixGuess, - (metaSuffix || closeMetaSuffix) ? '-meta.xml' : '', + metaSuffix || closeMetaSuffix ? '-meta.xml' : '', guess.metadataTypeGuess.name, ]) ), diff --git a/src/resolve/sourceComponent.ts b/src/resolve/sourceComponent.ts index da5dcfb930..09cae25019 100644 --- a/src/resolve/sourceComponent.ts +++ b/src/resolve/sourceComponent.ts @@ -365,36 +365,35 @@ export class SourceComponent implements MetadataComponent { // E.g., CustomLabels, Workflows, SharingRules, AssignmentRules. private getNonDecomposedChildren(): SourceComponent[] { const parsed = this.parseXmlSync(); - const children: SourceComponent[] = []; if (!this.type.children) { throw new SfError(`There are no child types for ${this.type.name}`); } - for (const childTypeId of Object.keys(this.type.children.types)) { - const childType = this.type.children.types[childTypeId]; + + return Object.values(this.type.children.types).flatMap((childType) => { const uniqueIdElement = childType.uniqueIdElement; - if (uniqueIdElement) { - const xmlPathToChildren = `${this.type.name}.${childType.xmlElementName}`; - const elements = ensureArray(get(parsed, xmlPathToChildren, [])); - const childComponents = elements.map((element) => { - const name = getString(element, uniqueIdElement); - if (!name) { - throw new SfError(`Missing ${uniqueIdElement} on ${childType.name} in ${this.xml}`); - } - return new SourceComponent( - { - name, - type: childType, - xml: this.xml, - parent: this, - }, - this.treeContainer, - this.forceIgnore - ); - }); - children.push(...childComponents); + + if (!uniqueIdElement) { + return []; } - } - return children; + const xmlPathToChildren = `${this.type.name}.${childType.xmlElementName}`; + const elements = ensureArray(get(parsed, xmlPathToChildren, [])); + return elements.map((element) => { + const name = getString(element, uniqueIdElement); + if (!name) { + throw new SfError(`Missing ${uniqueIdElement} on ${childType.name} in ${this.xml}`); + } + return new SourceComponent( + { + name, + type: childType, + xml: this.xml, + parent: this, + }, + this.treeContainer, + this.forceIgnore + ); + }); + }); } private *walk(fsPath: string): IterableIterator { diff --git a/test/client/metadataApiDeploy.test.ts b/test/client/metadataApiDeploy.test.ts index fe2d4d677a..4e6355e66a 100644 --- a/test/client/metadataApiDeploy.test.ts +++ b/test/client/metadataApiDeploy.test.ts @@ -6,7 +6,10 @@ */ import { basename, join } from 'path'; import { MockTestOrgData, TestContext } from '@salesforce/core/lib/testSetup'; +import deepEqualInAnyOrder = require('deep-equal-in-any-order'); + import { assert, expect } from 'chai'; +import * as chai from 'chai'; import { AnyJson, getString } from '@salesforce/ts-types'; import { PollingClient, StatusResult, Messages } from '@salesforce/core'; import { Duration } from '@salesforce/kit'; @@ -36,6 +39,8 @@ import { } from '../mock/type-constants/customObjectConstant'; import { COMPONENT } from '../mock/type-constants/apexClassConstant'; +chai.use(deepEqualInAnyOrder); + Messages.importMessagesDirectory(__dirname); const messages = Messages.loadMessages('@salesforce/source-deploy-retrieve', 'sdr'); const expectedError = { @@ -820,7 +825,7 @@ describe('MetadataApiDeploy', () => { }, ]; - expect(responses).to.deep.equal(expected); + expect(responses).to.deep.equalInAnyOrder(expected); }); it('should report "Deleted" when no component in org', () => {