From af9f07189b48d87a38ecc01763a4d682264aa60a Mon Sep 17 00:00:00 2001 From: mshanemc Date: Tue, 4 Oct 2022 10:14:12 -0500 Subject: [PATCH 01/10] refactor: remove let, push variables down to JIT --- src/convert/metadataConverter.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/convert/metadataConverter.ts b/src/convert/metadataConverter.ts index f7a241bac1..c5272ee98b 100644 --- a/src/convert/metadataConverter.ts +++ b/src/convert/metadataConverter.ts @@ -43,7 +43,6 @@ export class MetadataConverter { (comps instanceof ComponentSet ? Array.from(comps.getSourceComponents()) : comps) as SourceComponent[] ).filter((comp) => comp.type.isAddressable !== false); - let manifestContents; const isSource = targetFormat === 'source'; const tasks: Array> = []; @@ -57,14 +56,13 @@ export class MetadataConverter { if (output.packageName) { cs.fullName = output.packageName; } - manifestContents = await cs.getPackageXml(); packagePath = this.getPackagePath(output); defaultDirectory = packagePath; writer = new StandardWriter(packagePath); if (!isSource) { const manifestPath = join(packagePath, MetadataConverter.PACKAGE_XML_FILE); tasks.push( - promises.writeFile(manifestPath, manifestContents), + promises.writeFile(manifestPath, await cs.getPackageXml()), ...cs.getTypesOfDestructiveChanges().map(async (destructiveChangesType) => // for each of the destructive changes in the component set, convert and write the correct metadata // to each manifest @@ -80,12 +78,11 @@ export class MetadataConverter { if (output.packageName) { cs.fullName = output.packageName; } - manifestContents = await cs.getPackageXml(); packagePath = this.getPackagePath(output); defaultDirectory = packagePath; writer = new ZipWriter(packagePath); if (!isSource) { - writer.addToZip(manifestContents, MetadataConverter.PACKAGE_XML_FILE); + writer.addToZip(await cs.getPackageXml(), MetadataConverter.PACKAGE_XML_FILE); // for each of the destructive changes in the component set, convert and write the correct metadata // to each manifest for (const destructiveChangeType of cs.getTypesOfDestructiveChanges()) { From 0d38b1f8d0fc6c89d1540d0913ff85965c13f280 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Tue, 4 Oct 2022 11:28:18 -0500 Subject: [PATCH 02/10] fix: decomposed adapter should resolve a COFT to its parent --- .../adapters/decomposedSourceAdapter.ts | 25 +++++++++++-------- test/resolve/sourceComponent.test.ts | 23 ++++++++++++++++- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/resolve/adapters/decomposedSourceAdapter.ts b/src/resolve/adapters/decomposedSourceAdapter.ts index 49da57c976..bc67b914f3 100644 --- a/src/resolve/adapters/decomposedSourceAdapter.ts +++ b/src/resolve/adapters/decomposedSourceAdapter.ts @@ -87,7 +87,14 @@ export class DecomposedSourceAdapter extends MixedContentSourceAdapter { const strategy = this.type.strategies.decomposition; if (triggerIsAChild) { - if (strategy === DecompositionStrategy.FolderPerType || isResolvingSource) { + if ( + strategy === DecompositionStrategy.TopLevel && + this.type.children.types[childTypeId].unaddressableWithoutParent && + isResolvingSource + ) { + // we can't deploy the child, so we need to return its parent component + return component; + } else if (strategy === DecompositionStrategy.FolderPerType || isResolvingSource) { let parent = component; if (!parent) { parent = new SourceComponent( @@ -111,15 +118,13 @@ export class DecomposedSourceAdapter extends MixedContentSourceAdapter { this.forceIgnore ); } - } else { - if (!component) { - // This is most likely metadata found within a CustomObject folder that is not a - // child type of CustomObject. E.g., Layout, SharingRules, ApexClass. - throw new SfError( - messages.getMessage('error_unexpected_child_type', [trigger, this.type.name]), - 'TypeInferenceError' - ); - } + } else if (!component) { + // This is most likely metadata found within a CustomObject folder that is not a + // child type of CustomObject. E.g., Layout, SharingRules, ApexClass. + throw new SfError( + messages.getMessage('error_unexpected_child_type', [trigger, this.type.name]), + 'TypeInferenceError' + ); } if (component) { component.content = pathToContent; diff --git a/test/resolve/sourceComponent.test.ts b/test/resolve/sourceComponent.test.ts index 6a56a83a9b..1a42b806b7 100644 --- a/test/resolve/sourceComponent.test.ts +++ b/test/resolve/sourceComponent.test.ts @@ -8,7 +8,6 @@ import { join } from 'path'; import { assert, expect } from 'chai'; import { createSandbox } from 'sinon'; import { Messages, SfError } from '@salesforce/core'; - import { decomposed, matchingContentFile, mixedContentDirectory, xmlInFolder } from '../mock'; import { DECOMPOSED_COMPONENT } from '../mock/type-constants/customObjectConstant'; import { COMPONENT } from '../mock/type-constants/apexClassConstant'; @@ -32,6 +31,10 @@ import { SourceComponent, VirtualTreeContainer, } from '../../src'; +import { + DECOMPOSED_TOP_LEVEL_CHILD_XML_PATHS, + DECOMPOSED_TOP_LEVEL_COMPONENT, +} from '../mock/type-constants/customObjectTranslationConstant'; import { DecomposedSourceAdapter } from '../../src/resolve/adapters'; import { RegistryTestUtil } from './registryTestUtil'; @@ -423,6 +426,24 @@ describe('SourceComponent', () => { }); }); + describe('Un-addressable decomposed child (cot/cof)', () => { + it('gets parent when asked to resolve a child by filePath', () => { + const expectedTopLevel = DECOMPOSED_TOP_LEVEL_COMPONENT; + const adapter = new DecomposedSourceAdapter( + expectedTopLevel.type, + new RegistryAccess(), + undefined, + expectedTopLevel.tree + ); + + const result = adapter.getComponent(DECOMPOSED_TOP_LEVEL_CHILD_XML_PATHS[0], true); + // eslint-disable-next-line no-console + console.log(result); + expect(result.type).to.deep.equal(expectedTopLevel.type); + expect(result.xml).to.equal(expectedTopLevel.xml); + }); + }); + describe('Nondecomposed Child Components', () => { const type = registry.types.customlabels; const expectedChild = SourceComponent.createVirtualComponent( From ae1e035d2fa40d82544e50e70d23eca22ddc1ff8 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Tue, 4 Oct 2022 11:30:20 -0500 Subject: [PATCH 03/10] chore: auto-update metadata coverage in METADATA_SUPPORT.md --- METADATA_SUPPORT.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/METADATA_SUPPORT.md b/METADATA_SUPPORT.md index 35ec9b10dc..93809039da 100644 --- a/METADATA_SUPPORT.md +++ b/METADATA_SUPPORT.md @@ -531,14 +531,24 @@ v57 introduces the following new types. Here's their current level of support |Metadata Type|Support|Notes| |:---|:---|:---| |ActionableListDefinition|❌|Not supported, but support could be added| +|CampaignTemplateDefinition|❌|Not supported, but support could be added| |ClauseCatgConfiguration|❌|Not supported, but support could be added| +|DisclosureDefinition|❌|Not supported, but support could be added| +|DisclosureDefinitionVersion|❌|Not supported, but support could be added| |DisclosureType|❌|Not supported, but support could be added| |ExternalClientApplication|✅|| +|ExternalDocStorageConfig|❌|Not supported, but support could be added| +|Gear|❌|Not supported, but support could be added| |GearDescriptor|❌|Not supported, but support could be added| +|GearLifecycle|❌|Not supported, but support could be added| |GearRule|❌|Not supported, but support could be added| +|GearRuleTest|❌|Not supported, but support could be added| |IdentityProviderSettings|✅|| +|LightningPropertyTypeBundle|❌|Not supported, but support could be added (but not for tracking)| +|LocationUse|❌|Not supported, but support could be added| |OmniSupervisorConfig|❌|Not supported, but support could be added (but not for tracking)| |ProductSpecificationTypeDefinition|❌|Not supported, but support could be added| +|WaveAnalyticAssetCollection|❌|Not supported, but support could be added| ## Additional Types From 7d0dcd1f2908a41a20d0e6d2e698b56501e88e85 Mon Sep 17 00:00:00 2001 From: SF-CLI-BOT Date: Tue, 4 Oct 2022 16:40:14 +0000 Subject: [PATCH 04/10] test: record perf --- .../eda.json | 8 ++++---- .../lotsOfClasses.json | 8 ++++---- .../lotsOfClassesOneDir.json | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/eda.json b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/eda.json index 44ecf55f87..b4a2a1e84a 100644 --- a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/eda.json +++ b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/eda.json @@ -1,18 +1,18 @@ [ { "name": "componentSetCreate", - "duration": 197.8062740000314 + "duration": 208.06498400005512 }, { "name": "sourceToMdapi", - "duration": 5338.978776999982 + "duration": 5322.269709000015 }, { "name": "sourceToZip", - "duration": 4433.559571999998 + "duration": 4832.698105999967 }, { "name": "mdapiToSource", - "duration": 6825.319519999961 + "duration": 3625.784056000004 } ] \ No newline at end of file diff --git a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/lotsOfClasses.json b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/lotsOfClasses.json index 6fe4cbd23e..d0b099f5c9 100644 --- a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/lotsOfClasses.json +++ b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/lotsOfClasses.json @@ -1,18 +1,18 @@ [ { "name": "componentSetCreate", - "duration": 401.4154649999691 + "duration": 397.36901500000386 }, { "name": "sourceToMdapi", - "duration": 8158.042217999988 + "duration": 7502.408032000007 }, { "name": "sourceToZip", - "duration": 6723.08442899998 + "duration": 6753.71645300003 }, { "name": "mdapiToSource", - "duration": 7021.386991000036 + "duration": 4371.168727000011 } ] \ No newline at end of file diff --git a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/lotsOfClassesOneDir.json b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/lotsOfClassesOneDir.json index dd85b4b756..b6dcc55792 100644 --- a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/lotsOfClassesOneDir.json +++ b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8370C-CPU-2-80GHz/lotsOfClassesOneDir.json @@ -1,18 +1,18 @@ [ { "name": "componentSetCreate", - "duration": 701.4275400000042 + "duration": 708.7594559999998 }, { "name": "sourceToMdapi", - "duration": 12828.85087699996 + "duration": 10645.160910999984 }, { "name": "sourceToZip", - "duration": 9517.812057000003 + "duration": 9419.763166999968 }, { "name": "mdapiToSource", - "duration": 13720.21484999999 + "duration": 7377.691368 } ] \ No newline at end of file From 17c86d79b7d0c64dbc14cfa9a1f336ac1a216a10 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Tue, 4 Oct 2022 14:22:36 -0500 Subject: [PATCH 05/10] refactor: let COT/CFT skip childtype logic --- src/resolve/adapters/decomposedSourceAdapter.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/resolve/adapters/decomposedSourceAdapter.ts b/src/resolve/adapters/decomposedSourceAdapter.ts index bc67b914f3..2940e8843b 100644 --- a/src/resolve/adapters/decomposedSourceAdapter.ts +++ b/src/resolve/adapters/decomposedSourceAdapter.ts @@ -86,15 +86,8 @@ export class DecomposedSourceAdapter extends MixedContentSourceAdapter { const triggerIsAChild = !!childTypeId; const strategy = this.type.strategies.decomposition; - if (triggerIsAChild) { - if ( - strategy === DecompositionStrategy.TopLevel && - this.type.children.types[childTypeId].unaddressableWithoutParent && - isResolvingSource - ) { - // we can't deploy the child, so we need to return its parent component - return component; - } else if (strategy === DecompositionStrategy.FolderPerType || isResolvingSource) { + if (triggerIsAChild && !this.type.children.types[childTypeId].unaddressableWithoutParent) { + if (strategy === DecompositionStrategy.FolderPerType || isResolvingSource) { let parent = component; if (!parent) { parent = new SourceComponent( From 8f4512998fb374f6c3d17a7996833aeb23355dd0 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Tue, 4 Oct 2022 14:23:12 -0500 Subject: [PATCH 06/10] fix: make fileReponses for CFT when COT is deployed --- src/client/metadataApiDeploy.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/client/metadataApiDeploy.ts b/src/client/metadataApiDeploy.ts index e930d6057f..3aecfa940a 100644 --- a/src/client/metadataApiDeploy.ts +++ b/src/client/metadataApiDeploy.ts @@ -106,20 +106,23 @@ export class DeployResult implements MetadataTransferResult { if (baseResponse.state === ComponentStatus.Failed) { const diagnostic = this.diagnosticUtil.parseDeployDiagnostic(component, message); - const response = Object.assign(baseResponse, diagnostic) as FileResponse; + const response = { ...baseResponse, diagnostic } as FileResponse; responses.push(response); } else { // components with children are already taken care of through the messages, // so don't walk their content directories. - if (content && !type.children) { + if ( + content && + (!type.children || Object.values(type.children.types).some((t) => t.unaddressableWithoutParent)) + ) { for (const filePath of component.walkContent()) { - const response = Object.assign({}, baseResponse, { filePath }) as FileResponse; + const response = { ...baseResponse, filePath } as FileResponse; responses.push(response); } } if (xml) { - const response = Object.assign({}, baseResponse, { filePath: xml }) as FileResponse; + const response = { ...baseResponse, filePath: xml } as FileResponse; responses.push(response); } } From a23fb7975f0a68391665bd7284520ff0c3ac62df Mon Sep 17 00:00:00 2001 From: mshanemc Date: Tue, 4 Oct 2022 14:32:06 -0500 Subject: [PATCH 07/10] refactor: restore objectAssign for diagnostic --- src/client/metadataApiDeploy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/metadataApiDeploy.ts b/src/client/metadataApiDeploy.ts index 3aecfa940a..fd0ee8d6ae 100644 --- a/src/client/metadataApiDeploy.ts +++ b/src/client/metadataApiDeploy.ts @@ -106,7 +106,7 @@ export class DeployResult implements MetadataTransferResult { if (baseResponse.state === ComponentStatus.Failed) { const diagnostic = this.diagnosticUtil.parseDeployDiagnostic(component, message); - const response = { ...baseResponse, diagnostic } as FileResponse; + const response = Object.assign(baseResponse, diagnostic) as FileResponse; responses.push(response); } else { // components with children are already taken care of through the messages, From e974ff5550fb097b685d03771d418492f43b0727 Mon Sep 17 00:00:00 2001 From: SF-CLI-BOT Date: Tue, 4 Oct 2022 19:43:44 +0000 Subject: [PATCH 08/10] test: record perf --- .../eda.json | 8 ++++---- .../lotsOfClasses.json | 8 ++++---- .../lotsOfClassesOneDir.json | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/eda.json b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/eda.json index 980a46ecd3..9b5cb649cb 100644 --- a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/eda.json +++ b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/eda.json @@ -1,18 +1,18 @@ [ { "name": "componentSetCreate", - "duration": 218.47389499998826 + "duration": 227.84873699999298 }, { "name": "sourceToMdapi", - "duration": 5293.27240300001 + "duration": 5575.808999000001 }, { "name": "sourceToZip", - "duration": 4158.915987000015 + "duration": 5121.344982999988 }, { "name": "mdapiToSource", - "duration": 6551.467303000012 + "duration": 4306.255004000006 } ] \ No newline at end of file diff --git a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/lotsOfClasses.json b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/lotsOfClasses.json index e36ee1c20e..88864c7f2e 100644 --- a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/lotsOfClasses.json +++ b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/lotsOfClasses.json @@ -1,18 +1,18 @@ [ { "name": "componentSetCreate", - "duration": 431.3132029999979 + "duration": 464.14559599998756 }, { "name": "sourceToMdapi", - "duration": 8141.630254999996 + "duration": 8464.103521000012 }, { "name": "sourceToZip", - "duration": 6378.759560999984 + "duration": 7716.617144000018 }, { "name": "mdapiToSource", - "duration": 7380.699353000004 + "duration": 5273.308957000001 } ] \ No newline at end of file diff --git a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/lotsOfClassesOneDir.json b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/lotsOfClassesOneDir.json index 8e93676913..1d50cf74dd 100644 --- a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/lotsOfClassesOneDir.json +++ b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-Platinum-8272CL-CPU-2-60GHz/lotsOfClassesOneDir.json @@ -1,18 +1,18 @@ [ { "name": "componentSetCreate", - "duration": 764.7591390000016 + "duration": 782.2161900000065 }, { "name": "sourceToMdapi", - "duration": 11849.736803999986 + "duration": 12909.834803000005 }, { "name": "sourceToZip", - "duration": 10867.191843999986 + "duration": 11247.063521999982 }, { "name": "mdapiToSource", - "duration": 14328.787168999988 + "duration": 12979.326094000018 } ] \ No newline at end of file From 072a4d2a72b5089550dc13e6d44a0e4f99786597 Mon Sep 17 00:00:00 2001 From: mshanemc Date: Tue, 4 Oct 2022 16:49:36 -0500 Subject: [PATCH 09/10] test: cleanup console.log --- test/resolve/sourceComponent.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/resolve/sourceComponent.test.ts b/test/resolve/sourceComponent.test.ts index 1a42b806b7..8aef95ffb9 100644 --- a/test/resolve/sourceComponent.test.ts +++ b/test/resolve/sourceComponent.test.ts @@ -437,8 +437,6 @@ describe('SourceComponent', () => { ); const result = adapter.getComponent(DECOMPOSED_TOP_LEVEL_CHILD_XML_PATHS[0], true); - // eslint-disable-next-line no-console - console.log(result); expect(result.type).to.deep.equal(expectedTopLevel.type); expect(result.xml).to.equal(expectedTopLevel.xml); }); From 7e9bb39951c843bec61d3922146e91e23eef420a Mon Sep 17 00:00:00 2001 From: SF-CLI-BOT Date: Tue, 4 Oct 2022 22:01:27 +0000 Subject: [PATCH 10/10] test: record perf --- .../eda.json | 8 ++++---- .../lotsOfClasses.json | 8 ++++---- .../lotsOfClassesOneDir.json | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/eda.json b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/eda.json index d7a2b9d488..8705e1dfa6 100644 --- a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/eda.json +++ b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/eda.json @@ -1,18 +1,18 @@ [ { "name": "componentSetCreate", - "duration": 325.82882699999027 + "duration": 329.62463900004514 }, { "name": "sourceToMdapi", - "duration": 7251.922354000009 + "duration": 7505.23844700004 }, { "name": "sourceToZip", - "duration": 5983.844335000002 + "duration": 6470.010548999999 }, { "name": "mdapiToSource", - "duration": 8623.723956000002 + "duration": 5877.771837000037 } ] \ No newline at end of file diff --git a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/lotsOfClasses.json b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/lotsOfClasses.json index bab9d4631f..bd8ffac737 100644 --- a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/lotsOfClasses.json +++ b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/lotsOfClasses.json @@ -1,18 +1,18 @@ [ { "name": "componentSetCreate", - "duration": 664.5060110000195 + "duration": 644.1402209999505 }, { "name": "sourceToMdapi", - "duration": 11993.994738000038 + "duration": 11856.592849999957 }, { "name": "sourceToZip", - "duration": 9293.955343000009 + "duration": 10338.099250999978 }, { "name": "mdapiToSource", - "duration": 10224.62978399999 + "duration": 8291.250971000001 } ] \ No newline at end of file diff --git a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/lotsOfClassesOneDir.json b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/lotsOfClassesOneDir.json index 192a6f3670..9fe92f79b0 100644 --- a/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/lotsOfClassesOneDir.json +++ b/test/nuts/perfResults/x64-linux-2xIntel-Xeon-CPU-E5-2673-v4-2-30GHz/lotsOfClassesOneDir.json @@ -1,18 +1,18 @@ [ { "name": "componentSetCreate", - "duration": 1084.5274579999968 + "duration": 1090.1220250000479 }, { "name": "sourceToMdapi", - "duration": 18790.406279999996 + "duration": 17970.10952900001 }, { "name": "sourceToZip", - "duration": 16412.87079200003 + "duration": 15943.596995999978 }, { "name": "mdapiToSource", - "duration": 16847.423238000018 + "duration": 14545.061661000014 } ] \ No newline at end of file