Skip to content

Commit 3dc275c

Browse files
committed
fix: always ask at least once for sourceMembers
1 parent 445a071 commit 3dc275c

File tree

2 files changed

+38
-27
lines changed

2 files changed

+38
-27
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"@salesforce/core": "^4.3.11",
5050
"@salesforce/kit": "^3.0.6",
5151
"@salesforce/source-deploy-retrieve": "^9.4.2",
52+
"@salesforce/ts-types": "^2.0.5",
5253
"fast-xml-parser": "^4.2.5",
5354
"graceful-fs": "^4.2.11",
5455
"isomorphic-git": "1.23.0",

src/shared/remoteSourceTrackingService.ts

+37-27
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as path from 'path';
99
import * as fs from 'fs';
1010
import { retryDecorator, NotRetryableError } from 'ts-retry-promise';
1111
import { ConfigFile, Logger, Org, Messages, Lifecycle, SfError } from '@salesforce/core';
12-
import { Dictionary, Optional } from '@salesforce/ts-types';
12+
import { Dictionary, Optional, definiteEntriesOf } from '@salesforce/ts-types';
1313
import { env, Duration } from '@salesforce/kit';
1414
import { ChangeResult, RemoteChangeElement, MemberRevision, SourceMember, RemoteSyncInput } from './types';
1515
import { getMetadataKeyFromFileResponse, mappingsForSourceMemberTypesToMetadataType } from './metadataKeys';
@@ -124,13 +124,7 @@ export class RemoteSourceTrackingService extends ConfigFile<RemoteSourceTracking
124124
}
125125
return path.isAbsolute(fileToDelete) ? fileToDelete : path.join(process.cwd(), fileToDelete);
126126
}
127-
private static convertRevisionToChange(memberKey: string, memberRevision: MemberRevision): RemoteChangeElement {
128-
return {
129-
type: memberRevision.memberType,
130-
name: memberKey.replace(`${memberRevision.memberType}__`, ''),
131-
deleted: memberRevision.isNameObsolete,
132-
};
133-
}
127+
134128
/**
135129
* Initializes the service with existing remote source tracking data, or sets
136130
* the state to begin source tracking of metadata changes in the org.
@@ -225,7 +219,7 @@ export class RemoteSourceTrackingService extends ConfigFile<RemoteSourceTracking
225219
public getTrackedElement(key: string): RemoteChangeElement | undefined {
226220
const memberRevision = this.getSourceMembers()[key];
227221
if (memberRevision) {
228-
return RemoteSourceTrackingService.convertRevisionToChange(key, memberRevision);
222+
return convertRevisionToChange(key, memberRevision);
229223
}
230224
}
231225

@@ -337,21 +331,15 @@ export class RemoteSourceTrackingService extends ConfigFile<RemoteSourceTracking
337331

338332
// Look for any changed that haven't been synced. I.e, the lastRetrievedFromServer
339333
// does not match the serverRevisionCounter.
340-
const trackedRevisions = this.getSourceMembers();
341-
const returnElements: RemoteChangeElement[] = [];
342-
343-
for (const key of Object.keys(trackedRevisions)) {
344-
const member = trackedRevisions[key];
345-
if (member && member.serverRevisionCounter !== member.lastRetrievedFromServer) {
346-
returnElements.push(RemoteSourceTrackingService.convertRevisionToChange(key, member));
347-
}
348-
}
334+
const returnElements = definiteEntriesOf(this.getSourceMembers())
335+
.filter(([, member]) => member.serverRevisionCounter !== member.lastRetrievedFromServer)
336+
.map(([key, member]) => convertRevisionToChange(key, member));
349337

350-
if (returnElements.length) {
351-
this.logger.debug(`Found ${returnElements.length} elements not synced with org`);
352-
} else {
353-
this.logger.debug('Remote source tracking is up to date');
354-
}
338+
this.logger.debug(
339+
returnElements.length
340+
? `Found ${returnElements.length} elements not synced with org`
341+
: 'Remote source tracking is up to date'
342+
);
355343

356344
return returnElements;
357345
}
@@ -370,19 +358,21 @@ export class RemoteSourceTrackingService extends ConfigFile<RemoteSourceTracking
370358
return;
371359
}
372360

373-
const outstandingSourceMembers = calculateExpectedSourceMembers(expectedMembers);
374-
if (expectedMembers.length === 0 || outstandingSourceMembers.size === 0) {
375-
// Don't bother polling if we're not matching SourceMembers
361+
if (expectedMembers.length === 0) {
376362
return;
377363
}
378364

365+
const outstandingSourceMembers = calculateExpectedSourceMembers(expectedMembers);
366+
379367
const originalOutstandingSize = outstandingSourceMembers.size;
380368
// this will be the absolute timeout from the start of the poll. We can also exit early if it doesn't look like more results are coming in
381369
const pollingTimeout = this.calculateTimeout(outstandingSourceMembers.size);
382370
let highestRevisionSoFar = this.getServerMaxRevision();
383371
let pollAttempts = 0;
384372
let consecutiveEmptyResults = 0;
385373
let someResultsReturned = false;
374+
/** we weren't expecting these SourceMembers, based on the deployment results */
375+
const bonusTypes = new Set<string>();
386376

