@salesforce/source-tracking 7.4.10 → 7.5.1
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/lib/shared/functions.d.ts +3 -2
- package/lib/shared/functions.js +1 -2
- package/lib/shared/guards.d.ts +1 -3
- package/lib/shared/guards.js +1 -5
- package/lib/shared/local/functions.d.ts +0 -1
- package/lib/shared/local/functions.js +2 -4
- package/lib/shared/local/localShadowRepo.js +3 -27
- package/lib/shared/local/moveDetection.d.ts +1 -4
- package/lib/shared/local/moveDetection.js +5 -14
- package/lib/shared/localComponentSetArray.js +1 -1
- package/lib/shared/metadataKeys.d.ts +3 -3
- package/lib/shared/metadataKeys.js +12 -15
- package/lib/shared/remote/expectedSourceMembers.d.ts +3 -2
- package/lib/shared/remote/expectedSourceMembers.js +3 -2
- package/lib/shared/remote/fileOperations.d.ts +1 -2
- package/lib/shared/remote/fileOperations.js +37 -5
- package/lib/shared/remote/orgQueries.d.ts +0 -1
- package/lib/shared/remote/orgQueries.js +3 -4
- package/lib/shared/remote/remoteSourceTrackingService.d.ts +6 -4
- package/lib/shared/remote/remoteSourceTrackingService.js +62 -22
- package/lib/shared/remoteChangeIgnoring.d.ts +2 -2
- package/lib/shared/remoteChangeIgnoring.js +5 -24
- package/lib/shared/types.d.ts +2 -1
- package/lib/sourceTracking.d.ts +2 -0
- package/lib/sourceTracking.js +43 -22
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -9
|
@@ -18,7 +18,7 @@ export declare const pathIsInFolder: (folder: string) => (filePath: string) => b
|
|
|
18
18
|
export declare const folderContainsPath: (filePath: string) => (folder: string) => boolean;
|
|
19
19
|
export declare const chunkArray: <T>(arr: T[], size: number) => T[][];
|
|
20
20
|
export declare const ensureRelative: (projectPath: string) => (filePath: string) => string;
|
|
21
|
-
|
|
21
|
+
type ParsedCustomLabels = {
|
|
22
22
|
CustomLabels: {
|
|
23
23
|
labels: Array<{
|
|
24
24
|
fullName: string;
|
|
@@ -40,5 +40,6 @@ export declare const sourceComponentHasFullNameAndType: (input: SourceComponent)
|
|
|
40
40
|
export declare const getAllFiles: (sc: SourceComponent) => string[];
|
|
41
41
|
export declare const remoteChangeToMetadataMember: (cr: ChangeResult) => MetadataMember;
|
|
42
42
|
export declare const FileResponseSuccessToRemoteSyncInput: (fr: FileResponseSuccess) => RemoteSyncInput;
|
|
43
|
-
export declare const changeResultToMetadataComponent: (registry
|
|
43
|
+
export declare const changeResultToMetadataComponent: (registry: RegistryAccess) => (cr: ChangeResultWithNameAndType) => MetadataComponent;
|
|
44
44
|
export declare const uniqueArrayConcat: <T>(arr1: T[] | Set<T>, arr2: T[] | Set<T>) => T[];
|
|
45
|
+
export {};
|
package/lib/shared/functions.js
CHANGED
|
@@ -22,7 +22,6 @@ exports.uniqueArrayConcat = exports.changeResultToMetadataComponent = exports.Fi
|
|
|
22
22
|
const node_path_1 = require("node:path");
|
|
23
23
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
24
24
|
const ts_types_1 = require("@salesforce/ts-types");
|
|
25
|
-
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
26
25
|
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
27
26
|
const kit_1 = require("@salesforce/kit");
|
|
28
27
|
const remoteChangeIgnoring_1 = require("./remoteChangeIgnoring");
|
|
@@ -145,7 +144,7 @@ exports.remoteChangeToMetadataMember = remoteChangeToMetadataMember;
|
|
|
145
144
|
// weird, right? This is for oclif.table which allows types but not interfaces. In this case, they are equivalent
|
|
146
145
|
const FileResponseSuccessToRemoteSyncInput = (fr) => fr;
|
|
147
146
|
exports.FileResponseSuccessToRemoteSyncInput = FileResponseSuccessToRemoteSyncInput;
|
|
148
|
-
const changeResultToMetadataComponent = (registry
|
|
147
|
+
const changeResultToMetadataComponent = (registry) => (cr) => ({
|
|
149
148
|
fullName: cr.name,
|
|
150
149
|
type: registry.getTypeByName(cr.type),
|
|
151
150
|
});
|
package/lib/shared/guards.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FileResponse, FileResponseSuccess } from '@salesforce/source-deploy-retrieve';
|
|
2
2
|
import { ChangeResult } from './types';
|
|
3
3
|
import { ChangeResultWithNameAndType } from './types';
|
|
4
|
-
export declare const metadataMemberGuard: (input: MetadataMember | undefined | Partial<MetadataMember>) => input is MetadataMember;
|
|
5
|
-
export declare const isSdrFailure: (fileResponse: FileResponse) => fileResponse is FileResponseFailure;
|
|
6
4
|
export declare const isSdrSuccess: (fileResponse: FileResponse) => fileResponse is FileResponseSuccess;
|
|
7
5
|
export declare const FileResponseIsDeleted: (fileResponse: FileResponse) => boolean;
|
|
8
6
|
export declare const FileResponseIsNotDeleted: (fileResponse: FileResponse) => boolean;
|
package/lib/shared/guards.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isDefined = exports.isChangeResultWithNameAndType = exports.FileResponseHasPath = exports.FileResponseIsNotDeleted = exports.FileResponseIsDeleted = exports.isSdrSuccess =
|
|
3
|
+
exports.isDefined = exports.isChangeResultWithNameAndType = exports.FileResponseHasPath = exports.FileResponseIsNotDeleted = exports.FileResponseIsDeleted = exports.isSdrSuccess = void 0;
|
|
4
4
|
/*
|
|
5
5
|
* Copyright 2025, Salesforce, Inc.
|
|
6
6
|
*
|
|
@@ -17,10 +17,6 @@ exports.isDefined = exports.isChangeResultWithNameAndType = exports.FileResponse
|
|
|
17
17
|
* limitations under the License.
|
|
18
18
|
*/
|
|
19
19
|
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
20
|
-
const metadataMemberGuard = (input) => input !== undefined && typeof input.fullName === 'string' && typeof input.type === 'string';
|
|
21
|
-
exports.metadataMemberGuard = metadataMemberGuard;
|
|
22
|
-
const isSdrFailure = (fileResponse) => fileResponse.state === source_deploy_retrieve_1.ComponentStatus.Failed;
|
|
23
|
-
exports.isSdrFailure = isSdrFailure;
|
|
24
20
|
const isSdrSuccess = (fileResponse) => fileResponse.state !== source_deploy_retrieve_1.ComponentStatus.Failed;
|
|
25
21
|
exports.isSdrSuccess = isSdrSuccess;
|
|
26
22
|
const FileResponseIsDeleted = (fileResponse) => fileResponse.state === source_deploy_retrieve_1.ComponentStatus.Deleted;
|
|
@@ -3,7 +3,6 @@ export declare const IS_WINDOWS: boolean;
|
|
|
3
3
|
export declare const toFilenames: (rows: StatusRow[]) => string[];
|
|
4
4
|
export declare const isDeleted: (status: StatusRow) => boolean;
|
|
5
5
|
export declare const isAdded: (status: StatusRow) => boolean;
|
|
6
|
-
export declare const ensureWindows: (filepath: string) => string;
|
|
7
6
|
export declare const ensurePosix: (filepath: string) => string;
|
|
8
7
|
export declare const FILE = 0;
|
|
9
8
|
export declare const HEAD = 1;
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.WORKDIR = exports.HEAD = exports.FILE = exports.ensurePosix = exports.
|
|
36
|
+
exports.WORKDIR = exports.HEAD = exports.FILE = exports.ensurePosix = exports.isAdded = exports.isDeleted = exports.toFilenames = exports.IS_WINDOWS = void 0;
|
|
37
37
|
/*
|
|
38
38
|
* Copyright 2025, Salesforce, Inc.
|
|
39
39
|
*
|
|
@@ -49,8 +49,8 @@ exports.WORKDIR = exports.HEAD = exports.FILE = exports.ensurePosix = exports.en
|
|
|
49
49
|
* See the License for the specific language governing permissions and
|
|
50
50
|
* limitations under the License.
|
|
51
51
|
*/
|
|
52
|
-
const os = __importStar(require("node:os"));
|
|
53
52
|
const path = __importStar(require("node:path"));
|
|
53
|
+
const os = __importStar(require("node:os"));
|
|
54
54
|
exports.IS_WINDOWS = os.type() === 'Windows_NT'; // array members for status results
|
|
55
55
|
// filenames were normalized when read from isogit
|
|
56
56
|
const toFilenames = (rows) => rows.map((row) => row[exports.FILE]);
|
|
@@ -59,8 +59,6 @@ const isDeleted = (status) => status[exports.WORKDIR] === 0;
|
|
|
59
59
|
exports.isDeleted = isDeleted;
|
|
60
60
|
const isAdded = (status) => status[exports.HEAD] === 0 && status[exports.WORKDIR] === 2;
|
|
61
61
|
exports.isAdded = isAdded;
|
|
62
|
-
const ensureWindows = (filepath) => path.win32.normalize(filepath);
|
|
63
|
-
exports.ensureWindows = ensureWindows;
|
|
64
62
|
const ensurePosix = (filepath) => filepath.split(path.sep).join(path.posix.sep);
|
|
65
63
|
exports.ensurePosix = ensurePosix;
|
|
66
64
|
// We don't use STAGE (StatusRow[3]). Changes are added and committed in one step
|
|
@@ -57,9 +57,7 @@ const os = __importStar(require("node:os"));
|
|
|
57
57
|
const fs = __importStar(require("graceful-fs"));
|
|
58
58
|
const core_1 = require("@salesforce/core");
|
|
59
59
|
const kit_1 = require("@salesforce/kit");
|
|
60
|
-
// @ts-expect-error isogit has both ESM and CJS exports but node16 module/resolution identifies it as ESM
|
|
61
60
|
const isomorphic_git_1 = __importDefault(require("isomorphic-git"));
|
|
62
|
-
const performance_1 = require("@oclif/core/performance");
|
|
63
61
|
const functions_1 = require("../functions");
|
|
64
62
|
const moveDetection_1 = require("./moveDetection");
|
|
65
63
|
const functions_2 = require("./functions");
|
|
@@ -74,7 +72,7 @@ const redirectToCliRepoError = (e) => {
|
|
|
74
72
|
}
|
|
75
73
|
throw e;
|
|
76
74
|
};
|
|
77
|
-
/** do not try to add more than this many files at a time through isogit. You'll hit EMFILE: too many open files
|
|
75
|
+
/** do not try to add more than this many files at a time through isogit. You'll hit EMFILE: too many open files */
|
|
78
76
|
const MAX_FILE_ADD = kit_1.env.getNumber('SF_SOURCE_TRACKING_BATCH_SIZE', kit_1.env.getNumber('SFDX_SOURCE_TRACKING_BATCH_SIZE', functions_2.IS_WINDOWS ? 8000 : 15_000));
|
|
79
77
|
class ShadowRepo {
|
|
80
78
|
static instanceMap = new Map();
|
|
@@ -133,12 +131,7 @@ class ShadowRepo {
|
|
|
133
131
|
* @returns the deleted directory
|
|
134
132
|
*/
|
|
135
133
|
async delete() {
|
|
136
|
-
|
|
137
|
-
await fs.promises.rm(this.gitDir, { recursive: true, force: true });
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
await fs.promises.rm(this.gitDir, { recursive: true });
|
|
141
|
-
}
|
|
134
|
+
await fs.promises.rm(this.gitDir, { recursive: true, force: true });
|
|
142
135
|
return this.gitDir;
|
|
143
136
|
}
|
|
144
137
|
/**
|
|
@@ -152,7 +145,6 @@ class ShadowRepo {
|
|
|
152
145
|
async getStatus(noCache = false) {
|
|
153
146
|
this.logger.trace(`start: getStatus (noCache = ${noCache})`);
|
|
154
147
|
if (!this.status || noCache) {
|
|
155
|
-
const marker = performance_1.Performance.mark('@salesforce/source-tracking', 'localShadowRepo.getStatus#withoutCache');
|
|
156
148
|
try {
|
|
157
149
|
// status hasn't been initialized yet
|
|
158
150
|
this.status = await isomorphic_git_1.default.statusMatrix({
|
|
@@ -179,7 +171,6 @@ class ShadowRepo {
|
|
|
179
171
|
catch (e) {
|
|
180
172
|
redirectToCliRepoError(e);
|
|
181
173
|
}
|
|
182
|
-
marker?.stop();
|
|
183
174
|
}
|
|
184
175
|
this.logger.trace(`done: getStatus (noCache = ${noCache})`);
|
|
185
176
|
return this.status;
|
|
@@ -243,10 +234,6 @@ class ShadowRepo {
|
|
|
243
234
|
// this is valid, might not be an error
|
|
244
235
|
return 'no files to commit';
|
|
245
236
|
}
|
|
246
|
-
const marker = performance_1.Performance.mark('@salesforce/source-tracking', 'localShadowRepo.commitChanges', {
|
|
247
|
-
deployedFiles: deployedFiles.length,
|
|
248
|
-
deletedFiles: deletedFiles.length,
|
|
249
|
-
});
|
|
250
237
|
if (deployedFiles.length) {
|
|
251
238
|
const chunks = (0, functions_1.chunkArray)(
|
|
252
239
|
// these are stored in posix/style/path format. We have to convert inbound stuff from windows
|
|
@@ -284,9 +271,6 @@ class ShadowRepo {
|
|
|
284
271
|
if (deletedFiles.length) {
|
|
285
272
|
// Using a cache here speeds up the performance by ~24.4%
|
|
286
273
|
let cache = {};
|
|
287
|
-
const deleteMarker = performance_1.Performance.mark('@salesforce/source-tracking', 'localShadowRepo.commitChanges#delete', {
|
|
288
|
-
deletedFiles: deletedFiles.length,
|
|
289
|
-
});
|
|
290
274
|
for (const filepath of [...new Set(functions_2.IS_WINDOWS ? deletedFiles.map(normalize).map(functions_2.ensurePosix) : deletedFiles)]) {
|
|
291
275
|
try {
|
|
292
276
|
// these need to be done sequentially because isogit manages file locking. Isogit remove does not support multiple files at once
|
|
@@ -299,7 +283,6 @@ class ShadowRepo {
|
|
|
299
283
|
}
|
|
300
284
|
// clear cache
|
|
301
285
|
cache = {};
|
|
302
|
-
deleteMarker?.stop();
|
|
303
286
|
}
|
|
304
287
|
try {
|
|
305
288
|
this.logger.trace('start: commitChanges git.commit');
|
|
@@ -320,29 +303,22 @@ class ShadowRepo {
|
|
|
320
303
|
catch (e) {
|
|
321
304
|
redirectToCliRepoError(e);
|
|
322
305
|
}
|
|
323
|
-
marker?.stop();
|
|
324
306
|
}
|
|
325
307
|
async detectMovedFiles() {
|
|
326
308
|
// get status will return os-specific paths
|
|
327
309
|
const matchingFiles = (0, moveDetection_1.getMatches)(await this.getStatus());
|
|
328
310
|
if (!matchingFiles.added.size || !matchingFiles.deleted.size)
|
|
329
311
|
return;
|
|
330
|
-
const movedFilesMarker = performance_1.Performance.mark('@salesforce/source-tracking', 'localShadowRepo.detectMovedFiles');
|
|
331
312
|
const matches = await (0, moveDetection_1.filenameMatchesToMap)(this.registry)(this.projectPath)(this.gitDir)(matchingFiles);
|
|
332
313
|
if (matches.deleteOnly.size === 0 && matches.fullMatches.size === 0)
|
|
333
|
-
return
|
|
314
|
+
return;
|
|
334
315
|
this.logger.debug((0, moveDetection_1.getLogMessage)(matches));
|
|
335
|
-
movedFilesMarker?.addDetails({
|
|
336
|
-
filesMoved: matches.fullMatches.size,
|
|
337
|
-
filesMovedAndEdited: matches.deleteOnly.size,
|
|
338
|
-
});
|
|
339
316
|
// Commit the moved files and refresh the status
|
|
340
317
|
await this.commitChanges({
|
|
341
318
|
deletedFiles: [...matches.fullMatches.values(), ...matches.deleteOnly.values()],
|
|
342
319
|
deployedFiles: [...matches.fullMatches.keys()],
|
|
343
320
|
message: 'Committing moved files',
|
|
344
321
|
});
|
|
345
|
-
movedFilesMarker?.stop();
|
|
346
322
|
}
|
|
347
323
|
}
|
|
348
324
|
exports.ShadowRepo = ShadowRepo;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RegistryAccess } from '@salesforce/source-deploy-retrieve';
|
|
2
|
-
import {
|
|
2
|
+
import { StatusRow, StringMap } from './types';
|
|
3
3
|
type AddedAndDeletedFilenames = {
|
|
4
4
|
added: Set<string>;
|
|
5
5
|
deleted: Set<string>;
|
|
@@ -15,7 +15,4 @@ export declare const filenameMatchesToMap: (registry: RegistryAccess) => (projec
|
|
|
15
15
|
/** compare delete and adds from git.status, matching basenames of the files. returns early when there's nothing to match */
|
|
16
16
|
export declare const getMatches: (status: StatusRow[]) => AddedAndDeletedFilenames;
|
|
17
17
|
export declare const getLogMessage: (matches: StringMapsForMatches) => string;
|
|
18
|
-
/** returns a map of <hash+basename, filepath>. If two items result in the same hash+basename, return that in the ignore bucket */
|
|
19
|
-
export declare const buildMap: (info: DetectionFileInfoWithType[]) => StringMap[];
|
|
20
|
-
export declare const toKey: (input: DetectionFileInfoWithType) => string;
|
|
21
18
|
export {};
|
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.
|
|
39
|
+
exports.getLogMessage = exports.getMatches = exports.filenameMatchesToMap = void 0;
|
|
40
40
|
/*
|
|
41
41
|
* Copyright 2025, Salesforce, Inc.
|
|
42
42
|
*
|
|
@@ -54,12 +54,10 @@ exports.toKey = exports.buildMap = exports.getLogMessage = exports.getMatches =
|
|
|
54
54
|
*/
|
|
55
55
|
const node_path_1 = __importDefault(require("node:path"));
|
|
56
56
|
const node_os_1 = require("node:os");
|
|
57
|
+
const fs = __importStar(require("graceful-fs"));
|
|
57
58
|
const core_1 = require("@salesforce/core");
|
|
58
59
|
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
59
|
-
// @ts-expect-error isogit has both ESM and CJS exports but node16 module/resolution identifies it as ESM
|
|
60
60
|
const isomorphic_git_1 = __importDefault(require("isomorphic-git"));
|
|
61
|
-
const fs = __importStar(require("graceful-fs"));
|
|
62
|
-
const performance_1 = require("@oclif/core/performance");
|
|
63
61
|
const guards_1 = require("../guards");
|
|
64
62
|
const functions_1 = require("../functions");
|
|
65
63
|
const functions_2 = require("./functions");
|
|
@@ -111,8 +109,8 @@ const getLogMessage = (matches) => [
|
|
|
111
109
|
exports.getLogMessage = getLogMessage;
|
|
112
110
|
/** build maps of the add/deletes with filenames, returning the matches Logs if we can't make a match because buildMap puts them in the ignored bucket */
|
|
113
111
|
const buildMaps = async ({ addedInfo, deletedInfo }) => {
|
|
114
|
-
const [addedMap, addedIgnoredMap] =
|
|
115
|
-
const [deletedMap, deletedIgnoredMap] =
|
|
112
|
+
const [addedMap, addedIgnoredMap] = buildMap(addedInfo);
|
|
113
|
+
const [deletedMap, deletedIgnoredMap] = buildMap(deletedInfo);
|
|
116
114
|
// If we detected any files that have the same basename and hash, emit a warning and send telemetry
|
|
117
115
|
// These files will still show up as expected in the `sf project deploy preview` output
|
|
118
116
|
// We could add more logic to determine and display filepaths that we ignored...
|
|
@@ -161,16 +159,11 @@ const compareHashes = ({ addedMap, deletedMap }) => {
|
|
|
161
159
|
/** enrich the filenames with basename and oid (hash) */
|
|
162
160
|
const toFileInfo = async ({ projectPath, gitDir, added, deleted, }) => {
|
|
163
161
|
// Track how long it takes to gather the oid information from the git trees
|
|
164
|
-
const getInfoMarker = performance_1.Performance.mark('@salesforce/source-tracking', 'localShadowRepo.detectMovedFiles#toFileInfo', {
|
|
165
|
-
addedFiles: added.size,
|
|
166
|
-
deletedFiles: deleted.size,
|
|
167
|
-
});
|
|
168
162
|
const headRef = await isomorphic_git_1.default.resolveRef({ fs, dir: projectPath, gitdir: gitDir, ref: 'HEAD' });
|
|
169
163
|
const [addedInfo, deletedInfo] = await Promise.all([
|
|
170
164
|
await Promise.all(Array.from(added).map(getHashForAddedFile(projectPath))),
|
|
171
165
|
await Promise.all(Array.from(deleted).map(getHashFromActualFileContents(gitDir)(projectPath)(headRef))),
|
|
172
166
|
]);
|
|
173
|
-
getInfoMarker?.stop();
|
|
174
167
|
return { addedInfo, deletedInfo };
|
|
175
168
|
};
|
|
176
169
|
/** returns a map of <hash+basename, filepath>. If two items result in the same hash+basename, return that in the ignore bucket */
|
|
@@ -178,7 +171,7 @@ const buildMap = (info) => {
|
|
|
178
171
|
const map = new Map();
|
|
179
172
|
const ignore = new Map();
|
|
180
173
|
info.map((i) => {
|
|
181
|
-
const key =
|
|
174
|
+
const key = toKey(i);
|
|
182
175
|
// If we find a duplicate key, we need to remove it and ignore it in the future.
|
|
183
176
|
// Finding duplicate hash#basename means that we cannot accurately determine where it was moved to or from
|
|
184
177
|
if (map.has(key) || ignore.has(key)) {
|
|
@@ -191,7 +184,6 @@ const buildMap = (info) => {
|
|
|
191
184
|
});
|
|
192
185
|
return [map, ignore];
|
|
193
186
|
};
|
|
194
|
-
exports.buildMap = buildMap;
|
|
195
187
|
const getHashForAddedFile = (projectPath) => async (filepath) => ({
|
|
196
188
|
filename: filepath,
|
|
197
189
|
basename: node_path_1.default.basename(filepath),
|
|
@@ -218,7 +210,6 @@ const getHashFromActualFileContents = (gitdir) => (projectPath) => (oid) => asyn
|
|
|
218
210
|
hash: (await isomorphic_git_1.default.readBlob({ fs, dir: projectPath, gitdir, filepath: functions_2.IS_WINDOWS ? (0, functions_2.ensurePosix)(filepath) : filepath, oid })).oid,
|
|
219
211
|
});
|
|
220
212
|
const toKey = (input) => [input.hash, input.basename, input.type, input.type, input.parentType ?? '', input.parentFullName ?? ''].join(JOIN_CHAR);
|
|
221
|
-
exports.toKey = toKey;
|
|
222
213
|
const removeHashFromEntry = ([k, v]) => [removeHashFromKey(k), v];
|
|
223
214
|
const removeHashFromKey = (hash) => hash.split(JOIN_CHAR).splice(1).join(JOIN_CHAR);
|
|
224
215
|
/** resolve the metadata types (and possibly parent components) */
|
|
@@ -62,7 +62,7 @@ const getNonSequential = ({ packageDirs, nonDeletes: nonDeletes, deletes: delete
|
|
|
62
62
|
path: packageDirs.map((dir) => dir.name).join(';'),
|
|
63
63
|
},
|
|
64
64
|
];
|
|
65
|
-
const getComponentSets = ({ groupings, sourceApiVersion, registry
|
|
65
|
+
const getComponentSets = ({ groupings, sourceApiVersion, registry, }) => {
|
|
66
66
|
const logger = core_1.Logger.childFromRoot('localComponentSetArray');
|
|
67
67
|
// optimistic resolution...some files may not be possible to resolve
|
|
68
68
|
const resolverForNonDeletes = new source_deploy_retrieve_1.MetadataResolver(registry);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RegistryAccess } from '@salesforce/source-deploy-retrieve';
|
|
2
2
|
import { RemoteSyncInput } from './types';
|
|
3
|
-
export declare const getMetadataKeyFromFileResponse: (fileResponse: RemoteSyncInput) => string[];
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const registrySupportsType: (registry
|
|
3
|
+
export declare const getMetadataKeyFromFileResponse: (registry: RegistryAccess) => (fileResponse: RemoteSyncInput) => string[];
|
|
4
|
+
export declare const getMappingsForSourceMemberTypesToMetadataType: (registry: RegistryAccess) => Map<string, string>;
|
|
5
|
+
export declare const registrySupportsType: (registry: RegistryAccess) => (type: string) => boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registrySupportsType = exports.
|
|
3
|
+
exports.registrySupportsType = exports.getMappingsForSourceMemberTypesToMetadataType = exports.getMetadataKeyFromFileResponse = void 0;
|
|
4
4
|
/*
|
|
5
5
|
* Copyright 2025, Salesforce, Inc.
|
|
6
6
|
*
|
|
@@ -25,16 +25,11 @@ const functions_1 = require("./functions");
|
|
|
25
25
|
const pathAfterFullName = (fileResponse) => fileResponse?.filePath
|
|
26
26
|
? (0, node_path_1.join)((0, node_path_1.dirname)(fileResponse.filePath).substring((0, node_path_1.dirname)(fileResponse.filePath).lastIndexOf(fileResponse.fullName)), (0, node_path_1.basename)(fileResponse.filePath)).replace(/\\/gi, '/')
|
|
27
27
|
: '';
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
const aliasTypes = registryAccess
|
|
31
|
-
.getAliasTypes()
|
|
32
|
-
// allow assertion because aliasTypes are defined as having that property
|
|
33
|
-
.map((aliasType) => [aliasType.name, registryAccess.getTypeByName(aliasType.aliasFor).name]);
|
|
34
|
-
const reverseAliasTypes = new Map(aliasTypes.map(([alias, type]) => [type, alias]));
|
|
28
|
+
const getAliasTypes = (registry) => registry.getAliasTypes().map((aliasType) => [aliasType.name, registry.getTypeByName(aliasType.aliasFor).name]);
|
|
29
|
+
const reverseStringMap = (original) => new Map(original.map(([k, v]) => [v, k]));
|
|
35
30
|
// handle all "weird" type/name translation between SourceMember and SDR FileResponse
|
|
36
31
|
// These get de-duplicated in a set later, so it's ok to have one per file
|
|
37
|
-
const getMetadataKeyFromFileResponse = (fileResponse) => {
|
|
32
|
+
const getMetadataKeyFromFileResponse = (registry) => (fileResponse) => {
|
|
38
33
|
// also create an element for the parent object
|
|
39
34
|
if (fileResponse.type === 'CustomField' && fileResponse.filePath) {
|
|
40
35
|
const splits = (0, node_path_1.normalize)(fileResponse.filePath).split(node_path_1.sep);
|
|
@@ -64,24 +59,26 @@ const getMetadataKeyFromFileResponse = (fileResponse) => {
|
|
|
64
59
|
.toArray()
|
|
65
60
|
.flatMap((component) => component.getChildren().map((child) => (0, functions_1.getMetadataKey)('CustomLabel', child.fullName)));
|
|
66
61
|
}
|
|
62
|
+
const reverseAliasTypesResult = reverseStringMap(getAliasTypes(registry));
|
|
67
63
|
// if we've aliased a type, we'll have to possibly sync both types--you can't tell from the sourceComponent retrieved which way it was stored on the server
|
|
68
|
-
if (
|
|
64
|
+
if (reverseAliasTypesResult.has(fileResponse.type)) {
|
|
69
65
|
return [
|
|
70
66
|
(0, functions_1.getMetadataKey)(fileResponse.type, fileResponse.fullName),
|
|
71
|
-
(0, functions_1.getMetadataKey)(
|
|
67
|
+
(0, functions_1.getMetadataKey)(reverseAliasTypesResult.get(fileResponse.type), fileResponse.fullName),
|
|
72
68
|
];
|
|
73
69
|
}
|
|
74
70
|
// standard key for everything else
|
|
75
71
|
return [(0, functions_1.getMetadataKey)(fileResponse.type, fileResponse.fullName)];
|
|
76
72
|
};
|
|
77
73
|
exports.getMetadataKeyFromFileResponse = getMetadataKeyFromFileResponse;
|
|
78
|
-
|
|
79
|
-
...
|
|
74
|
+
const getMappingsForSourceMemberTypesToMetadataType = (registry) => new Map([
|
|
75
|
+
...getAliasTypes(registry),
|
|
80
76
|
['AuraDefinition', 'AuraDefinitionBundle'],
|
|
81
77
|
['LightningComponentResource', 'LightningComponentBundle'],
|
|
82
78
|
]);
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
exports.getMappingsForSourceMemberTypesToMetadataType = getMappingsForSourceMemberTypesToMetadataType;
|
|
80
|
+
const registrySupportsType = (registry) => (type) => {
|
|
81
|
+
if ((0, exports.getMappingsForSourceMemberTypesToMetadataType)(registry).has(type)) {
|
|
85
82
|
return true;
|
|
86
83
|
}
|
|
87
84
|
if (type === 'PicklistValue') {
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { type RegistryAccess } from '@salesforce/source-deploy-retrieve';
|
|
2
|
+
import { type RemoteSyncInput } from '../types';
|
|
3
|
+
export declare const calculateExpectedSourceMembers: (registry: RegistryAccess, expectedMembers: RemoteSyncInput[]) => Map<string, RemoteSyncInput>;
|
|
@@ -58,8 +58,9 @@ const excludedKeys = [
|
|
|
58
58
|
'CustomTab###standard-mailapp',
|
|
59
59
|
'ApexEmailNotifications###apexEmailNotifications',
|
|
60
60
|
];
|
|
61
|
-
const calculateExpectedSourceMembers = (expectedMembers) => {
|
|
61
|
+
const calculateExpectedSourceMembers = (registry, expectedMembers) => {
|
|
62
62
|
const outstandingSourceMembers = new Map();
|
|
63
|
+
const getKeys = (0, metadataKeys_1.getMetadataKeyFromFileResponse)(registry);
|
|
63
64
|
expectedMembers
|
|
64
65
|
.filter((fileResponse) =>
|
|
65
66
|
// unchanged files will never be in the sourceMembers. Not really sure why SDR returns them.
|
|
@@ -84,7 +85,7 @@ const calculateExpectedSourceMembers = (expectedMembers) => {
|
|
|
84
85
|
!fileResponse.type.startsWith('Workflow') &&
|
|
85
86
|
!isSpecialAuraXml(fileResponse.filePath))
|
|
86
87
|
.map((member) => {
|
|
87
|
-
(
|
|
88
|
+
getKeys(member)
|
|
88
89
|
// remove some individual members known to not work with tracking even when their type does
|
|
89
90
|
.filter((key) =>
|
|
90
91
|
// CustomObject could have been re-added by the key generator from one of its fields
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RemoteChangeElement } from '../types';
|
|
2
|
-
import { ContentsV0, ContentsV1, MemberRevision
|
|
2
|
+
import { ContentsV0, ContentsV1, MemberRevision } from './types';
|
|
3
3
|
export declare const FILENAME = "maxRevision.json";
|
|
4
4
|
export declare const getFilePath: (orgId: string) => string;
|
|
5
5
|
export declare const readFileContents: (filePath: string) => Promise<ContentsV1 | Record<string, never>>;
|
|
@@ -10,4 +10,3 @@ export declare const writeTrackingFile: ({ filePath, maxCounter, members, }: {
|
|
|
10
10
|
maxCounter: number;
|
|
11
11
|
members: Map<string, MemberRevision>;
|
|
12
12
|
}) => Promise<void>;
|
|
13
|
-
export declare const toLegacyMemberRevision: ([, member]: [string, MemberRevision]) => [key: string, MemberRevisionLegacy];
|
|
@@ -1,9 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
39
|
+
exports.writeTrackingFile = exports.upgradeFileContents = exports.revisionToRemoteChangeElement = exports.readFileContents = exports.getFilePath = exports.FILENAME = void 0;
|
|
7
40
|
/*
|
|
8
41
|
* Copyright 2025, Salesforce, Inc.
|
|
9
42
|
*
|
|
@@ -19,8 +52,8 @@ exports.toLegacyMemberRevision = exports.writeTrackingFile = exports.upgradeFile
|
|
|
19
52
|
* See the License for the specific language governing permissions and
|
|
20
53
|
* limitations under the License.
|
|
21
54
|
*/
|
|
22
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
23
55
|
const node_path_1 = __importDefault(require("node:path"));
|
|
56
|
+
const fs = __importStar(require("graceful-fs"));
|
|
24
57
|
const kit_1 = require("@salesforce/kit");
|
|
25
58
|
const core_1 = require("@salesforce/core");
|
|
26
59
|
const functions_1 = require("../functions");
|
|
@@ -29,7 +62,7 @@ const getFilePath = (orgId) => node_path_1.default.join('.sf', 'orgs', orgId, ex
|
|
|
29
62
|
exports.getFilePath = getFilePath;
|
|
30
63
|
const readFileContents = async (filePath) => {
|
|
31
64
|
try {
|
|
32
|
-
const contents = await
|
|
65
|
+
const contents = await fs.promises.readFile(filePath, 'utf8');
|
|
33
66
|
const parsedContents = (0, kit_1.parseJsonMap)(contents, filePath);
|
|
34
67
|
if (parsedContents.fileVersion === 1) {
|
|
35
68
|
return parsedContents;
|
|
@@ -87,7 +120,7 @@ const writeTrackingFile = async ({ filePath, maxCounter, members, }) => {
|
|
|
87
120
|
: {
|
|
88
121
|
fileVersion: 0,
|
|
89
122
|
serverMaxRevisionCounter: maxCounter,
|
|
90
|
-
sourceMembers: Object.fromEntries(Array.from(members.entries()).map(
|
|
123
|
+
sourceMembers: Object.fromEntries(Array.from(members.entries()).map(toLegacyMemberRevision)),
|
|
91
124
|
};
|
|
92
125
|
await lockResult.writeAndUnlock(JSON.stringify(contents, null, 4));
|
|
93
126
|
};
|
|
@@ -101,5 +134,4 @@ const toLegacyMemberRevision = ([, member]) => [
|
|
|
101
134
|
isNameObsolete: member.IsNameObsolete,
|
|
102
135
|
},
|
|
103
136
|
];
|
|
104
|
-
exports.toLegacyMemberRevision = toLegacyMemberRevision;
|
|
105
137
|
//# sourceMappingURL=fileOperations.js.map
|
|
@@ -15,4 +15,3 @@ export declare const querySourceMembersFrom: ({ conn, fromRevision, queryCache,
|
|
|
15
15
|
/** if you don't pass in a logger, you get no log output */
|
|
16
16
|
logger?: PinoLogger;
|
|
17
17
|
}) => Promise<SourceMember[]>;
|
|
18
|
-
export declare const queryFn: (conn: Connection, query: string) => Promise<SourceMember[]>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.querySourceMembersFrom = exports.querySourceMembersTo = exports.calculateTimeout = void 0;
|
|
4
4
|
/*
|
|
5
5
|
* Copyright 2025, Salesforce, Inc.
|
|
6
6
|
*
|
|
@@ -36,7 +36,7 @@ exports.calculateTimeout = calculateTimeout;
|
|
|
36
36
|
/** exported only for spy/mock */
|
|
37
37
|
const querySourceMembersTo = async (conn, toRevision) => {
|
|
38
38
|
const query = `SELECT ${types_1.SOURCE_MEMBER_FIELDS.join(', ')} FROM SourceMember WHERE RevisionCounter <= ${toRevision}`;
|
|
39
|
-
return
|
|
39
|
+
return queryFn(conn, query);
|
|
40
40
|
};
|
|
41
41
|
exports.querySourceMembersTo = querySourceMembersTo;
|
|
42
42
|
const querySourceMembersFrom = async ({ conn, fromRevision, queryCache, userQueryCache, logger, }) => {
|
|
@@ -51,7 +51,7 @@ const querySourceMembersFrom = async ({ conn, fromRevision, queryCache, userQuer
|
|
|
51
51
|
// because `serverMaxRevisionCounter` is always updated, we need to select > to catch the most recent change
|
|
52
52
|
const query = `SELECT ${types_1.SOURCE_MEMBER_FIELDS.join(', ')} FROM SourceMember WHERE RevisionCounter > ${fromRevision}`;
|
|
53
53
|
logger?.debug(`Query: ${query}`);
|
|
54
|
-
const queryResult = await
|
|
54
|
+
const queryResult = await queryFn(conn, query);
|
|
55
55
|
if (userQueryCache) {
|
|
56
56
|
await updateCacheWithUnknownUsers(conn, queryResult, userQueryCache);
|
|
57
57
|
}
|
|
@@ -71,7 +71,6 @@ const queryFn = async (conn, query) => {
|
|
|
71
71
|
throw core_1.SfError.wrap(error);
|
|
72
72
|
}
|
|
73
73
|
};
|
|
74
|
-
exports.queryFn = queryFn;
|
|
75
74
|
/** A series of workarounds for server-side bugs. Each bug should be filed against a team, with a WI, so we know when these are fixed and can be removed */
|
|
76
75
|
const sourceMemberCorrections = (sourceMember) => {
|
|
77
76
|
if (sourceMember.MemberType === 'QuickActionDefinition') {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Logger, Org } from '@salesforce/core';
|
|
2
|
+
import { RegistryAccess } from '@salesforce/source-deploy-retrieve';
|
|
2
3
|
import { ChangeResult, RemoteChangeElement, RemoteSyncInput } from '../types';
|
|
3
4
|
export type PinoLogger = ReturnType<(typeof Logger)['getRawRootLogger']>;
|
|
4
5
|
/** Options for RemoteSourceTrackingService.getInstance */
|
|
5
|
-
|
|
6
|
+
type RemoteSourceTrackingServiceOptions = {
|
|
6
7
|
org: Org;
|
|
7
8
|
projectPath: string;
|
|
8
9
|
};
|
|
@@ -39,7 +40,7 @@ export declare class RemoteSourceTrackingService {
|
|
|
39
40
|
* pass in a series of SDR FilResponses .\
|
|
40
41
|
* it sets their last retrieved revision to the current revision counter from the server.
|
|
41
42
|
*/
|
|
42
|
-
syncSpecifiedElements(elements: RemoteSyncInput[]): Promise<void>;
|
|
43
|
+
syncSpecifiedElements(registry: RegistryAccess, elements: RemoteSyncInput[]): Promise<void>;
|
|
43
44
|
/**
|
|
44
45
|
* Resets source tracking state by first clearing all tracked data, then
|
|
45
46
|
* queries and synchronizes SourceMembers from the associated org.
|
|
@@ -66,7 +67,7 @@ export declare class RemoteSourceTrackingService {
|
|
|
66
67
|
* @param expectedMemberNames Array of metadata names to poll
|
|
67
68
|
* @param pollingTimeout maximum amount of time in seconds to poll for SourceMembers
|
|
68
69
|
*/
|
|
69
|
-
pollForSourceTracking(expectedMembers: RemoteSyncInput[]): Promise<void>;
|
|
70
|
+
pollForSourceTracking(registry: RegistryAccess, expectedMembers: RemoteSyncInput[]): Promise<void>;
|
|
70
71
|
/**
|
|
71
72
|
* Adds the given SourceMembers to the list of tracked MemberRevisions, optionally updating
|
|
72
73
|
* the lastRetrievedFromServer field (sync), and persists the changes to maxRevision.json.
|
|
@@ -82,4 +83,5 @@ export declare class RemoteSourceTrackingService {
|
|
|
82
83
|
* pass in an RCE, and this will return a pullable ChangeResult.
|
|
83
84
|
* Useful for correcing bundle types where the files show change results with types but aren't resolvable
|
|
84
85
|
*/
|
|
85
|
-
export declare const remoteChangeElementToChangeResult: (rce: RemoteChangeElement) => ChangeResult;
|
|
86
|
+
export declare const remoteChangeElementToChangeResult: (registry: RegistryAccess) => ((rce: RemoteChangeElement) => ChangeResult);
|
|
87
|
+
export {};
|