diff --git a/package.json b/package.json index 62c27ef21a..08f0aa7d25 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@salesforce/source-deploy-retrieve", - "version": "4.5.12", + "version": "5.0.0", "description": "JavaScript library to run Salesforce metadata deploys and retrieves", "main": "lib/src/index.js", "author": "Salesforce", diff --git a/src/collections/componentSet.ts b/src/collections/componentSet.ts index 2a054587c7..55105e35aa 100644 --- a/src/collections/componentSet.ts +++ b/src/collections/componentSet.ts @@ -64,7 +64,10 @@ export class ComponentSet extends LazyCollection { private components = new Map>(); // internal component maps used by this.getObject() when building manifests. - private destructiveComponents = new Map>(); + private destructiveComponents = { + [DestructiveChangesType.PRE]: new Map>(), + [DestructiveChangesType.POST]: new Map>(), + }; private manifestComponents = new Map>(); private destructiveChangesType = DestructiveChangesType.POST; @@ -76,11 +79,12 @@ export class ComponentSet extends LazyCollection { this.logger = Logger.childFromRoot(this.constructor.name); for (const component of components) { - let asDeletion = false; - if (component instanceof SourceComponent) { - asDeletion = component.isMarkedForDelete(); - } - this.add(component, asDeletion); + const destructiveType = + component instanceof SourceComponent + ? component.getDestructiveChangesType() + : this.destructiveChangesType; + + this.add(component, destructiveType); } } @@ -128,15 +132,15 @@ export class ComponentSet extends LazyCollection { const resolver = new MetadataResolver(registry, tree); const set = new ComponentSet([], registry); - const buildComponents = (paths: string[], asDeletes: boolean): void => { + const buildComponents = (paths: string[], destructiveType?: DestructiveChangesType): void => { for (const path of paths) { for (const component of resolver.getComponentsFromPath(path, inclusiveFilter)) { - set.add(component, asDeletes); + set.add(component, destructiveType); } } }; - buildComponents(fsPaths, false); - buildComponents(fsDeletePaths, true); + buildComponents(fsPaths); + buildComponents(fsDeletePaths, DestructiveChangesType.POST); set.forceIgnoredPaths = resolver.forceIgnoredPaths; @@ -171,6 +175,7 @@ export class ComponentSet extends LazyCollection { const manifestResolver = new ManifestResolver(options.tree, options.registry); const manifest = await manifestResolver.resolve(manifestPath); + const resolveIncludeSet = options.resolveSourcePaths ? new ComponentSet([], options.registry) : undefined; @@ -178,14 +183,41 @@ export class ComponentSet extends LazyCollection { result.apiVersion = manifest.apiVersion; result.fullName = manifest.fullName; - for (const component of manifest.components) { + const addComponent = ( + component: MetadataComponent, + deletionType?: DestructiveChangesType + ): void => { if (resolveIncludeSet) { - resolveIncludeSet.add(component); + resolveIncludeSet.add(component, deletionType); } const memberIsWildcard = component.fullName === ComponentSet.WILDCARD; if (!memberIsWildcard || options.forceAddWildcards || !options.resolveSourcePaths) { - result.add(component); + result.add(component, deletionType); } + }; + + const resolveDestructiveChanges = async ( + path: string, + destructiveChangeType: DestructiveChangesType + ) => { + const manifest = await manifestResolver.resolve(path); + for (const comp of manifest.components) { + addComponent( + new SourceComponent({ type: comp.type, name: comp.fullName }), + destructiveChangeType + ); + } + }; + + if (options.destructivePre) { + await resolveDestructiveChanges(options.destructivePre, DestructiveChangesType.PRE); + } + if (options.destructivePost) { + await resolveDestructiveChanges(options.destructivePost, DestructiveChangesType.POST); + } + + for (const component of manifest.components) { + addComponent(component); } if (options.resolveSourcePaths) { @@ -251,20 +283,18 @@ export class ComponentSet extends LazyCollection { /** * Get an object representation of a package manifest based on the set components. - * + * @param destructiveType Optional value for generating objects representing destructive change manifests * @returns Object representation of a package manifest */ - public getObject(forDestructiveChanges = false): PackageManifestObject { + public getObject(destructiveType?: DestructiveChangesType): PackageManifestObject { // If this ComponentSet has components marked for delete, we need to // only include those components in a destructiveChanges.xml and // all other components in the regular manifest. let components = this.components; - if (this.hasDeletes) { - if (forDestructiveChanges) { - components = this.destructiveComponents; - } else { - components = this.manifestComponents; - } + if (this.getTypesOfDestructiveChanges().length) { + components = destructiveType + ? this.destructiveComponents[destructiveType] + : this.manifestComponents; } const typeMap = new Map(); @@ -276,7 +306,7 @@ export class ComponentSet extends LazyCollection { typeMap.set(typeName, []); } const typeEntry = typeMap.get(typeName); - if (fullName === ComponentSet.WILDCARD && !type.supportsWildcardAndName) { + if (fullName === ComponentSet.WILDCARD && !type.supportsWildcardAndName && !destructiveType) { // if the type doesn't support mixed wildcards and specific names, overwrite the names to be a wildcard typeMap.set(typeName, [fullName]); } else if ( @@ -330,13 +360,13 @@ export class ComponentSet extends LazyCollection { * @param indentation Number of spaces to indent lines by. * @param forDestructiveChanges Whether to build a manifest for destructive changes. */ - public getPackageXml(indentation = 4, forDestructiveChanges = false): string { + public getPackageXml(indentation = 4, destructiveType?: DestructiveChangesType): string { const j2x = new j2xParser({ format: true, indentBy: new Array(indentation + 1).join(' '), ignoreAttributes: false, }); - const toParse = this.getObject(forDestructiveChanges); + const toParse = this.getObject(destructiveType); toParse.Package[XML_NS_KEY] = XML_NS_URL; return XML_DECL.concat(j2x.parse(toParse)); } @@ -363,29 +393,49 @@ export class ComponentSet extends LazyCollection { >; } - public add(component: ComponentLike, asDeletion?: boolean): void { + public add(component: ComponentLike, deletionType?: DestructiveChangesType): void { const key = this.simpleKey(component); if (!this.components.has(key)) { this.components.set(key, new Map()); } - if (component instanceof SourceComponent) { - this.components.get(key).set(this.sourceKey(component), component); - - // Build maps of destructive components and regular components as they are added - // as an optimization when building manifests. - if (asDeletion) { - component.setMarkedForDelete(true); - this.logger.debug(`Marking component for delete: ${component.fullName}`); - if (!this.destructiveComponents.has(key)) { - this.destructiveComponents.set(key, new Map()); - } - this.destructiveComponents.get(key).set(this.sourceKey(component), component); - } else { - if (!this.manifestComponents.has(key)) { - this.manifestComponents.set(key, new Map()); - } - this.manifestComponents.get(key).set(this.sourceKey(component), component); + + if (!(component instanceof SourceComponent)) { + return; + } + + // we're working with SourceComponents now + this.components.get(key).set(this.sourceKey(component), component); + + // Build maps of destructive components and regular components as they are added + // as an optimization when building manifests. + if (deletionType) { + component.setMarkedForDelete(deletionType); + this.logger.debug(`Marking component for delete: ${component.fullName}`); + const deletions = this.destructiveComponents[deletionType]; + if (!deletions.has(key)) { + deletions.set(key, new Map()); } + deletions.get(key).set(this.sourceKey(component), component); + } else { + if (!this.manifestComponents.has(key)) { + this.manifestComponents.set(key, new Map()); + } + this.manifestComponents.get(key).set(this.sourceKey(component), component); + } + + // something could try adding a component meant for deletion improperly, which would be marked as an addition + // specifically the ComponentSet.fromManifest with the `resolveSourcePaths` options which calls + // ComponentSet.fromSource, and adds everything as an addition + if ( + this.manifestComponents.has(key) && + (this.destructiveChangesPre.has(key) || this.destructiveChangesPost.has(key)) + ) { + // if a component is in the manifestComponents, as well as being part of a destructive manifest, keep in the destructive manifest + component.setMarkedForDelete(deletionType); + this.manifestComponents.delete(key); + this.logger.debug( + `Component: ${key} was found in both destructive and constructive manifests - keeping as a destructive change` + ); } } @@ -477,6 +527,22 @@ export class ComponentSet extends LazyCollection { return this.destructiveChangesType; } + /** + * Will return the types of destructive changes in the component set + * or an empty array if there aren't destructive components present + * @return DestructiveChangesType[] + */ + public getTypesOfDestructiveChanges(): DestructiveChangesType[] { + const destructiveChangesTypes: DestructiveChangesType[] = []; + if (this.destructiveChangesPre.size) { + destructiveChangesTypes.push(DestructiveChangesType.PRE); + } + if (this.destructiveChangesPost.size) { + destructiveChangesTypes.push(DestructiveChangesType.POST); + } + return destructiveChangesTypes; + } + /** * Each {@link SourceComponent} counts as an element in the set, even if multiple * ones map to the same `fullName` and `type` pair. @@ -492,11 +558,12 @@ export class ComponentSet extends LazyCollection { return size; } - /** - * Returns `true` if this `ComponentSet` contains components marked for deletion. - */ - get hasDeletes(): boolean { - return this.destructiveComponents.size > 0; + get destructiveChangesPre(): Map> { + return this.destructiveComponents[DestructiveChangesType.PRE]; + } + + get destructiveChangesPost(): Map> { + return this.destructiveComponents[DestructiveChangesType.POST]; } private sourceKey(component: SourceComponent): string { diff --git a/src/collections/types.ts b/src/collections/types.ts index fca8141487..857dcbd5bc 100644 --- a/src/collections/types.ts +++ b/src/collections/types.ts @@ -62,4 +62,13 @@ export interface FromManifestOptions extends OptionalTreeRegistryOptions { * conditions. */ forceAddWildcards?: boolean; + + /** + * path to a `destructiveChangesPre.xml` file in XML format + */ + destructivePre?: string; + /** + * path to a `destructiveChangesPost.xml` file in XML format + */ + destructivePost?: string; } diff --git a/src/convert/metadataConverter.ts b/src/convert/metadataConverter.ts index d13387cbc0..b48c64a025 100644 --- a/src/convert/metadataConverter.ts +++ b/src/convert/metadataConverter.ts @@ -5,28 +5,27 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ import { - SfdxFileFormat, ConvertOutputConfig, ConvertResult, DirectoryConfig, + SfdxFileFormat, ZipConfig, } from './types'; -import { DestructiveChangesType } from '../collections/types'; import { SourceComponent } from '../resolve'; import { promises } from 'graceful-fs'; import { dirname, join, normalize } from 'path'; import { ensureDirectoryExists } from '../utils/fileSystemHandler'; import { - ComponentReader, ComponentConverter, - StandardWriter, + ComponentReader, + ComponentWriter, pipeline, + StandardWriter, ZipWriter, - ComponentWriter, } from './streams'; import { ConversionError, LibraryError } from '../errors'; import { SourcePath } from '../common'; -import { ComponentSet } from '../collections'; +import { ComponentSet, DestructiveChangesType } from '../collections'; import { RegistryAccess } from '../registry'; export class MetadataConverter { @@ -103,13 +102,19 @@ export class MetadataConverter { if (!isSource) { const manifestPath = join(packagePath, MetadataConverter.PACKAGE_XML_FILE); tasks.push(promises.writeFile(manifestPath, manifestContents)); - // For deploying destructive changes - if (cs.hasDeletes) { - const manifestFileName = this.getDestructiveManifestFileName(cs); - const destructiveManifestContents = cs.getPackageXml(undefined, true); - const destructiveManifestPath = join(packagePath, manifestFileName); - tasks.push(promises.writeFile(destructiveManifestPath, destructiveManifestContents)); + const destructiveChangesTypes = cs.getTypesOfDestructiveChanges(); + if (destructiveChangesTypes.length) { + // for each of the destructive changes in the component set, convert and write the correct metadata + // to each manifest + destructiveChangesTypes.map((destructiveChangesType) => { + const file = this.getDestructiveManifest(destructiveChangesType); + const destructiveManifestContents = cs.getPackageXml(4, destructiveChangesType); + const destructiveManifestPath = join(packagePath, file); + tasks.push( + promises.writeFile(destructiveManifestPath, destructiveManifestContents) + ); + }); } } break; @@ -123,12 +128,16 @@ export class MetadataConverter { writer = new ZipWriter(packagePath); if (!isSource) { (writer as ZipWriter).addToZip(manifestContents, MetadataConverter.PACKAGE_XML_FILE); - // For deploying destructive changes - if (cs.hasDeletes) { - const manifestFileName = this.getDestructiveManifestFileName(cs); - const destructiveManifestContents = cs.getPackageXml(undefined, true); - (writer as ZipWriter).addToZip(destructiveManifestContents, manifestFileName); + const destructiveChangesTypes = cs.getTypesOfDestructiveChanges(); + if (destructiveChangesTypes.length) { + // for each of the destructive changes in the component set, convert and write the correct metadata + // to each manifest + destructiveChangesTypes.map((destructiveChangeType) => { + const file = this.getDestructiveManifest(destructiveChangeType); + const destructiveManifestContents = cs.getPackageXml(4, destructiveChangeType); + (writer as ZipWriter).addToZip(destructiveManifestContents, file); + }); } } break; @@ -167,16 +176,6 @@ export class MetadataConverter { } } - private getDestructiveManifestFileName(cs: ComponentSet): string { - let manifestFileName: string; - if (cs.getDestructiveChangesType() === DestructiveChangesType.POST) { - manifestFileName = MetadataConverter.DESTRUCTIVE_CHANGES_POST_XML_FILE; - } else { - manifestFileName = MetadataConverter.DESTRUCTIVE_CHANGES_PRE_XML_FILE; - } - return manifestFileName; - } - private getPackagePath(outputConfig: DirectoryConfig | ZipConfig): SourcePath | undefined { let packagePath: SourcePath; const { genUniqueDir = true, outputDirectory, packageName, type } = outputConfig; @@ -203,4 +202,12 @@ export class MetadataConverter { } return packagePath; } + + private getDestructiveManifest(destructiveChangesType: DestructiveChangesType): string { + if (destructiveChangesType === DestructiveChangesType.POST) { + return MetadataConverter.DESTRUCTIVE_CHANGES_POST_XML_FILE; + } else if (destructiveChangesType === DestructiveChangesType.PRE) { + return MetadataConverter.DESTRUCTIVE_CHANGES_PRE_XML_FILE; + } + } } diff --git a/src/resolve/sourceComponent.ts b/src/resolve/sourceComponent.ts index e5b44cb9bb..9da4d6b58b 100644 --- a/src/resolve/sourceComponent.ts +++ b/src/resolve/sourceComponent.ts @@ -15,6 +15,7 @@ import { get, getString, JsonMap } from '@salesforce/ts-types'; import { SfdxFileFormat } from '../convert'; import { MetadataType } from '../registry'; import { TypeInferenceError } from '../errors'; +import { DestructiveChangesType } from '../collections'; export type ComponentProperties = { name: string; @@ -38,6 +39,7 @@ export class SourceComponent implements MetadataComponent { private _tree: TreeContainer; private forceIgnore: ForceIgnore; private markedForDelete = false; + private destructiveChangesType: DestructiveChangesType; constructor( props: ComponentProperties, @@ -152,8 +154,21 @@ export class SourceComponent implements MetadataComponent { return this.markedForDelete; } - public setMarkedForDelete(asDeletion: boolean): void { - this.markedForDelete = asDeletion; + public getDestructiveChangesType(): DestructiveChangesType { + return this.destructiveChangesType; + } + + public setMarkedForDelete(destructiveChangeType?: DestructiveChangesType | boolean): void { + if (destructiveChangeType === false) { + this.markedForDelete = false; + // unset destructiveChangesType if it was already set + delete this.destructiveChangesType; + } else { + this.markedForDelete = true; + destructiveChangeType === DestructiveChangesType.PRE + ? (this.destructiveChangesType = DestructiveChangesType.PRE) + : (this.destructiveChangesType = DestructiveChangesType.POST); + } } private calculateRelativePath(fsPath: string): string { diff --git a/test/collections/componentSet.test.ts b/test/collections/componentSet.test.ts index 8b452e6915..7cfabc2272 100644 --- a/test/collections/componentSet.test.ts +++ b/test/collections/componentSet.test.ts @@ -11,16 +11,19 @@ import { join } from 'path'; import { createSandbox, SinonStub } from 'sinon'; import { ComponentSet, + DestructiveChangesType, + ManifestResolver, MetadataApiDeploy, MetadataApiRetrieve, MetadataComponent, + MetadataMember, MetadataResolver, MetadataType, RegistryAccess, + SourceComponent, } from '../../src'; import { ComponentSetError } from '../../src/errors'; import { nls } from '../../src/i18n'; -import { ManifestResolver, MetadataMember, SourceComponent } from '../../src/resolve'; import { mockConnection } from '../mock/client'; import { decomposedtoplevel, @@ -108,12 +111,12 @@ describe('ComponentSet', () => { const mdResolver = new MetadataResolver(mockRegistry, manifestFiles.TREE); const expected = mdResolver.getComponentsFromPath('mixedSingleFiles'); mdResolver.getComponentsFromPath('decomposedTopLevels').forEach((comp) => { - comp.setMarkedForDelete(true); + comp.setMarkedForDelete(); expected.push(comp); }); expect(result).to.deep.equal(expected); - expect(compSet.hasDeletes).to.be.true; + expect(!!compSet.getTypesOfDestructiveChanges().length).to.be.true; }); }); @@ -327,7 +330,7 @@ describe('ComponentSet', () => { tree: manifestFiles.TREE, fsDeletePaths: ['.'], }); - expect(set.getObject(true)).to.deep.equal({ + expect(set.getObject(DestructiveChangesType.POST)).to.deep.equal({ Package: { fullName: undefined, types: [ @@ -562,7 +565,9 @@ describe('ComponentSet', () => { tree: manifestFiles.TREE, fsDeletePaths: ['.'], }); - expect(set.getPackageXml(4, true)).to.equal(manifestFiles.BASIC.data.toString()); + expect(set.getPackageXml(4, DestructiveChangesType.POST)).to.equal( + manifestFiles.BASIC.data.toString() + ); }); }); @@ -780,18 +785,41 @@ describe('ComponentSet', () => { it('should add metadata component marked for delete to package components', async () => { const set = new ComponentSet(undefined, mockRegistry); - expect(set.hasDeletes).to.be.false; + expect(!!set.getTypesOfDestructiveChanges().length).to.be.false; + + const component = new SourceComponent({ + name: mixedContentSingleFile.COMPONENT.name, + type: mixedContentSingleFile.COMPONENT.type, + xml: mixedContentSingleFile.COMPONENT.xml, + }); + set.add(component, DestructiveChangesType.POST); + + expect(!!set.getTypesOfDestructiveChanges().length).to.be.true; + expect(set.getSourceComponents().first().isMarkedForDelete()).to.be.true; + expect(set.has(component)).to.be.true; + }); + + it('should delete metadata from package components, if its present in destructive changes', async () => { + const set = new ComponentSet(undefined, mockRegistry); + expect(!!set.getTypesOfDestructiveChanges().length).to.be.false; const component = new SourceComponent({ name: mixedContentSingleFile.COMPONENT.name, type: mixedContentSingleFile.COMPONENT.type, xml: mixedContentSingleFile.COMPONENT.xml, }); - set.add(component, true); + set.add(component, DestructiveChangesType.POST); + + expect(!!set.getTypesOfDestructiveChanges().length).to.be.true; + expect(set.getDestructiveChangesType()).to.equal(DestructiveChangesType.POST); + expect(set.getSourceComponents().first().isMarkedForDelete()).to.be.true; - expect(set.hasDeletes).to.be.true; + set.add(component); + set.setDestructiveChangesType(DestructiveChangesType.PRE); + expect(set.getDestructiveChangesType()).to.equal(DestructiveChangesType.PRE); expect(set.getSourceComponents().first().isMarkedForDelete()).to.be.true; expect(set.has(component)).to.be.true; + expect(set.getSourceComponents().toArray().length).to.equal(1); }); }); diff --git a/test/convert/metadataConverter.test.ts b/test/convert/metadataConverter.test.ts index 40e366c3e0..5618118dab 100644 --- a/test/convert/metadataConverter.test.ts +++ b/test/convert/metadataConverter.test.ts @@ -5,21 +5,25 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ import { createSandbox, SinonStub } from 'sinon'; -import { xmlInFolder, mockRegistry } from '../mock/registry'; +import { mockRegistry, xmlInFolder } from '../mock/registry'; import * as streams from '../../src/convert/streams'; import * as fs from 'graceful-fs'; import * as fsUtil from '../../src/utils/fileSystemHandler'; import { dirname, join } from 'path'; -import { expect, assert } from 'chai'; +import { assert, expect } from 'chai'; import { ConversionError, LibraryError } from '../../src/errors'; import { COMPONENTS } from '../mock/registry/type-constants/mixedContentInFolderConstants'; import { fail } from 'assert'; -import { ComponentSet, MetadataConverter, SourceComponent } from '../../src'; +import { + ComponentSet, + DestructiveChangesType, + MetadataConverter, + SourceComponent, +} from '../../src'; import { DECOMPOSED_CHILD_COMPONENT_1, DECOMPOSED_CHILD_COMPONENT_2, } from '../mock/registry/type-constants/decomposedConstants'; -import { DestructiveChangesType } from '../../src/collections/types'; const env = createSandbox(); @@ -160,7 +164,7 @@ describe('MetadataConverter', () => { ]); }); - it('should write destructive changes post manifest when ComponentSet has deletes', async () => { + it('should write destructive changes post manifest when ComponentSet has deletes marked for post', async () => { const timestamp = 123456; const packagePath = join( outputDirectory, @@ -172,14 +176,17 @@ describe('MetadataConverter', () => { type: DECOMPOSED_CHILD_COMPONENT_1.type, xml: DECOMPOSED_CHILD_COMPONENT_1.xml, }); - component1.setMarkedForDelete(true); + component1.setMarkedForDelete(DestructiveChangesType.POST); const component2 = new SourceComponent({ name: DECOMPOSED_CHILD_COMPONENT_2.name, type: DECOMPOSED_CHILD_COMPONENT_2.type, xml: DECOMPOSED_CHILD_COMPONENT_2.xml, }); const compSet = new ComponentSet([component1, component2], mockRegistry); - const expectedDestructiveContents = compSet.getPackageXml(undefined, true); + const expectedDestructiveContents = compSet.getPackageXml( + undefined, + DestructiveChangesType.POST + ); const expectedContents = compSet.getPackageXml(); await converter.convert(compSet, 'metadata', { type: 'directory', outputDirectory }); @@ -207,7 +214,7 @@ describe('MetadataConverter', () => { type: DECOMPOSED_CHILD_COMPONENT_1.type, xml: DECOMPOSED_CHILD_COMPONENT_1.xml, }); - component1.setMarkedForDelete(true); + component1.setMarkedForDelete(DestructiveChangesType.PRE); const component2 = new SourceComponent({ name: DECOMPOSED_CHILD_COMPONENT_2.name, type: DECOMPOSED_CHILD_COMPONENT_2.type, @@ -215,7 +222,10 @@ describe('MetadataConverter', () => { }); const compSet = new ComponentSet([component1, component2], mockRegistry); compSet.setDestructiveChangesType(DestructiveChangesType.PRE); - const expectedDestructiveContents = compSet.getPackageXml(undefined, true); + const expectedDestructiveContents = compSet.getPackageXml( + undefined, + DestructiveChangesType.PRE + ); const expectedContents = compSet.getPackageXml(); await converter.convert(compSet, 'metadata', { type: 'directory', outputDirectory }); @@ -367,14 +377,17 @@ describe('MetadataConverter', () => { type: DECOMPOSED_CHILD_COMPONENT_1.type, xml: DECOMPOSED_CHILD_COMPONENT_1.xml, }); - component1.setMarkedForDelete(true); + component1.setMarkedForDelete(); const component2 = new SourceComponent({ name: DECOMPOSED_CHILD_COMPONENT_2.name, type: DECOMPOSED_CHILD_COMPONENT_2.type, xml: DECOMPOSED_CHILD_COMPONENT_2.xml, }); const compSet = new ComponentSet([component1, component2], mockRegistry); - const expectedDestructiveContents = compSet.getPackageXml(undefined, true); + const expectedDestructiveContents = compSet.getPackageXml( + undefined, + DestructiveChangesType.POST + ); const expectedContents = compSet.getPackageXml(); const addToZipStub = env.stub(streams.ZipWriter.prototype, 'addToZip'); @@ -391,13 +404,13 @@ describe('MetadataConverter', () => { ]); }); - it('should write destructive changes pre manifest when ComponentSet has deletes', async () => { + it('should write destructive changes pre manifest when ComponentSet has deletes marked for pre', async () => { const component1 = new SourceComponent({ name: DECOMPOSED_CHILD_COMPONENT_1.name, type: DECOMPOSED_CHILD_COMPONENT_1.type, xml: DECOMPOSED_CHILD_COMPONENT_1.xml, }); - component1.setMarkedForDelete(true); + component1.setMarkedForDelete(DestructiveChangesType.PRE); const component2 = new SourceComponent({ name: DECOMPOSED_CHILD_COMPONENT_2.name, type: DECOMPOSED_CHILD_COMPONENT_2.type, @@ -405,7 +418,7 @@ describe('MetadataConverter', () => { }); const compSet = new ComponentSet([component1, component2], mockRegistry); compSet.setDestructiveChangesType(DestructiveChangesType.PRE); - const expectedDestructiveContents = compSet.getPackageXml(undefined, true); + const expectedDestructiveContents = compSet.getPackageXml(4, DestructiveChangesType.PRE); const expectedContents = compSet.getPackageXml(); const addToZipStub = env.stub(streams.ZipWriter.prototype, 'addToZip'); diff --git a/test/convert/streams.test.ts b/test/convert/streams.test.ts index 6f5b8e3f74..a35c134374 100644 --- a/test/convert/streams.test.ts +++ b/test/convert/streams.test.ts @@ -185,7 +185,7 @@ describe('Streams', () => { type: component.type, xml: component.xml, }); - myComp.setMarkedForDelete(true); + myComp.setMarkedForDelete(); const converter = new streams.ComponentConverter('source', mockRegistry); converter._transform(myComp, '', async (err: Error, data: WriterFormat) => { diff --git a/test/resolve/sourceComponent.test.ts b/test/resolve/sourceComponent.test.ts index 22ac581f03..54a7b87fda 100644 --- a/test/resolve/sourceComponent.test.ts +++ b/test/resolve/sourceComponent.test.ts @@ -4,29 +4,35 @@ * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import { SourceComponent, VirtualTreeContainer } from '../../src/resolve'; +import { + DestructiveChangesType, + MetadataType, + RegistryAccess, + SourceComponent, + VirtualTreeContainer, +} from '../../src'; import { RegistryTestUtil } from './registryTestUtil'; import { - xmlInFolder, decomposed, - mixedContentDirectory, matchingContentFile, - mockRegistryData, + mixedContentDirectory, mockRegistry, + mockRegistryData, + xmlInFolder, } from '../mock/registry'; import { assert, expect } from 'chai'; import { DECOMPOSED_COMPONENT } from '../mock/registry/type-constants/decomposedConstants'; import { COMPONENT } from '../mock/registry/type-constants/matchingContentFileConstants'; import { - COMPONENT_1, CHILD_1_NAME, CHILD_1_XML, VIRTUAL_DIR, COMPONENT_1_XML, COMPONENT_1_XML_PATH, CHILD_2_NAME, - MATCHING_RULES_TYPE, + COMPONENT_1, MATCHING_RULES_COMPONENT_XML_PATH, + MATCHING_RULES_TYPE, TREE, } from '../mock/registry/type-constants/nonDecomposedConstants'; import { createSandbox } from 'sinon'; @@ -34,7 +40,6 @@ import { join } from 'path'; import { DecomposedSourceAdapter } from '../../src/resolve/adapters'; import { TypeInferenceError } from '../../src/errors'; import { nls } from '../../src/i18n'; -import { MetadataType, RegistryAccess } from '../../src'; const env = createSandbox(); @@ -60,14 +65,25 @@ describe('SourceComponent', () => { }); it('should return correct markedForDelete status', () => { - expect(COMPONENT.isMarkedForDelete()).to.be.false; - try { - COMPONENT.setMarkedForDelete(true); - expect(COMPONENT.isMarkedForDelete()).to.be.true; - } finally { - COMPONENT.setMarkedForDelete(false); - expect(COMPONENT.isMarkedForDelete()).to.be.false; - } + const comp = new SourceComponent({ name: 'test', type: undefined }); + expect(comp.isMarkedForDelete()).to.be.false; + expect(comp.getDestructiveChangesType()).to.equal(undefined); + + comp.setMarkedForDelete(); + expect(comp.isMarkedForDelete()).to.be.true; + expect(comp.getDestructiveChangesType()).to.equal(DestructiveChangesType.POST); + + comp.setMarkedForDelete(DestructiveChangesType.PRE); + expect(comp.isMarkedForDelete()).to.be.true; + expect(comp.getDestructiveChangesType()).to.equal(DestructiveChangesType.PRE); + + comp.setMarkedForDelete(false); + expect(comp.isMarkedForDelete()).to.be.false; + expect(comp.getDestructiveChangesType()).to.equal(undefined); + + comp.setMarkedForDelete(true); + expect(comp.isMarkedForDelete()).to.be.true; + expect(comp.getDestructiveChangesType()).to.equal(DestructiveChangesType.POST); }); it('should return correct relative path for a nested component', () => {