Skip to content

Commit e292796

Browse files
chore: build CS from source/org/metadata
1 parent 1572a8c commit e292796

File tree

3 files changed

+98
-57
lines changed

3 files changed

+98
-57
lines changed

src/collections/componentSetBuilder.ts

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { SourceComponent } from '../resolve/sourceComponent';
1414
import { ComponentSet } from '../collections/componentSet';
1515
import { RegistryAccess } from '../registry/registryAccess';
1616
import type { FileProperties } from '../client/types';
17-
import { MetadataType } from '../registry/types';
17+
import type { MetadataType } from '../registry/types';
1818
import { MetadataResolver } from '../resolve';
1919
import { DestructiveChangesType, FromConnectionOptions } from './types';
2020

@@ -91,15 +91,15 @@ export class ComponentSetBuilder {
9191
*/
9292

9393
public static async build(options: ComponentSetOptions): Promise<ComponentSet> {
94-
let componentSet: ComponentSet | undefined;
95-
9694
const { sourcepath, manifest, metadata, packagenames, org } = options;
9795
const registry = new RegistryAccess(undefined, options.projectDir);
96+
let componentSetToReturn = new ComponentSet(undefined, registry);
9897

9998
if (sourcepath) {
10099
getLogger().debug(`Building ComponentSet from sourcepath: ${sourcepath.join(', ')}`);
101100
const fsPaths = sourcepath.map(validateAndResolvePath);
102-
componentSet = ComponentSet.fromSource({
101+
// first possible option, so we can just set it, next CSB options, must add to this componentSet
102+
componentSetToReturn = ComponentSet.fromSource({
103103
fsPaths,
104104
registry,
105105
});
@@ -108,38 +108,20 @@ export class ComponentSetBuilder {
108108
// Return empty ComponentSet and use packageNames in the connection via `.retrieve` options
109109
if (packagenames) {
110110
getLogger().debug(`Building ComponentSet for packagenames: ${packagenames.toString()}`);
111-
componentSet ??= new ComponentSet(undefined, registry);
112111
}
113112

114-
// Resolve manifest with source in package directories.
115-
if (manifest) {
116-
getLogger().debug(`Building ComponentSet from manifest: ${manifest.manifestPath}`);
117-
assertFileExists(manifest.manifestPath);
118-
119-
getLogger().debug(`Searching in packageDir: ${manifest.directoryPaths.join(', ')} for matching metadata`);
120-
componentSet = await ComponentSet.fromManifest({
121-
manifestPath: manifest.manifestPath,
122-
resolveSourcePaths: manifest.directoryPaths,
123-
forceAddWildcards: true,
124-
destructivePre: manifest.destructiveChangesPre,
125-
destructivePost: manifest.destructiveChangesPost,
126-
registry,
127-
});
128-
}
129-
130-
// Resolve metadata entries with source in package directories, unless we are building a ComponentSet
131-
// from metadata in an org.
132-
if (metadata && !org) {
113+
// Resolve metadata entries with source in package directories
114+
if (metadata) {
133115
getLogger().debug(`Building ComponentSet from metadata: ${metadata.metadataEntries.toString()}`);
134116
const directoryPaths = metadata.directoryPaths;
135-
componentSet ??= new ComponentSet(undefined, registry);
136117
const componentSetFilter = new ComponentSet(undefined, registry);
137118

138119
// Build a Set of metadata entries
139120
metadata.metadataEntries
121+
.filter(filterPsuedoTypes)
140122
.map(entryToTypeAndName(registry))
141123
.flatMap(typeAndNameToMetadataComponents({ directoryPaths, registry }))
142-
.map(addToComponentSet(componentSet))
124+
.map(addToComponentSet(componentSetToReturn))
143125
.map(addToComponentSet(componentSetFilter));
144126

145127
getLogger().debug(`Searching for matching metadata in directories: ${directoryPaths.join(', ')}`);
@@ -148,19 +130,21 @@ export class ComponentSetBuilder {
148130
// are resolved to SourceComponents
149131
if (metadata.destructiveEntriesPre) {
150132
metadata.destructiveEntriesPre
133+
.filter(filterPsuedoTypes)
151134
.map(entryToTypeAndName(registry))
152135
.map(assertNoWildcardInDestructiveEntries)
153136
.flatMap(typeAndNameToMetadataComponents({ directoryPaths, registry }))
154137
.map((mdComponent) => new SourceComponent({ type: mdComponent.type, name: mdComponent.fullName }))
155-
.map(addToComponentSet(componentSet, DestructiveChangesType.PRE));
138+
.map(addToComponentSet(componentSetToReturn, DestructiveChangesType.PRE));
156139
}
157140
if (metadata.destructiveEntriesPost) {
158141
metadata.destructiveEntriesPost
142+
.filter(filterPsuedoTypes)
159143
.map(entryToTypeAndName(registry))
160144
.map(assertNoWildcardInDestructiveEntries)
161145
.flatMap(typeAndNameToMetadataComponents({ directoryPaths, registry }))
162146
.map((mdComponent) => new SourceComponent({ type: mdComponent.type, name: mdComponent.fullName }))
163-
.map(addToComponentSet(componentSet, DestructiveChangesType.POST));
147+
.map(addToComponentSet(componentSetToReturn, DestructiveChangesType.POST));
164148
}
165149

166150
const resolvedComponents = ComponentSet.fromSource({
@@ -169,39 +153,56 @@ export class ComponentSetBuilder {
169153
registry,
170154
});
171155

172-
if (resolvedComponents.forceIgnoredPaths) {
156+
if (resolvedComponents?.forceIgnoredPaths) {
173157
// if useFsForceIgnore = true, then we won't be able to resolve a forceignored path,
174158
// which we need to do to get the ignored source component
175159
const resolver = new MetadataResolver(registry, undefined, false);
176160

177161
for (const ignoredPath of resolvedComponents.forceIgnoredPaths ?? []) {
178162
resolver.getComponentsFromPath(ignoredPath).map((ignored) => {
179-
componentSet = componentSet?.filter(
163+
componentSetToReturn = componentSetToReturn?.filter(
180164
(resolved) => !(resolved.fullName === ignored.name && resolved.type === ignored.type)
181165
);
182166
});
183167
}
184-
componentSet.forceIgnoredPaths = resolvedComponents.forceIgnoredPaths;
168+
componentSetToReturn.forceIgnoredPaths = resolvedComponents.forceIgnoredPaths;
185169
}
186170

187-
resolvedComponents.toArray().map(addToComponentSet(componentSet));
171+
resolvedComponents?.toArray().map(addToComponentSet(componentSetToReturn));
188172
}
189173

190174
// Resolve metadata entries with an org connection
191175
if (org) {
192-
componentSet ??= new ComponentSet(undefined, registry);
193176
const orgComponentSet = await this.resolveOrgComponents(registry, options);
194-
orgComponentSet.toArray().map(addToComponentSet(componentSet));
177+
orgComponentSet.toArray().map(addToComponentSet(componentSetToReturn));
178+
}
179+
180+
// Resolve manifest with source in package directories.
181+
// build from the manifest last, because if this value is passed with other ones, it will override the componentSetToReturn CS
182+
if (manifest) {
183+
getLogger().debug(`Building ComponentSet from manifest: ${manifest.manifestPath}`);
184+
assertFileExists(manifest.manifestPath);
185+
186+
getLogger().debug(`Searching in packageDir: ${manifest.directoryPaths.join(', ')} for matching metadata`);
187+
// set here (using =) because generating a CS by using manifest + other options, is not supported
188+
componentSetToReturn = await ComponentSet.fromManifest({
189+
manifestPath: manifest.manifestPath,
190+
resolveSourcePaths: manifest.directoryPaths,
191+
forceAddWildcards: true,
192+
destructivePre: manifest.destructiveChangesPre,
193+
destructivePost: manifest.destructiveChangesPost,
194+
registry,
195+
});
195196
}
196197

197198
// there should have been a componentSet created by this point.
198-
componentSet = assertComponentSetIsNotUndefined(componentSet);
199-
componentSet.apiVersion ??= options.apiversion;
200-
componentSet.sourceApiVersion ??= options.sourceapiversion;
201-
componentSet.projectDirectory = options.projectDir;
199+
componentSetToReturn = assertComponentSetIsNotUndefined(componentSetToReturn);
200+
componentSetToReturn.apiVersion ??= options.apiversion;
201+
componentSetToReturn.sourceApiVersion ??= options.sourceapiversion;
202+
componentSetToReturn.projectDirectory = options.projectDir;
202203

203-
logComponents(componentSet);
204-
return componentSet;
204+
logComponents(componentSetToReturn);
205+
return componentSetToReturn;
205206
}
206207

207208
private static async resolveOrgComponents(
@@ -331,6 +332,13 @@ export const entryToTypeAndName =
331332
return { type, metadataName: name.length ? name.join(':').trim() : '*' };
332333
};
333334

335+
const filterPsuedoTypes = (value: string): boolean => {
336+
const [typeName] = value.split(':');
337+
return !Object.values(PSEUDO_TYPES)
338+
.map((p) => p.toLowerCase())
339+
.includes(typeName.toLowerCase());
340+
};
341+
334342
const typeAndNameToMetadataComponents =
335343
(context: { directoryPaths: ManifestOption['directoryPaths']; registry: RegistryAccess }) =>
336344
({ type, metadataName }: MetadataTypeAndMetadataName): MetadataComponent[] =>

test/collections/componentSet.test.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import {
3434
import { decomposedtoplevel, digitalExperienceBundle, matchingContentFile, mixedContentSingleFile } from '../mock';
3535
import { MATCHING_RULES_COMPONENT } from '../mock/type-constants/customlabelsConstant';
3636
import * as manifestFiles from '../mock/manifestConstants';
37-
import { testApiVersion, testApiVersionAsString } from '../mock/manifestConstants';
3837
import * as coverage from '../../src/registry/coverage';
3938

4039
const registryAccess = new RegistryAccess();
@@ -436,7 +435,7 @@ describe('ComponentSet', () => {
436435
];
437436
const resolveStub = $$.SANDBOX.stub(ManifestResolver.prototype, 'resolve').resolves({
438437
components: expected,
439-
apiVersion: testApiVersionAsString,
438+
apiVersion: manifestFiles.testApiVersionAsString,
440439
});
441440
$$.SANDBOX.stub(RegistryAccess.prototype, 'getTypeByName').returns(registry.types.apexclass);
442441
const manifest = manifestFiles.ONE_FOLDER_MEMBER;
@@ -581,7 +580,7 @@ describe('ComponentSet', () => {
581580
];
582581
const resolveStub = $$.SANDBOX.stub(ConnectionResolver.prototype, 'resolve').resolves({
583582
components: expected,
584-
apiVersion: testApiVersionAsString,
583+
apiVersion: manifestFiles.testApiVersionAsString,
585584
});
586585
$$.SANDBOX.stub(RegistryAccess.prototype, 'getTypeByName').returns(registry.types.apexclass);
587586
const set = await ComponentSet.fromConnection({ usernameOrConnection: connection });
@@ -684,7 +683,9 @@ describe('ComponentSet', () => {
684683
let getCurrentApiVersionStub: SinonStub;
685684

686685
beforeEach(() => {
687-
getCurrentApiVersionStub = $$.SANDBOX.stub(coverage, 'getCurrentApiVersion').resolves(testApiVersion);
686+
getCurrentApiVersionStub = $$.SANDBOX.stub(coverage, 'getCurrentApiVersion').resolves(
687+
manifestFiles.testApiVersion
688+
);
688689
});
689690

690691
afterEach(() => {
@@ -712,7 +713,7 @@ describe('ComponentSet', () => {
712713
members: ['b', 'c'],
713714
},
714715
],
715-
version: testApiVersionAsString,
716+
version: manifestFiles.testApiVersionAsString,
716717
},
717718
});
718719
expect(getCurrentApiVersionStub.calledOnce).to.be.true;
@@ -725,7 +726,7 @@ describe('ComponentSet', () => {
725726
registry: registryAccess,
726727
tree: manifestFiles.TREE,
727728
});
728-
set.apiVersion = testApiVersionAsString;
729+
set.apiVersion = manifestFiles.testApiVersionAsString;
729730
expect(await set.getObject()).to.deep.equal({
730731
Package: {
731732
types: [
@@ -738,7 +739,7 @@ describe('ComponentSet', () => {
738739
members: ['b', 'c'],
739740
},
740741
],
741-
version: testApiVersionAsString,
742+
version: manifestFiles.testApiVersionAsString,
742743
},
743744
});
744745
expect(resolveSpy.called).to.be.false;
@@ -778,7 +779,7 @@ describe('ComponentSet', () => {
778779
registry: registryAccess,
779780
tree: manifestFiles.TREE,
780781
});
781-
process.env.SF_ORG_API_VERSION = testApiVersionAsString;
782+
process.env.SF_ORG_API_VERSION = manifestFiles.testApiVersionAsString;
782783
expect(await set.getObject()).to.deep.equal({
783784
Package: {
784785
types: [
@@ -791,7 +792,7 @@ describe('ComponentSet', () => {
791792
members: ['b', 'c'],
792793
},
793794
],
794-
version: testApiVersionAsString,
795+
version: manifestFiles.testApiVersionAsString,
795796
},
796797
});
797798
expect(getCurrentApiVersionStub.called).to.be.false;
@@ -843,7 +844,7 @@ describe('ComponentSet', () => {
843844
members: ['b', 'c'],
844845
},
845846
],
846-
version: testApiVersionAsString,
847+
version: manifestFiles.testApiVersionAsString,
847848
},
848849
});
849850
});
@@ -868,7 +869,7 @@ describe('ComponentSet', () => {
868869
members: ['b', 'c'],
869870
},
870871
],
871-
version: testApiVersionAsString,
872+
version: manifestFiles.testApiVersionAsString,
872873
},
873874
});
874875
});
@@ -1003,7 +1004,7 @@ describe('ComponentSet', () => {
10031004

10041005
describe('getPackageXml', () => {
10051006
beforeEach(() => {
1006-
$$.SANDBOX.stub(coverage, 'getCurrentApiVersion').resolves(testApiVersion);
1007+
$$.SANDBOX.stub(coverage, 'getCurrentApiVersion').resolves(manifestFiles.testApiVersion);
10071008
});
10081009
it('should return manifest string when initialized from manifest file', async () => {
10091010
const manifest = manifestFiles.ONE_OF_EACH;

test/collections/componentSetBuilder.test.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ import { assert, expect, config } from 'chai';
1313
import { Connection, SfError } from '@salesforce/core';
1414
import { instantiateContext, MockTestOrgData, restoreContext, stubContext } from '@salesforce/core/testSetup';
1515
import { RegistryAccess } from '../../src/registry/registryAccess';
16-
import { ComponentSetBuilder, entryToTypeAndName } from '../../src/collections/componentSetBuilder';
16+
import {
17+
ComponentSetBuilder,
18+
ComponentSetOptions,
19+
entryToTypeAndName,
20+
} from '../../src/collections/componentSetBuilder';
1721
import { ComponentSet } from '../../src/collections/componentSet';
18-
import { FromSourceOptions } from '../../src/collections/types';
22+
import type { FromSourceOptions } from '../../src/collections/types';
1923
import { MetadataResolver, SourceComponent } from '../../src';
2024

2125
config.truncateThreshold = 0;
@@ -491,6 +495,34 @@ describe('ComponentSetBuilder', () => {
491495
restoreContext($$);
492496
});
493497

498+
it('should create a CS from every option possible', async () => {
499+
fileExistsSyncStub.returns(true);
500+
fromSourceStub.returns(new ComponentSet([customObjectComponent]));
501+
fromManifestStub.resolves(new ComponentSet([apexClassWildcardMatch]));
502+
fromConnectionStub.resolves(new ComponentSet([apexClassWildcardNoMatch]));
503+
504+
const packageDir1 = path.resolve('force-app');
505+
const sourcepath = ['force-app', 'my-app'];
506+
507+
const options: ComponentSetOptions = {
508+
sourcepath,
509+
org: {
510+
username: testOrg.username,
511+
exclude: [],
512+
},
513+
metadata: { directoryPaths: [packageDir1], metadataEntries: ['ApexClass:MyClass'] },
514+
};
515+
516+
const compSet = await ComponentSetBuilder.build(options);
517+
expect(fromSourceStub.callCount).to.equal(2);
518+
expect(fromConnectionStub.callCount).to.equal(1);
519+
520+
expect(compSet.size).to.equal(3);
521+
expect(compSet.has(apexClassComponent)).to.equal(true);
522+
expect(compSet.has(customObjectComponent)).to.equal(true);
523+
expect(compSet.has(apexClassWildcardNoMatch)).to.equal(true);
524+
});
525+
494526
it('should create ComponentSet from org connection', async () => {
495527
componentSet.add(apexClassComponent);
496528
fromConnectionStub.resolves(componentSet);
@@ -538,10 +570,10 @@ describe('ComponentSetBuilder', () => {
538570
};
539571

540572
const compSet = await ComponentSetBuilder.build(options);
541-
expect(fromSourceStub.callCount).to.equal(0);
573+
expect(fromSourceStub.callCount).to.equal(2);
542574
expect(fromConnectionStub.callCount).to.equal(1);
543-
expect(compSet.size).to.equal(1);
544-
expect(compSet.has(apexClassComponent)).to.equal(false);
575+
expect(compSet.size).to.equal(2);
576+
expect(compSet.has(apexClassComponent)).to.equal(true);
545577
expect(compSet.has(apexClassWildcardMatch)).to.equal(true);
546578
});
547579

0 commit comments

Comments
 (0)