Skip to content

Commit

Permalink
fix: metadata folder types get packaged incorrectly
Browse files Browse the repository at this point in the history
  • Loading branch information
Codeneos committed Jan 22, 2024
1 parent b720da4 commit e2ac4f6
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ describe('SalesforcePackageBuilder', () => {
'src/destructiveChangesPre.xml': buildXml('Package', { types: [ { name: 'ApexClass', members: [ 'c', 'd' ] } ] }),
'src/destructiveChanges.xml': buildXml('Package', { types: [ { name: 'ApexClass', members: [ 'g', 'h' ] } ] }),
'src/destructiveChangesSingle.xml': buildXml('Package', { types: [ { name: 'ApexClass', members: 'a' } ] }),
// Dashboards
'src/dashboards/MyFolder.dashboardFolder-meta.xml': buildXml('DashboardFolder', { name: 'MyFolder', accessType: 'Public', publicFolderAccess: 'ReadWrite' }),
'src/dashboards/MyFolder/Board.dashboard-meta.xml': buildXml('Dashboard', { name: 'Board' }),
});

beforeAll(() => container.registerAs(Logger.null, Logger));
Expand Down Expand Up @@ -473,14 +476,29 @@ describe('SalesforcePackageBuilder', () => {
'src/classes/myClass.cls-meta.xml',
'src/triggers/myTrigger.trigger-meta.xml',
]));
expect(manifest.list().length).toEqual(7);
expect(manifest.list().length).toEqual(9);
expect(manifest.list('AuraDefinitionBundle').length).toEqual(1);
expect(manifest.list('LightningComponentBundle').length).toEqual(1);
expect(manifest.list('ApexClass').length).toEqual(1);
expect(manifest.list('ApexTrigger').length).toEqual(1);
expect(manifest.list('CustomObject').length).toEqual(1);
expect(manifest.list('CustomField').length).toEqual(1);
expect(manifest.list('ListView').length).toEqual(1);
expect(manifest.list('Dashboard').length).toEqual(2);
});
});
describe('#dashboards', () => {
it('should add dashboards folders with -meta.xml suffix', async () => {
const packageBuilder = new SalesforcePackageBuilder(SalesforcePackageType.deploy, apiVersion, mockFs);
await packageBuilder.addFiles([ 'src/dashboards' ]);

const manifest = packageBuilder.getManifest();
const [ folder, dashBoard ] = [...packageBuilder.getPackage().sourceFiles()];

expect(folder.packagePath).toEqual('dashboards/MyFolder-meta.xml');
expect(dashBoard.packagePath).toEqual('dashboards/MyFolder/Board.dashboard');
expect(manifest.list().length).toEqual(2);
expect(manifest.list('Dashboard').length).toEqual(2);
});
});
});
Expand Down
53 changes: 36 additions & 17 deletions packages/salesforce/src/deploymentPackageBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import chalk from 'chalk';
import ZipArchive from 'jszip';

import { Logger, injectable , LifecyclePolicy, CachedFileSystemAdapter , FileSystem, Container } from '@vlocode/core';
import { cache, substringAfterLast , Iterable, XML, CancellationToken, FileSystemUri } from '@vlocode/util';
import { cache, substringAfterLast , Iterable, XML, CancellationToken, FileSystemUri, endsWith, substringBeforeLast, stringEqualsIgnoreCase, stringEquals } from '@vlocode/util';

