Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions build/package.readme
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ sf data query --query "SELECT InstanceName, MetadataPackageId, MetadataPackageVe

## script to update subscribers using a version (or lower) to another version
targetOrg=vincent@orgcheck.com
oldVersion=04tQy000000VPrl
newVersion=04tQy000000VhYX
oldVersion=04tQy000000VhYX
newVersion=04tQy000000Z76f
sf data create record --target-org "${targetOrg}" --sobjecttype=PackagePushRequest "--values=PackageVersionId=${newVersion}" --json > /tmp/out.txt
if [[ $(grep -c 'success": true' /tmp/out.txt) -ne 1 ]]; then
echo 'PackagePushRequest record not created.'
else
id=$(grep 'id": ' /tmp/out.txt | cut -d'"' -f4) ;
csvFile=/tmp/packagePushJob-${id}.csv ;
echo "PackagePushRequestId,SubscriberOrganizationKey" > "${csvFile}" ;
sf data query --query "SELECT OrgKey FROM PackageSubscriber WHERE MetadataPackageVersionId <= '${oldVersion}' " --resultformat=csv | awk 'NR > 1 { print "'${id}'," $1 }' >> "${csvFile}" ;
sf data query --query "SELECT OrgKey FROM PackageSubscriber WHERE MetadataPackageVersionId <= '${oldVersion}' LIMIT 9000 " --resultformat=csv | awk 'NR > 1 { print "'${id}'," $1 }' >> "${csvFile}" ;
sf data upsert bulk --target-org "${targetOrg}" --sobject PackagePushJob --file "${csvFile}" -i Id ;
echo "When bulk job if done, please run the following command:" ;
echo "sf data update record --target-org ${targetOrg} --sobject PackagePushRequest --record-id ${id} \"--values=Status=Pending\"";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -754,21 +754,22 @@ export class SalesforceManager implements SalesforceManagerIntf {
/**
* @see SalesforceManagerIntf.readMetadata
* @param {SalesforceMetadataRequest[]} metadatas - Information of what metadata you want to retrieve
* @param {boolean} expandWildcard - true if you want to expand the wildcard, false otherwise
* @param {SimpleLoggerIntf} logger - Logger
* @returns {Promise<Map<string, any[]>} Information by metadata type
* @throws {SalesforceError} If an error occurs during the metadata read
* @public
* @async
*/
public async readMetadata(metadatas: SalesforceMetadataRequest[], logger: SimpleLoggerIntf): Promise<Map<string, Array<Record<string, unknown>>>> {
public async readMetadata(metadatas: SalesforceMetadataRequest[], expandWildcard: boolean, logger: SimpleLoggerIntf): Promise<Map<string, Array<Record<string, unknown>>>> {
// Let's start to check if we are 'allowed' to use the Salesforce API...
this._watchDog?.beforeRequest(); // if limit has been reached, an error will be thrown here
// Now we can start, log some message
logger?.log(`Starting to call Metadata API for ${metadatas?.length} types...`);
// First, if the metadatas contains an item with member='*' we want to list for this type and substitute the '*' with the fullNames
await LargeProcessor.runAll<void>(
// only get the types that have at least '*' once
metadatas.filter((m) => m.members?.includes('*'))
metadatas.filter((m) => expandWildcard === true && m.members?.includes('*'))
// then turn this filtered list into a list of promises
.map((metadata) => async () => { // using async as we just want to run parallel processes without manipulating their return values
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,14 @@ export interface SalesforceManagerIntf {
/**
* @description Method to retrieve a list of metadata types
* @param {SalesforceMetadataRequest[]} metadatas - Information of what metadata you want to retrieve
* @param {boolean} expandWildcard - true if you want to expand the wildcard, false otherwise
* @param {SimpleLoggerIntf} logger - Logger to use
* @returns {Promise<Map<string, any[]>} Information by metadata type
* @throws {SalesforceError} If an error occurs during the query
* @async
* @public
*/
readMetadata(metadatas: SalesforceMetadataRequest[], logger: SimpleLoggerIntf): Promise<Map<string, Array<Record<string, unknown>>>>;
readMetadata(metadatas: SalesforceMetadataRequest[], expandWildcard: boolean, logger: SimpleLoggerIntf): Promise<Map<string, Array<Record<string, unknown>>>>;

/**
* @description Method to retrieve a list of metadata types by at Scale (using composite tooling api)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ export class DatasetObject implements Dataset {
throw new Error(`DatasetObject: No object were provided in the parameters.`);
}

// split name and namespace frpm object api name
const splittedApiName = fullObjectApiName.split('__');
const packageName = splittedApiName?.length === 3 ? splittedApiName[0] : '';

// Init the factories
const fieldDataFactory = dataFactory.getInstance(DataAliases.SfdcField);
const fieldSetDataFactory = dataFactory.getInstance(DataAliases.SfdcFieldSet);
Expand All @@ -64,20 +60,17 @@ export class DatasetObject implements Dataset {
'(SELECT Id, Name, Url, LinkType, OpenType, Description, CreatedDate, LastModifiedDate, NamespacePrefix FROM WebLinks) ' +
'FROM EntityDefinition ' +
`WHERE QualifiedApiName = '${fullObjectApiName}' ` +
(packageName ? `AND NamespacePrefix = '${packageName}' ` : '') +
'LIMIT 1' // We should get zero or one record, not more!
}, {
tooling: true,
string: 'SELECT DurableId, QualifiedApiName, Description, IsIndexed ' +
'FROM FieldDefinition '+
`WHERE EntityDefinition.QualifiedApiName = '${fullObjectApiName}' ` +
(packageName ? `AND EntityDefinition.NamespacePrefix = '${packageName}' ` : ''),
`WHERE EntityDefinition.QualifiedApiName = '${fullObjectApiName}' `,
queryMoreField: 'DurableId' // FieldDefinition does not support calling QueryMore, use the custom instead
}, {
string: 'SELECT TableEnumOrId, Id ' + // TableEnumOrId = EntityDefinition.QualifiedApiName
'FROM WorkflowRule ' +
`WHERE TableEnumOrId = '${fullObjectApiName}' ` +
(packageName ? `AND EntityDefinition.NamespacePrefix = '${packageName}' ` : ''),
`WHERE TableEnumOrId = '${fullObjectApiName}' `,
tooling: true,
}], logger),
sfdcManager.recordCount(fullObjectApiName, logger)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ export class DatasetProfilePasswordPolicies implements Dataset {

// First Metadata API query
logger?.log(`Querying Metadata API about ProfilePasswordPolicy...`);
const results = await sfdcManager.readMetadata([{
type: 'ProfilePasswordPolicy',
members: [ '*' ]
}], logger);
const results = await sfdcManager.readMetadata([{ type: 'ProfilePasswordPolicy', members: [ '*' ] }], true, logger);

// List of policies
const profilePasswordPolicies = results?.get('ProfilePasswordPolicy') || [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,9 @@ export class DatasetSharingRules implements Dataset {
*/
async run(sfdcManager: SalesforceManagerIntf, dataFactory: DataFactoryIntf, logger: SimpleLoggerIntf): Promise<Map<string, SfdcSharingRule>> {

// List all custom object which can have a sharing model
logger?.log(`Listing all custom objects that can have a sharing model...`);
const customObjectsResults = await sfdcManager.soqlQuery([{
tooling: true,
string: 'SELECT NamespacePrefix, DeveloperName ' +
'FROM CustomObject ' +
`WHERE SharingModel != ''`
}], logger);
const customObjectNames: Record<string, unknown>[] = customObjectsResults[0];

// Read all SharingRules metadata
logger?.log(`Reading sharing rules metadata via Metadata API...`);
const results = await sfdcManager.readMetadata([{
type: SalesforceMetadataTypes.SHARING_RULE,
members: ['*', ...(customObjectNames?.map((r) => `${r.NamespacePrefix ? `${r.NamespacePrefix}__`: ''}${r.DeveloperName}__c`) ?? [])]
}], logger);
const results = await sfdcManager.readMetadata([{ type: SalesforceMetadataTypes.SHARING_RULE, members: ['*'] }], true, logger);

// Init the factory and records
const sharingRuleDataFactory = dataFactory.getInstance(DataAliases.SfdcSharingRule);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ describe('tests.api.unit.SalesforceManager', () => {

describe('metadataApi use cases', () => {
it('checks if the salesforce manager implementation runs readMetadata correctly with explicit members', async () => {
const results = await manager.readMetadata([{ type: 'ProfilePasswordPolicy #Members=4#', members: [ 'member0', 'member999' ] }], simpleLogger);
const results = await manager.readMetadata([{ type: 'ProfilePasswordPolicy #Members=4#', members: [ 'member0', 'member999' ] }], false,simpleLogger);
expect(results).toBeDefined();
expect(results instanceof Map).toBeTruthy();
expect(results.size).toBe(1);
Expand All @@ -130,14 +130,24 @@ describe('tests.api.unit.SalesforceManager', () => {
expect(policies?.length).toBe(1); // member0 exists, but member999 does not
});

it('checks if the salesforce manager implementation runs readMetadata correctly with star (*)', async () => {
const results = await manager.readMetadata([{ type: 'ProfilePasswordPolicy #Members=4#', members: [ '*' ] }], simpleLogger);
it('checks if the salesforce manager implementation runs readMetadata correctly with star (*) with expandWildcard=true', async () => {
const results = await manager.readMetadata([{ type: 'ProfilePasswordPolicy #Members=4#', members: [ '*' ] }], true, simpleLogger);
expect(results).toBeDefined();
expect(results instanceof Map).toBeTruthy();
expect(results.size).toBe(1);
const policies: any[] | undefined = results.get('ProfilePasswordPolicy #Members=4#');
expect(policies instanceof Array).toBeTruthy();
expect(policies?.length).toBe(4); // you put '*' !
expect(policies?.length).toBe(4); // you put '*' with 4 members expected when expanding wildcards
});

it('checks if the salesforce manager implementation runs readMetadata correctly with star (*) with expandWildcard=false', async () => {
const results = await manager.readMetadata([{ type: 'ProfilePasswordPolicy #Members=4#', members: [ '*' ] }], false, simpleLogger);
expect(results).toBeDefined();
expect(results instanceof Map).toBeTruthy();
expect(results.size).toBe(1);
const policies: any[] | undefined = results.get('ProfilePasswordPolicy #Members=4#');
expect(policies instanceof Array).toBeTruthy();
expect(policies?.length).toBe(0); // you put '*' with 4 members expected when expanding wildcards, but expandWildcard=false, so we should have zero!
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class SalesforceManagerMock_DoingNothing implements SalesforceManagerIntf
async soqlQuery(_queries: SalesforceQueryRequest | any[], _logger: SimpleLoggerIntf): Promise<Array<Array<any>>> { return [[]]; }
async soslQuery(_queries: SalesforceQueryRequest | any[], _logger: SimpleLoggerIntf): Promise<Array<Array<any>>> { return [[]]; }
async dependenciesQuery(_ids: string[], _logger: SimpleLoggerIntf): Promise<{ records: Array<any>; errors: Array<string>; }> { return { records: [], errors: [] }; }
async readMetadata(_metadatas: SalesforceMetadataRequest[], _logger: SimpleLoggerIntf): Promise<Map<string, Array<any>>> { return new Map(); }
async readMetadata(_metadatas: SalesforceMetadataRequest[], _expandWildcard: boolean, _logger: SimpleLoggerIntf): Promise<Map<string, Array<any>>> { return new Map(); }
async readMetadataAtScale(_type: string, _ids: any[], _byPasses: string[], _logger: SimpleLoggerIntf): Promise<any[]> { return []; }
async describeGlobal(_logger: SimpleLoggerIntf): Promise<any[]> { return []; }
async describe(_sobjectDevName: string, _logger: SimpleLoggerIntf): Promise<any> { return {}; }
Expand Down
7 changes: 4 additions & 3 deletions packages/orgcheck-salesforce-app/sfdx-project.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"default": false,
"package": "Org Check",
"versionName": "Oxygen",
"versionNumber": "8.8.0.NEXT",
"versionNumber": "8.9.0.NEXT",
"versionDescription": "Org Check is an easy-to-install and easy-to-use Salesforce application in order to quickly analyze your org and its technical debt.",
"ancestorVersion": "HIGHEST"
},
Expand All @@ -14,7 +14,7 @@
"default": true,
"package": "Org Check (unlocked)",
"versionName": "Oxygen",
"versionNumber": "8.8.0.NEXT",
"versionNumber": "8.9.0.NEXT",
"versionDescription": "Org Check is an easy-to-install and easy-to-use Salesforce application in order to quickly analyze your org and its technical debt."
}
],
Expand All @@ -32,6 +32,7 @@
"Org Check (unlocked)@8.3.0-1": "04tKB000000DdYGYA0",
"Org Check (unlocked)@8.6.0-1": "04tKB000000De1KYAS",
"Org Check (unlocked)@8.7.0-1": "04tKB000000DeYWYA0",
"Org Check (unlocked)@8.8.0-1": "04tQy000000Z753IAC"
"Org Check (unlocked)@8.8.0-1": "04tQy000000Z753IAC",
"Org Check (unlocked)@8.9.0-1": "04tQy000000ZEEbIAO"
}
}
Loading