387377
this.logger.debug(
388378
`Polling for ${outstandingSourceMembers.size} SourceMembers from revision ${highestRevisionSoFar} with timeout of ${pollingTimeout.seconds}s`
@@ -402,7 +392,11 @@ export class RemoteSourceTrackingService extends ConfigFile<RemoteSourceTracking
402392
if (queriedMembers.length) {
403393
queriedMembers.map((member) => {
404394
// remove anything returned from the query list
405-
outstandingSourceMembers.delete(getMetadataKey(member.MemberType, member.MemberName));
395+
const metadataKey = getMetadataKey(member.MemberType, member.MemberName);
396+
const deleted = outstandingSourceMembers.delete(metadataKey);
397+
if (!deleted) {
398+
bonusTypes.add(metadataKey);
399+
}
406400
highestRevisionSoFar = Math.max(highestRevisionSoFar, member.RevisionCounter);
407401
});
408402
consecutiveEmptyResults = 0;
@@ -446,6 +440,15 @@ export class RemoteSourceTrackingService extends ConfigFile<RemoteSourceTracking
446440
try {
447441
await pollingFunction();
448442
this.logger.debug(`Retrieved all SourceMember data after ${pollAttempts} attempts`);
443+
// find places where the expectedSourceMembers might be too pruning too aggressively
444+
if (bonusTypes.size) {
445+
void Lifecycle.getInstance().emitTelemetry({
446+
eventName: 'sourceMemberBonusTypes',
447+
library: 'SourceTracking',
448+
deploymentSize: expectedMembers.length,
449+
bonusTypes: Array.from(bonusTypes).sort().join(','),
450+
});
451+
}
449452
} catch {
450453
this.logger.warn(
451454
`Polling for SourceMembers timed out after ${pollAttempts} attempts (last ${consecutiveEmptyResults} were empty) )`
@@ -467,6 +470,7 @@ export class RemoteSourceTrackingService extends ConfigFile<RemoteSourceTracking
467470
consecutiveEmptyResults,
468471
missingQuantity: outstandingSourceMembers.size,
469472
deploymentSize: expectedMembers.length,
473+
bonusTypes: Array.from(bonusTypes).sort().join(','),
470474
types: [...new Set(Array.from(outstandingSourceMembers.values()).map((member) => member.type))]
471475
.sort()
472476
.join(','),
@@ -578,3 +582,9 @@ export const remoteChangeElementToChangeResult = (rce: RemoteChangeElement): Cha
578582
: {}),
579583
origin: 'remote', // we know they're remote
580584
});
585+
586+
const convertRevisionToChange = (memberKey: string, memberRevision: MemberRevision): RemoteChangeElement => ({
587+
type: memberRevision.memberType,
588+
name: memberKey.replace(`${memberRevision.memberType}__`, ''),
589+
deleted: memberRevision.isNameObsolete,
590+
});

0 commit comments

Comments
 (0)