@salesforce/source-tracking 2.2.1 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/lib/shared/conflicts.js +3 -6
- package/lib/shared/expectedSourceMembers.js +22 -24
- package/lib/shared/functions.js +1 -1
- package/lib/shared/localComponentSetArray.js +4 -1
- package/lib/shared/metadataKeys.js +1 -1
- package/lib/shared/populateFilePaths.js +1 -1
- package/lib/shared/populateTypesAndNames.js +3 -4
- package/lib/shared/remoteSourceTrackingService.js +3 -6
- package/lib/sourceTracking.d.ts +9 -3
- package/lib/sourceTracking.js +51 -54
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [2.2.2](https://github.com/forcedotcom/source-tracking/compare/v2.2.1...v2.2.2) (2022-08-10)
|
|
6
|
+
|
|
7
|
+
### ⚠ BREAKING CHANGES
|
|
8
|
+
|
|
9
|
+
- return componentSet and File Responses
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- local CmpSet from changes tracks ignored files like normal CmpSet ([aaa707f](https://github.com/forcedotcom/source-tracking/commit/aaa707fb2e68f5b7199d79d8ea8213068bea09b1))
|
|
14
|
+
- local componentSet can show ignored local files ([c230437](https://github.com/forcedotcom/source-tracking/commit/c23043726dcee304a3b550c0d463719e11f6d9ef))
|
|
15
|
+
- overload to preserve backwards compatibility ([cfc53e3](https://github.com/forcedotcom/source-tracking/commit/cfc53e3ecf0b037cbe7c7ada2588c2e4ead2ab88))
|
|
16
|
+
- return componentSet and File Responses ([b8dc01e](https://github.com/forcedotcom/source-tracking/commit/b8dc01eb0e01ed0aa010c554beae35fa0613d628))
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
- bump eslint/jsdoc to get automerges flowing again ([afd85ff](https://github.com/forcedotcom/source-tracking/commit/afd85ff420877b7fb969085cf5f59d9c3f80555f))
|
|
21
|
+
- ensure remote changes have a value for ignored (plugin expects it) ([bc1379f](https://github.com/forcedotcom/source-tracking/commit/bc1379f8f020fed5bfca721330f4404662d1b300))
|
|
22
|
+
- force version change ([5483cd3](https://github.com/forcedotcom/source-tracking/commit/5483cd317614aea6aeb50c5544cede92fa9c2cb2))
|
|
23
|
+
- remote changes display ignoredness ([d3533f9](https://github.com/forcedotcom/source-tracking/commit/d3533f9275d2a290b3c34019e204718e16ceaa75))
|
|
24
|
+
|
|
5
25
|
### [2.2.1](https://github.com/forcedotcom/source-tracking/compare/v2.2.0...v2.2.1) (2022-07-05)
|
|
6
26
|
|
|
7
27
|
### Bug Fixes
|
package/lib/shared/conflicts.js
CHANGED
|
@@ -31,8 +31,7 @@ const findConflictsInComponentSet = (cs, conflicts) => {
|
|
|
31
31
|
conflicts
|
|
32
32
|
.filter((cr) => cr.name && cr.type && cs.has({ fullName: cr.name, type: cr.type }))
|
|
33
33
|
.forEach((cr) => {
|
|
34
|
-
|
|
35
|
-
(_a = cr.filenames) === null || _a === void 0 ? void 0 : _a.forEach((f) => {
|
|
34
|
+
cr.filenames?.forEach((f) => {
|
|
36
35
|
conflictMap.set(`${cr.name}#${cr.type}#${f}`, {
|
|
37
36
|
state: 'Conflict',
|
|
38
37
|
// the following 2 type assertions are valid because of previous filter statement
|
|
@@ -52,17 +51,15 @@ const getDedupedConflictsFromChanges = ({ localChanges = [], remoteChanges = [],
|
|
|
52
51
|
const fileNameIndex = new Map();
|
|
53
52
|
const metadataKeyIndex = new Map();
|
|
54
53
|
remoteChanges.map((change) => {
|
|
55
|
-
var _a;
|
|
56
54
|
if (change.name && change.type) {
|
|
57
55
|
metadataKeyIndex.set((0, functions_1.getMetadataKey)(change.name, change.type), change);
|
|
58
56
|
}
|
|
59
|
-
|
|
57
|
+
change.filenames?.map((filename) => {
|
|
60
58
|
fileNameIndex.set(filename, change);
|
|
61
59
|
});
|
|
62
60
|
});
|
|
63
61
|
const conflicts = new Set();
|
|
64
62
|
(0, populateTypesAndNames_1.populateTypesAndNames)({ elements: localChanges, excludeUnresolvable: true, projectPath, forceIgnore }).map((change) => {
|
|
65
|
-
var _a;
|
|
66
63
|
const metadataKey = (0, functions_1.getMetadataKey)(change.name, change.type);
|
|
67
64
|
// option 1: name and type match
|
|
68
65
|
if (metadataKeyIndex.has(metadataKey)) {
|
|
@@ -70,7 +67,7 @@ const getDedupedConflictsFromChanges = ({ localChanges = [], remoteChanges = [],
|
|
|
70
67
|
}
|
|
71
68
|
else {
|
|
72
69
|
// option 2: some of the filenames match
|
|
73
|
-
|
|
70
|
+
change.filenames?.map((filename) => {
|
|
74
71
|
if (fileNameIndex.has(filename)) {
|
|
75
72
|
conflicts.add({ ...fileNameIndex.get(filename) });
|
|
76
73
|
}
|
|
@@ -24,7 +24,7 @@ const typesToNoPollFor = [
|
|
|
24
24
|
];
|
|
25
25
|
const typesNotToPollForIfNamespace = ['CustomLabels', 'CustomMetadata', 'DuplicateRule', 'WebLink'];
|
|
26
26
|
const isEncodedTypeWithPercentSign = (type, filePath) => ['Layout', 'Profile', 'HomePageComponent', 'HomePageLayout', 'MilestoneType'].includes(type) &&
|
|
27
|
-
Boolean(filePath
|
|
27
|
+
Boolean(filePath?.includes('%'));
|
|
28
28
|
// aura xml aren't tracked as SourceMembers
|
|
29
29
|
const isSpecialAuraXml = (filePath) => Boolean(filePath &&
|
|
30
30
|
(filePath.endsWith('.cmp-meta.xml') ||
|
|
@@ -35,29 +35,27 @@ const isSpecialAuraXml = (filePath) => Boolean(filePath &&
|
|
|
35
35
|
const calculateExpectedSourceMembers = (expectedMembers) => {
|
|
36
36
|
const outstandingSourceMembers = new Map();
|
|
37
37
|
expectedMembers
|
|
38
|
-
.filter((fileResponse) =>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
!isSpecialAuraXml(fileResponse.filePath);
|
|
60
|
-
})
|
|
38
|
+
.filter((fileResponse) =>
|
|
39
|
+
// unchanged files will never be in the sourceMembers. Not really sure why SDR returns them.
|
|
40
|
+
fileResponse.state !== source_deploy_retrieve_1.ComponentStatus.Unchanged &&
|
|
41
|
+
// if a listView is the only change inside an object, the object won't have a sourceMember change. We won't wait for those to be found
|
|
42
|
+
// we don't know which email folder type might be there, so don't require either
|
|
43
|
+
// Portal doesn't support source tracking, according to the coverage report
|
|
44
|
+
!typesToNoPollFor.includes(fileResponse.type) &&
|
|
45
|
+
// don't wait for standard fields on standard objects
|
|
46
|
+
!(fileResponse.type === 'CustomField' && !fileResponse.filePath?.includes('__c')) &&
|
|
47
|
+
// deleted fields
|
|
48
|
+
!(fileResponse.type === 'CustomField' && fileResponse.filePath?.includes('_del__c')) &&
|
|
49
|
+
// built-in report type ReportType__screen_flows_prebuilt_crt
|
|
50
|
+
!(fileResponse.type === 'ReportType' && fileResponse.filePath?.includes('screen_flows_prebuilt_crt')) &&
|
|
51
|
+
// they're settings to mdapi, and FooSettings in sourceMembers
|
|
52
|
+
!fileResponse.type.includes('Settings') &&
|
|
53
|
+
// mdapi encodes these, sourceMembers don't have encoding
|
|
54
|
+
!isEncodedTypeWithPercentSign(fileResponse.type, fileResponse.filePath) &&
|
|
55
|
+
!(typesNotToPollForIfNamespace.includes(fileResponse.type) && fileResponse.filePath?.includes('__')) &&
|
|
56
|
+
// don't wait on workflow children
|
|
57
|
+
!fileResponse.type.startsWith('Workflow') &&
|
|
58
|
+
!isSpecialAuraXml(fileResponse.filePath))
|
|
61
59
|
.map((member) => {
|
|
62
60
|
(0, metadataKeys_1.getMetadataKeyFromFileResponse)(member)
|
|
63
61
|
// remove some individual members known to not work with tracking even when their type does
|
package/lib/shared/functions.js
CHANGED
|
@@ -20,7 +20,7 @@ const getKeyFromObject = (element) => {
|
|
|
20
20
|
throw new Error(`unable to complete key from ${JSON.stringify(element)}`);
|
|
21
21
|
};
|
|
22
22
|
exports.getKeyFromObject = getKeyFromObject;
|
|
23
|
-
const isBundle = (cmp) =>
|
|
23
|
+
const isBundle = (cmp) => cmp.type.strategies?.adapter === 'bundle';
|
|
24
24
|
exports.isBundle = isBundle;
|
|
25
25
|
const isLwcLocalOnlyTest = (filePath) => filePath.includes('__utam__') || filePath.includes('__tests__');
|
|
26
26
|
exports.isLwcLocalOnlyTest = isLwcLocalOnlyTest;
|
|
@@ -76,9 +76,12 @@ const getComponentSets = (groupings, sourceApiVersion) => {
|
|
|
76
76
|
})
|
|
77
77
|
.filter(guards_1.sourceComponentGuard)
|
|
78
78
|
.map((component) => componentSet.add(component));
|
|
79
|
+
// there may have been ignored files, but componentSet.add doesn't automatically track them.
|
|
80
|
+
// We'll manually set the ignored paths from what the resolver has been tracking
|
|
81
|
+
componentSet.forceIgnoredPaths = new Set([...(componentSet.forceIgnoredPaths ?? [])].concat(Array.from(resolverForNonDeletes.forceIgnoredPaths)));
|
|
79
82
|
return componentSet;
|
|
80
83
|
})
|
|
81
|
-
.filter((componentSet) => componentSet.size > 0);
|
|
84
|
+
.filter((componentSet) => componentSet.size > 0 || componentSet.forceIgnoredPaths?.size);
|
|
82
85
|
};
|
|
83
86
|
exports.getComponentSets = getComponentSets;
|
|
84
87
|
//# sourceMappingURL=localComponentSetArray.js.map
|
|
@@ -13,7 +13,7 @@ const core_1 = require("@salesforce/core");
|
|
|
13
13
|
const functions_1 = require("./functions");
|
|
14
14
|
// See UT for examples of the complexity this must handle
|
|
15
15
|
// keys always use forward slashes, even on Windows
|
|
16
|
-
const pathAfterFullName = (fileResponse) =>
|
|
16
|
+
const pathAfterFullName = (fileResponse) => fileResponse?.filePath
|
|
17
17
|
? (0, path_1.join)((0, path_1.dirname)(fileResponse.filePath).substring((0, path_1.dirname)(fileResponse.filePath).lastIndexOf(fileResponse.fullName)), (0, path_1.basename)(fileResponse.filePath)).replace(/\\/gi, '/')
|
|
18
18
|
: '';
|
|
19
19
|
const registry = new source_deploy_retrieve_1.RegistryAccess();
|
|
@@ -43,7 +43,7 @@ const populateFilePaths = (elements, packageDirPaths) => {
|
|
|
43
43
|
// there *could* be something missing
|
|
44
44
|
// some types (ex: LWC) show up as multiple files in the remote changes, but only one in the component set
|
|
45
45
|
// iterate the elements to see which ones didn't make it into the component set
|
|
46
|
-
const missingComponents = elements.filter((element) => !remoteChangesAsComponentSet.has({ type: element
|
|
46
|
+
const missingComponents = elements.filter((element) => !remoteChangesAsComponentSet.has({ type: element?.type, fullName: element?.name }));
|
|
47
47
|
// Throw if anything was actually missing
|
|
48
48
|
if (missingComponents.length > 0) {
|
|
49
49
|
throw new Error(`unable to generate complete component set for ${elements
|
|
@@ -45,19 +45,18 @@ const populateTypesAndNames = ({ elements, projectPath, forceIgnore, excludeUnre
|
|
|
45
45
|
// make it simpler to find things later
|
|
46
46
|
const elementMap = new Map();
|
|
47
47
|
elements.map((element) => {
|
|
48
|
-
|
|
49
|
-
(_a = element.filenames) === null || _a === void 0 ? void 0 : _a.map((filename) => {
|
|
48
|
+
element.filenames?.map((filename) => {
|
|
50
49
|
elementMap.set((0, functions_1.ensureRelative)(filename, projectPath), element);
|
|
51
50
|
});
|
|
52
51
|
});
|
|
53
52
|
// iterates the local components and sets their filenames
|
|
54
53
|
sourceComponents.map((matchingComponent) => {
|
|
55
|
-
if (
|
|
54
|
+
if (matchingComponent?.fullName && matchingComponent?.type.name) {
|
|
56
55
|
const filenamesFromMatchingComponent = [matchingComponent.xml, ...matchingComponent.walkContent()];
|
|
57
56
|
const ignored = filenamesFromMatchingComponent
|
|
58
57
|
.filter(ts_types_1.isString)
|
|
59
58
|
.filter((f) => !(0, functions_1.isLwcLocalOnlyTest)(f))
|
|
60
|
-
.some((f) => forceIgnore
|
|
59
|
+
.some((f) => forceIgnore?.denies(f));
|
|
61
60
|
filenamesFromMatchingComponent.map((filename) => {
|
|
62
61
|
if (filename && elementMap.has(filename)) {
|
|
63
62
|
// add the type/name from the componentSet onto the element
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
/* eslint-disable no-underscore-dangle */
|
|
9
9
|
/* eslint-disable @typescript-eslint/member-ordering */
|
|
10
|
-
var _a;
|
|
11
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
11
|
exports.remoteChangeElementToChangeResult = exports.RemoteSourceTrackingService = void 0;
|
|
13
12
|
const path = require("path");
|
|
@@ -23,7 +22,7 @@ const expectedSourceMembers_1 = require("./expectedSourceMembers");
|
|
|
23
22
|
* even when there is a longer timeout remaining (because the deployment is very large)
|
|
24
23
|
*/
|
|
25
24
|
const POLLING_DELAY_MS = 1000;
|
|
26
|
-
const CONSECUTIVE_EMPTY_POLLING_RESULT_LIMIT = (
|
|
25
|
+
const CONSECUTIVE_EMPTY_POLLING_RESULT_LIMIT = (kit_1.env.getNumber('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT') ?? 120) / kit_1.Duration.milliseconds(POLLING_DELAY_MS).seconds;
|
|
27
26
|
/**
|
|
28
27
|
* This service handles source tracking of metadata between a local project and an org.
|
|
29
28
|
* Source tracking state is persisted to .sfdx/orgs/<orgId>/maxRevision.json.
|
|
@@ -264,11 +263,10 @@ class RemoteSourceTrackingService extends core_1.ConfigFile {
|
|
|
264
263
|
}
|
|
265
264
|
let serverMaxRevisionCounter = this.getServerMaxRevision();
|
|
266
265
|
sourceMembers.forEach((change) => {
|
|
267
|
-
var _a;
|
|
268
266
|
// try accessing the sourceMembers object at the index of the change's name
|
|
269
267
|
// if it exists, we'll update the fields - if it doesn't, we'll create and insert it
|
|
270
268
|
const key = (0, functions_1.getMetadataKey)(change.MemberType, change.MemberName);
|
|
271
|
-
const sourceMember =
|
|
269
|
+
const sourceMember = this.getSourceMember(key) ?? {
|
|
272
270
|
serverRevisionCounter: change.RevisionCounter,
|
|
273
271
|
lastRetrievedFromServer: null,
|
|
274
272
|
memberType: change.MemberType,
|
|
@@ -432,8 +430,7 @@ class RemoteSourceTrackingService extends core_1.ConfigFile {
|
|
|
432
430
|
}
|
|
433
431
|
}
|
|
434
432
|
calculateTimeout(memberCount) {
|
|
435
|
-
|
|
436
|
-
const overriddenTimeout = (_a = kit_1.env.getNumber('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', 0)) !== null && _a !== void 0 ? _a : 0;
|
|
433
|
+
const overriddenTimeout = kit_1.env.getNumber('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', 0) ?? 0;
|
|
437
434
|
if (overriddenTimeout > 0) {
|
|
438
435
|
this.logger.debug(`Overriding SourceMember polling timeout to ${overriddenTimeout}`);
|
|
439
436
|
return kit_1.Duration.seconds(overriddenTimeout);
|
package/lib/sourceTracking.d.ts
CHANGED
|
@@ -19,6 +19,10 @@ export interface SourceTrackingOptions {
|
|
|
19
19
|
*/
|
|
20
20
|
ignoreLocalCache?: boolean;
|
|
21
21
|
}
|
|
22
|
+
declare type RemoteChangesResults = {
|
|
23
|
+
componentSetFromNonDeletes: ComponentSet;
|
|
24
|
+
fileResponsesFromDelete: FileResponse[];
|
|
25
|
+
};
|
|
22
26
|
/**
|
|
23
27
|
* Manages source tracking files (remote and local)
|
|
24
28
|
*
|
|
@@ -104,11 +108,12 @@ export declare class SourceTracking extends AsyncCreatable {
|
|
|
104
108
|
*
|
|
105
109
|
* Convenience method to reduce duplicated steps required to do a fka pull
|
|
106
110
|
* It's full of side effects: retrieving remote deletes, deleting those files locall, and then updating tracking files
|
|
107
|
-
* Most bizarrely, it then returns a ComponentSet of the remote nonDeletes
|
|
111
|
+
* Most bizarrely, it then returns a ComponentSet of the remote nonDeletes and the FileResponses from the delete
|
|
108
112
|
*
|
|
109
|
-
* @returns the ComponentSet for what you would retrieve now that the deletes are done
|
|
113
|
+
* @returns the ComponentSet for what you would retrieve now that the deletes are done, and optionally, a FileResponses array for the deleted files
|
|
110
114
|
*/
|
|
111
|
-
maybeApplyRemoteDeletesToLocal(): Promise<
|
|
115
|
+
maybeApplyRemoteDeletesToLocal(returnDeleteFileResponses: true): Promise<RemoteChangesResults>;
|
|
116
|
+
maybeApplyRemoteDeletesToLocal(returnDeleteFileResponses?: false): Promise<ComponentSet>;
|
|
112
117
|
/**
|
|
113
118
|
*
|
|
114
119
|
* returns immediately if there are no changesToDelete
|
|
@@ -186,3 +191,4 @@ export declare class SourceTracking extends AsyncCreatable {
|
|
|
186
191
|
private localChangesToOutputRow;
|
|
187
192
|
private remoteChangesToOutputRows;
|
|
188
193
|
}
|
|
194
|
+
export {};
|
package/lib/sourceTracking.js
CHANGED
|
@@ -13,6 +13,8 @@ const core_1 = require("@salesforce/core");
|
|
|
13
13
|
const kit_1 = require("@salesforce/kit");
|
|
14
14
|
const ts_types_1 = require("@salesforce/ts-types");
|
|
15
15
|
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
16
|
+
// this is not exported by SDR (see the comments in SDR regarding its limitations)
|
|
17
|
+
const filePathGenerator_1 = require("@salesforce/source-deploy-retrieve/lib/src/utils/filePathGenerator");
|
|
16
18
|
const remoteSourceTrackingService_1 = require("./shared/remoteSourceTrackingService");
|
|
17
19
|
const localShadowRepo_1 = require("./shared/localShadowRepo");
|
|
18
20
|
const conflicts_1 = require("./shared/conflicts");
|
|
@@ -31,7 +33,6 @@ const localComponentSetArray_1 = require("./shared/localComponentSetArray");
|
|
|
31
33
|
*/
|
|
32
34
|
class SourceTracking extends kit_1.AsyncCreatable {
|
|
33
35
|
constructor(options) {
|
|
34
|
-
var _a, _b, _c;
|
|
35
36
|
super(options);
|
|
36
37
|
this.org = options.org;
|
|
37
38
|
this.orgId = this.org.getOrgId();
|
|
@@ -39,9 +40,9 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
39
40
|
this.packagesDirs = options.project.getPackageDirectories();
|
|
40
41
|
this.logger = core_1.Logger.childFromRoot('SourceTracking');
|
|
41
42
|
this.project = options.project;
|
|
42
|
-
this.ignoreConflicts =
|
|
43
|
-
this.ignoreLocalCache =
|
|
44
|
-
this.subscribeSDREvents =
|
|
43
|
+
this.ignoreConflicts = options.ignoreConflicts ?? false;
|
|
44
|
+
this.ignoreLocalCache = options.ignoreLocalCache ?? false;
|
|
45
|
+
this.subscribeSDREvents = options.subscribeSDREvents ?? false;
|
|
45
46
|
this.hasSfdxTrackingFiles = (0, compatibility_1.hasSfdxTrackingFiles)(this.orgId, this.projectPath);
|
|
46
47
|
}
|
|
47
48
|
// eslint-disable-next-line class-methods-use-this
|
|
@@ -70,7 +71,7 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
70
71
|
packageDirs: this.packagesDirs,
|
|
71
72
|
nonDeletes,
|
|
72
73
|
deletes,
|
|
73
|
-
}, byPackageDir
|
|
74
|
+
}, byPackageDir ?? Boolean(projectConfig.pushPackageDirectoriesSequentially)); // if the users specified true or false for the param, that overrides the project config
|
|
74
75
|
this.logger.debug(`will build array of ${groupings.length} componentSet(s)`);
|
|
75
76
|
return (0, localComponentSetArray_1.getComponentSets)(groupings, sourceApiVersion);
|
|
76
77
|
}
|
|
@@ -133,7 +134,7 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
133
134
|
return results;
|
|
134
135
|
}
|
|
135
136
|
async getChanges(options) {
|
|
136
|
-
if (
|
|
137
|
+
if (options?.origin === 'local') {
|
|
137
138
|
await this.ensureLocalTracking();
|
|
138
139
|
const filenames = await this.getLocalChangesAsFilenames(options.state);
|
|
139
140
|
if (options.format === 'string') {
|
|
@@ -162,7 +163,7 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
162
163
|
.filter(guards_1.sourceComponentGuard);
|
|
163
164
|
}
|
|
164
165
|
}
|
|
165
|
-
if (
|
|
166
|
+
if (options?.origin === 'remote') {
|
|
166
167
|
await this.ensureRemoteTracking();
|
|
167
168
|
const remoteChanges = await this.remoteSourceTrackingService.retrieveUpdates();
|
|
168
169
|
this.logger.debug('remoteChanges', remoteChanges);
|
|
@@ -178,8 +179,8 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
178
179
|
}
|
|
179
180
|
// turn it into a componentSet to resolve filenames
|
|
180
181
|
const remoteChangesAsComponentSet = new source_deploy_retrieve_1.ComponentSet(filteredChanges.map((element) => ({
|
|
181
|
-
type: element
|
|
182
|
-
fullName: element
|
|
182
|
+
type: element?.type,
|
|
183
|
+
fullName: element?.name,
|
|
183
184
|
})));
|
|
184
185
|
const matchingLocalSourceComponentsSet = source_deploy_retrieve_1.ComponentSet.fromSource({
|
|
185
186
|
fsPaths: this.packagesDirs.map((dir) => (0, path_1.resolve)(dir.fullPath)),
|
|
@@ -197,18 +198,12 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
197
198
|
}
|
|
198
199
|
throw new Error(`unsupported options: ${JSON.stringify(options)}`);
|
|
199
200
|
}
|
|
200
|
-
|
|
201
|
-
*
|
|
202
|
-
* Convenience method to reduce duplicated steps required to do a fka pull
|
|
203
|
-
* It's full of side effects: retrieving remote deletes, deleting those files locall, and then updating tracking files
|
|
204
|
-
* Most bizarrely, it then returns a ComponentSet of the remote nonDeletes.
|
|
205
|
-
*
|
|
206
|
-
* @returns the ComponentSet for what you would retrieve now that the deletes are done
|
|
207
|
-
*/
|
|
208
|
-
async maybeApplyRemoteDeletesToLocal() {
|
|
201
|
+
async maybeApplyRemoteDeletesToLocal(returnDeleteFileResponses) {
|
|
209
202
|
const changesToDelete = await this.getChanges({ origin: 'remote', state: 'delete', format: 'SourceComponent' });
|
|
210
|
-
await this.deleteFilesAndUpdateTracking(changesToDelete);
|
|
211
|
-
return
|
|
203
|
+
const fileResponsesFromDelete = await this.deleteFilesAndUpdateTracking(changesToDelete);
|
|
204
|
+
return returnDeleteFileResponses
|
|
205
|
+
? { componentSetFromNonDeletes: await this.remoteNonDeletesAsComponentSet(), fileResponsesFromDelete }
|
|
206
|
+
: this.remoteNonDeletesAsComponentSet();
|
|
212
207
|
}
|
|
213
208
|
/**
|
|
214
209
|
*
|
|
@@ -237,15 +232,12 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
237
232
|
})), true // skip polling because it's a pull
|
|
238
233
|
),
|
|
239
234
|
]);
|
|
240
|
-
return filenames.map((filename) => {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
fullName: (_b = sourceComponentByFileName.get(filename)) === null || _b === void 0 ? void 0 : _b.fullName,
|
|
247
|
-
});
|
|
248
|
-
});
|
|
235
|
+
return filenames.map((filename) => ({
|
|
236
|
+
state: 'Deleted',
|
|
237
|
+
filename,
|
|
238
|
+
type: sourceComponentByFileName.get(filename)?.type.name,
|
|
239
|
+
fullName: sourceComponentByFileName.get(filename)?.fullName,
|
|
240
|
+
}));
|
|
249
241
|
}
|
|
250
242
|
/**
|
|
251
243
|
* Update tracking for the options passed.
|
|
@@ -253,12 +245,11 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
253
245
|
* @param options the files to update
|
|
254
246
|
*/
|
|
255
247
|
async updateLocalTracking(options) {
|
|
256
|
-
var _a, _b;
|
|
257
248
|
await this.ensureLocalTracking();
|
|
258
249
|
// relative paths make smaller trees AND isogit wants them relative
|
|
259
250
|
const relativeOptions = {
|
|
260
|
-
files: (
|
|
261
|
-
deletedFiles: (
|
|
251
|
+
files: (options.files ?? []).map((file) => (0, functions_1.ensureRelative)(file, this.projectPath)),
|
|
252
|
+
deletedFiles: (options.deletedFiles ?? []).map((file) => (0, functions_1.ensureRelative)(file, this.projectPath)),
|
|
262
253
|
};
|
|
263
254
|
// plot twist: if you delete a member of a bundle (ex: lwc/foo/foo.css) and push, it'll not be in the fileResponses (deployedFiles) or deletedFiles
|
|
264
255
|
// what got deleted? Any local changes NOT in the fileResponses but part of a successfully deployed bundle
|
|
@@ -378,7 +369,6 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
378
369
|
* Compares local and remote changes to detect conflicts
|
|
379
370
|
*/
|
|
380
371
|
async getConflicts() {
|
|
381
|
-
var _a;
|
|
382
372
|
// we're going to need have both initialized
|
|
383
373
|
await Promise.all([this.ensureRemoteTracking(), this.ensureLocalTracking()]);
|
|
384
374
|
// Strategy: check local changes first (since it'll be faster) to avoid callout
|
|
@@ -400,7 +390,7 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
400
390
|
if (remoteChanges.length === 0) {
|
|
401
391
|
return [];
|
|
402
392
|
}
|
|
403
|
-
|
|
393
|
+
this.forceIgnore ?? (this.forceIgnore = source_deploy_retrieve_1.ForceIgnore.findAndCreate(this.project.getDefaultPackage().path));
|
|
404
394
|
return (0, conflicts_1.getDedupedConflictsFromChanges)({
|
|
405
395
|
localChanges,
|
|
406
396
|
remoteChanges,
|
|
@@ -538,38 +528,34 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
538
528
|
throw new Error(`unable to get local changes for state ${state}`);
|
|
539
529
|
}
|
|
540
530
|
localChangesToOutputRow(input, localType) {
|
|
541
|
-
var _a;
|
|
542
531
|
this.logger.debug('converting ChangeResult to a row', input);
|
|
543
|
-
|
|
532
|
+
this.forceIgnore ?? (this.forceIgnore = source_deploy_retrieve_1.ForceIgnore.findAndCreate(this.project.getDefaultPackage().path));
|
|
544
533
|
if (input.filenames) {
|
|
545
|
-
return input.filenames.map((filename) => {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
ignored: this.forceIgnore.denies(filename),
|
|
554
|
-
});
|
|
555
|
-
});
|
|
534
|
+
return input.filenames.map((filename) => ({
|
|
535
|
+
type: input.type ?? '',
|
|
536
|
+
state: localType,
|
|
537
|
+
fullName: input.name ?? '',
|
|
538
|
+
filePath: filename,
|
|
539
|
+
origin: 'local',
|
|
540
|
+
ignored: this.forceIgnore.denies(filename),
|
|
541
|
+
}));
|
|
556
542
|
}
|
|
557
543
|
throw new Error('no filenames found for local ChangeResult');
|
|
558
544
|
}
|
|
559
|
-
//
|
|
545
|
+
// reserve the right to do something more sophisticated in the future
|
|
546
|
+
// via async for figuring out hypothetical filenames (ex: getting default packageDir)
|
|
560
547
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
561
548
|
async remoteChangesToOutputRows(input) {
|
|
562
|
-
var _a, _b, _c, _d;
|
|
563
549
|
this.logger.debug('converting ChangeResult to a row', input);
|
|
564
|
-
|
|
550
|
+
this.forceIgnore ?? (this.forceIgnore = source_deploy_retrieve_1.ForceIgnore.findAndCreate(this.project.getDefaultPackage().path));
|
|
565
551
|
const baseObject = {
|
|
566
|
-
type:
|
|
552
|
+
type: input.type ?? '',
|
|
567
553
|
origin: input.origin,
|
|
568
554
|
state: stateFromChangeResult(input),
|
|
569
|
-
fullName:
|
|
555
|
+
fullName: input.name ?? '',
|
|
570
556
|
};
|
|
571
557
|
// it's easy to check ignores if the filePaths exist locally
|
|
572
|
-
if (
|
|
558
|
+
if (input.filenames?.length) {
|
|
573
559
|
return input.filenames.map((filename) => ({
|
|
574
560
|
...baseObject,
|
|
575
561
|
filePath: filename,
|
|
@@ -577,7 +563,18 @@ class SourceTracking extends kit_1.AsyncCreatable {
|
|
|
577
563
|
}));
|
|
578
564
|
}
|
|
579
565
|
// when the file doesn't exist locally, there are no filePaths
|
|
580
|
-
//
|
|
566
|
+
// SDR can generate the hypothetical place it *would* go and check that
|
|
567
|
+
if (input.name && input.type) {
|
|
568
|
+
return [
|
|
569
|
+
{
|
|
570
|
+
...baseObject,
|
|
571
|
+
ignored: (0, filePathGenerator_1.filePathsFromMetadataComponent)({
|
|
572
|
+
fullName: input.name,
|
|
573
|
+
type: new source_deploy_retrieve_1.RegistryAccess().getTypeByName(input.type),
|
|
574
|
+
}).some((hypotheticalFilePath) => this.forceIgnore.denies(hypotheticalFilePath)),
|
|
575
|
+
},
|
|
576
|
+
];
|
|
577
|
+
}
|
|
581
578
|
return [baseObject];
|
|
582
579
|
}
|
|
583
580
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/source-tracking",
|
|
3
3
|
"description": "API for tracking local and remote Salesforce metadata changes",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.2",
|
|
5
5
|
"author": "Salesforce",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
7
7
|
"main": "lib/index.js",
|
|
@@ -43,17 +43,17 @@
|
|
|
43
43
|
"/oclif.manifest.json"
|
|
44
44
|
],
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@salesforce/core": "^3.
|
|
47
|
-
"@salesforce/kit": "^1.5.
|
|
48
|
-
"@salesforce/source-deploy-retrieve": "^6.
|
|
46
|
+
"@salesforce/core": "^3.26.1",
|
|
47
|
+
"@salesforce/kit": "^1.5.45",
|
|
48
|
+
"@salesforce/source-deploy-retrieve": "^6.2.7",
|
|
49
49
|
"graceful-fs": "^4.2.9",
|
|
50
50
|
"isomorphic-git": "1.17.0",
|
|
51
51
|
"ts-retry-promise": "^0.6.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@salesforce/cli-plugins-testkit": "^2.3.
|
|
55
|
-
"@salesforce/dev-config": "^3.
|
|
56
|
-
"@salesforce/dev-scripts": "^2.0.
|
|
54
|
+
"@salesforce/cli-plugins-testkit": "^2.3.10",
|
|
55
|
+
"@salesforce/dev-config": "^3.1.0",
|
|
56
|
+
"@salesforce/dev-scripts": "^2.0.4",
|
|
57
57
|
"@salesforce/prettier-config": "^0.0.2",
|
|
58
58
|
"@salesforce/ts-sinon": "^1.3.21",
|
|
59
59
|
"@types/shelljs": "^0.8.9",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"eslint-config-salesforce-typescript": "^1.0.0",
|
|
69
69
|
"eslint-plugin-header": "^3.1.1",
|
|
70
70
|
"eslint-plugin-import": "2.25.4",
|
|
71
|
-
"eslint-plugin-jsdoc": "^
|
|
71
|
+
"eslint-plugin-jsdoc": "^39.3.6",
|
|
72
72
|
"eslint-plugin-prettier": "^3.4.0",
|
|
73
73
|
"husky": "^7.0.4",
|
|
74
74
|
"mocha": "^9.1.3",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"shelljs": "^0.8.4",
|
|
79
79
|
"shx": "^0.3.3",
|
|
80
80
|
"sinon": "^10.0.0",
|
|
81
|
-
"ts-node": "^10.1
|
|
81
|
+
"ts-node": "^10.9.1",
|
|
82
82
|
"ts-prune": "^0.10.0",
|
|
83
83
|
"typescript": "^4.7.4"
|
|
84
84
|
},
|