import { PackageManifest } from './deploy/packageXml';
import { SalesforcePackage, SalesforcePackageComponent } from './deploymentPackage';
Expand Down Expand Up @@ -88,9 +88,14 @@ export class SalesforcePackageBuilder {

// get metadata type
const xmlName = await this.getComponentType(file);
if (xmlName == 'Package' && path.basename(file).includes('destructive')) {
const destructiveChangeType = file.toLocaleLowerCase().includes('post') ? 'post' : 'pre';
this.mdPackage.mergeDestructiveChanges(await this.fs.readFile(file), destructiveChangeType);
if (xmlName == 'Package') {
const lowercasePath = file.toLocaleLowerCase();
if (!path.basename(lowercasePath).includes('destructive')) {
this.logger.warn(`${file} is a Package manifest which is not supported by the package builder`);
} else {
const destructiveChangeType = lowercasePath.includes('post') ? 'post' : 'pre';
this.mdPackage.mergeDestructiveChanges(await this.fs.readFile(file), destructiveChangeType);
}
continue;
}

Expand All @@ -104,13 +109,14 @@ export class SalesforcePackageBuilder {
continue;
}

if (metadataType.name != xmlName) {
const isFolderMetadata = stringEquals(metadataType.folderType, xmlName, { caseInsensitive: true });
if (metadataType.name != xmlName && !isFolderMetadata) {
// Support for SFDX formatted source code
childMetadataFiles.push([ file, xmlName, metadataType]);
continue;
}

if (metadataType.id == 'staticresource' && file.endsWith('-meta.xml')) {
if (metadataType.id === 'staticresource' && file.endsWith('-meta.xml')) {
const folder = this.stripFileExtension(file, 2);
const isFolder = await this.fs.isDirectory(folder);
if (isFolder) {
Expand Down Expand Up @@ -236,12 +242,14 @@ export class SalesforcePackageBuilder {
componentName = this.getPackageComponentName(file, metadataType);
}

const componentType = await this.getPackageComponentType(file, metadataType);

if (this.type === SalesforcePackageType.destruct) {
this.mdPackage.addDestructiveChange(metadataType.name, componentName);
this.mdPackage.addDestructiveChange(componentType, componentName);
} else {
const packagePath = await this.getPackagePath(file, metadataType);
this.mdPackage.add({
componentType: metadataType.name,
componentType,
componentName,
packagePath,
data: await this.fs.readFile(file),
Expand Down Expand Up @@ -523,7 +531,7 @@ export class SalesforcePackageBuilder {
return suffix?.toLowerCase() != 'xml' ? suffix : undefined;
}

private async getComponentTypeFromSource(file: string) {
private async getComponentTypeFromSource(file: string) : Promise<string| undefined>{
const isMetaFile = file.endsWith('-meta.xml');

if (!isMetaFile) {
Expand All @@ -535,20 +543,19 @@ export class SalesforcePackageBuilder {
}

const metadataTypes = this.metadataRegistry.getMetadataTypes();
let xmlName = await this.getRootElementName(file);
const xmlName = await this.getRootElementName(file);

// Cannot detect certain metadata types properly so instead manually set the type
if (xmlName == 'EmailFolder') {
xmlName = 'EmailTemplate';
} else if (xmlName && xmlName.endsWith('Folder')) {
// Handles document Folder and other folder cases
xmlName = xmlName.substr(0, xmlName.length - 6);
} else if (xmlName == 'Package') {
if (xmlName == 'Package') {
// Package are considered valid types for destructive changes
return xmlName;
}

const metadataType = xmlName && metadataTypes.find(type => type.name == xmlName || type.childXmlNames?.includes(xmlName!));
const metadataType = xmlName ? metadataTypes.find(type =>
type.name == xmlName ||
type.childXmlNames?.includes(xmlName!)
) : undefined

if (metadataType) {
return xmlName;
}
Expand Down Expand Up @@ -614,6 +621,11 @@ export class SalesforcePackageBuilder {
const packageFolder = this.getPackageFolder(file, metadataType);
const expectedSuffix = isMetaFile ? `${metadataType.suffix}-meta.xml` : `${metadataType.suffix}`;

if (metadataType.folderContentType) {
// For folder metadata the meta file name should match the folder name
return path.posix.join(packageFolder, `${substringBeforeLast(contentName,'.')}-meta.xml`);
}

if (isMetaFile && !metadataType.hasContent && !metadataType.isBundle) {
// SFDX adds a '-meta.xml' to each file, when deploying we need to strip these
// when the source does not have a meta data file
Expand All @@ -636,6 +648,13 @@ export class SalesforcePackageBuilder {
return path.posix.join(packageFolder, baseName);
}

private async getPackageComponentType(file: string, metadataType: MetadataType) {
if (metadataType.folderContentType) {
return this.metadataRegistry.getMetadataType(metadataType.folderContentType)!.name;
}
return metadataType.name;
}

@cache({ unwrapPromise: true })
private async findContentFile(metaFile: string) {
const metaFileSuggestedContentFile = metaFile.slice(0, -9);
Expand Down
19 changes: 11 additions & 8 deletions packages/util/src/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getObjectProperty } from './object';
* @param b String b
* @param caseInsensitive Wether or not to do a case insensitive or case-sensitive comparison
*/
export function stringEquals(a : string | undefined | null, b: string | undefined | null, caseInsensitive: boolean = true) : boolean {
export function stringEquals(a : string | undefined | null, b: string | undefined | null, options?: { caseInsensitive: boolean } | boolean) : boolean {
if (a === b) {
return true;
}
Expand All @@ -17,7 +17,7 @@ export function stringEquals(a : string | undefined | null, b: string | undefine
if (b === null || b === undefined) {
return false;
}
if (caseInsensitive) {
if (options === undefined || options === true || (options && options.caseInsensitive)) {
return b.toLowerCase() === a.toLowerCase();
}
return false;
Expand Down Expand Up @@ -45,22 +45,25 @@ export function stringEqualsIgnoreCase(a : string | undefined | null, b: string
}

/**
* Determines if the string spcified ends with the other string, caseInsensitive by default
* Checks if the specified string {@link a} ends with the specified string {@link based}.
* By default the comparison is case sensitive unless specified otherwise by setting the `caseInsensitive` option to `true`.
* If either string is null or undefined returns `false`.
* @param a String a
* @param b String b
* @param caseInsensitive Wether or not to do a case insensitive or case-sensitive comparison
* @param options Options
* @param options.caseInsensitive Wether or not to do a case insensitive or case-sensitive comparison
*/
export function endsWith(a : string | undefined | null, b: string | undefined | null, caseInsensitive: boolean = true) : boolean {
export function endsWith(a: string | undefined | null, b: string | undefined | null, options?: { caseInsensitive: boolean }): boolean {
if (a === null || a === undefined) {
return false;
}
if (b === null || b === undefined) {
return false;
}
if (caseInsensitive) {
return b.toLowerCase().endsWith(a.toLowerCase());
if (options?.caseInsensitive) {
return a.toLowerCase().endsWith(b.toLowerCase());
}
return b.endsWith(a);
return a.endsWith(b);
}

export function format(formatStr: string, ...args: any[]) {
Expand Down

0 comments on commit e2ac4f6

Please sign in to comment.