@salesforce/source-tracking 2.1.1 → 2.2.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/CHANGELOG.md +30 -0
- package/README.md +0 -26
- package/lib/index.d.ts +1 -1
- package/lib/index.js +3 -1
- package/lib/shared/conflicts.d.ts +16 -0
- package/lib/shared/conflicts.js +84 -0
- package/lib/shared/expectedSourceMembers.d.ts +2 -0
- package/lib/shared/expectedSourceMembers.js +76 -0
- package/lib/shared/functions.d.ts +2 -0
- package/lib/shared/functions.js +5 -1
- package/lib/shared/localComponentSetArray.d.ts +15 -0
- package/lib/shared/localComponentSetArray.js +84 -0
- package/lib/shared/localShadowRepo.js +1 -1
- package/lib/shared/metadataKeys.d.ts +1 -0
- package/lib/shared/metadataKeys.js +17 -1
- package/lib/shared/populateFilePaths.d.ts +9 -0
- package/lib/shared/populateFilePaths.js +77 -0
- package/lib/shared/populateTypesAndNames.d.ts +18 -0
- package/lib/shared/populateTypesAndNames.js +80 -0
- package/lib/shared/remoteSourceTrackingService.d.ts +0 -5
- package/lib/shared/remoteSourceTrackingService.js +3 -72
- package/lib/shared/types.d.ts +12 -4
- package/lib/shared/types.js +5 -0
- package/lib/sourceTracking.d.ts +81 -17
- package/lib/sourceTracking.js +167 -271
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,36 @@
|
|
|
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.1](https://github.com/forcedotcom/source-tracking/compare/v2.2.0...v2.2.1) (2022-07-05)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- bump core ([#180](https://github.com/forcedotcom/source-tracking/issues/180)) ([bf0c1f7](https://github.com/forcedotcom/source-tracking/commit/bf0c1f71f91701dacd2516914ab2abca33b1d00a))
|
|
10
|
+
|
|
11
|
+
## [2.2.0](https://github.com/forcedotcom/source-tracking/compare/v2.1.2...v2.2.0) (2022-06-29)
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
- event subscription and convenience method for push ([0c2135b](https://github.com/forcedotcom/source-tracking/commit/0c2135ba3076d3d7a3efd1e4d3c41a468e349728))
|
|
16
|
+
- local repo cache breaking for get status, and a generic method ([6645b72](https://github.com/forcedotcom/source-tracking/commit/6645b72c4695a15caca8aa6d3dc158a600fd15de))
|
|
17
|
+
- never track utam ([6e71f03](https://github.com/forcedotcom/source-tracking/commit/6e71f031c27c4e690d8538253b751da13da0b6e3))
|
|
18
|
+
- option to use SDR events ([d86f698](https://github.com/forcedotcom/source-tracking/commit/d86f69896185b68af7e489f6026589957e06f29d))
|
|
19
|
+
- top-level cache config of local cache behavior ([236ac28](https://github.com/forcedotcom/source-tracking/commit/236ac28314b45c42eff83b9ab8003d0c39efbbb0))
|
|
20
|
+
- track based on sdr events ([1238a68](https://github.com/forcedotcom/source-tracking/commit/1238a686f1d2c6091154ac6370c3d3d019c3a7a7))
|
|
21
|
+
|
|
22
|
+
### Bug Fixes
|
|
23
|
+
|
|
24
|
+
- async lifecycle subscribe ([75031f3](https://github.com/forcedotcom/source-tracking/commit/75031f3bbe753001a42f7abcfec1415bfb62547e))
|
|
25
|
+
- custom field was not polling correctly (logic error on del\_\_c) ([1ff2341](https://github.com/forcedotcom/source-tracking/commit/1ff23419d737cb2a22bcf070f5b2790b9ef0536d))
|
|
26
|
+
- logic on local ignored ([9667a6e](https://github.com/forcedotcom/source-tracking/commit/9667a6e8b442a6df0a42fd42dde4dfc289928f90))
|
|
27
|
+
- use fixed jsforce autoFetch, restore ut ([0b32d21](https://github.com/forcedotcom/source-tracking/commit/0b32d217013a346ef8826d3820566b7d70dba3c1))
|
|
28
|
+
|
|
29
|
+
### [2.1.2](https://github.com/forcedotcom/source-tracking/compare/v2.1.1...v2.1.2) (2022-06-23)
|
|
30
|
+
|
|
31
|
+
### Bug Fixes
|
|
32
|
+
|
|
33
|
+
- bump core for autofetch ([3567c69](https://github.com/forcedotcom/source-tracking/commit/3567c69dd49444ef757b9699bb676a0a1a25561c))
|
|
34
|
+
|
|
5
35
|
### [2.1.1](https://github.com/forcedotcom/source-tracking/compare/v2.1.0...v2.1.1) (2022-06-22)
|
|
6
36
|
|
|
7
37
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
JavaScript library for tracking local and remote Salesforce metadata changes.
|
|
4
4
|
|
|
5
|
-
**_ UNDER DEVELOPMENT _**
|
|
6
|
-
|
|
7
5
|
You should use the class named SourceTracking.
|
|
8
6
|
|
|
9
7
|
Start like this:
|
|
@@ -14,7 +12,6 @@ import { SourceTracking } from '@salesforce/source-tracking';
|
|
|
14
12
|
const tracking = await SourceTracking.create({
|
|
15
13
|
org: this.org, // Org from sfdx-core
|
|
16
14
|
project: this.project, // Project from sfdx-core
|
|
17
|
-
apiVersion: this.flags.apiversion as string, // can be undefined, will figure it out if you don't allow users to override
|
|
18
15
|
});
|
|
19
16
|
```
|
|
20
17
|
|
|
@@ -87,26 +84,3 @@ await tracking.updateRemoteTracking(
|
|
|
87
84
|
false
|
|
88
85
|
);
|
|
89
86
|
```
|
|
90
|
-
|
|
91
|
-
## TODO
|
|
92
|
-
|
|
93
|
-
NUT for tracking file compatibility check logic
|
|
94
|
-
pollSourceMembers should better handle aggregated types. ex:
|
|
95
|
-
|
|
96
|
-
```txt
|
|
97
|
-
DEBUG Could not find 2 SourceMembers (using ebikes): AuraDefinition__pageTemplate_2_7_3/pageTemplate_2_7_3.cmp-meta.xml,[object Object],CustomObject__Account,[object Object]
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Enhancements
|
|
101
|
-
|
|
102
|
-
- for updating ST after deploy/retrieve, we need a quick way for those commands to ask, "is this an ST org?" OR a graceful "ifSupported" wrapper for those methods.
|
|
103
|
-
- ensureRemoteTracking could have 2 options in an object
|
|
104
|
-
1. `ensureQueryHasReturned` which will make sure the query has run at least once
|
|
105
|
-
2. `forceQuery` will re-query even if the query already ran (cache-buster typically)
|
|
106
|
-
|
|
107
|
-
### Cleanup
|
|
108
|
-
|
|
109
|
-
- review commented code
|
|
110
|
-
- review public methods for whether they should be public
|
|
111
|
-
- organize any shared types
|
|
112
|
-
- export top-level stuff
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export * from './sourceTracking';
|
|
2
2
|
export * from './compatibility';
|
|
3
|
-
export { RemoteSyncInput, ChangeOptionType, ChangeOptions, LocalUpdateOptions, ChangeResult,
|
|
3
|
+
export { RemoteSyncInput, ChangeOptionType, ChangeOptions, LocalUpdateOptions, ChangeResult, StatusOutputRow, ConflictResponse, SourceConflictError, } from './shared/types';
|
|
4
4
|
export { getKeyFromObject } from './shared/functions';
|
package/lib/index.js
CHANGED
|
@@ -20,9 +20,11 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
20
20
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
21
21
|
};
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.getKeyFromObject = void 0;
|
|
23
|
+
exports.getKeyFromObject = exports.SourceConflictError = void 0;
|
|
24
24
|
__exportStar(require("./sourceTracking"), exports);
|
|
25
25
|
__exportStar(require("./compatibility"), exports);
|
|
26
|
+
var types_1 = require("./shared/types");
|
|
27
|
+
Object.defineProperty(exports, "SourceConflictError", { enumerable: true, get: function () { return types_1.SourceConflictError; } });
|
|
26
28
|
var functions_1 = require("./shared/functions");
|
|
27
29
|
Object.defineProperty(exports, "getKeyFromObject", { enumerable: true, get: function () { return functions_1.getKeyFromObject; } });
|
|
28
30
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ComponentSet, ForceIgnore } from '@salesforce/source-deploy-retrieve';
|
|
2
|
+
import { ConflictResponse, ChangeResult } from './types';
|
|
3
|
+
export declare const throwIfConflicts: (conflicts: ConflictResponse[]) => void;
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param cs ComponentSet to compare
|
|
7
|
+
* @param conflicts ChangeResult[] representing conflicts from SourceTracking.getConflicts
|
|
8
|
+
* @returns ConflictResponse[] de-duped and formatted for json or table display
|
|
9
|
+
*/
|
|
10
|
+
export declare const findConflictsInComponentSet: (cs: ComponentSet, conflicts: ChangeResult[]) => ConflictResponse[];
|
|
11
|
+
export declare const getDedupedConflictsFromChanges: ({ localChanges, remoteChanges, projectPath, forceIgnore, }: {
|
|
12
|
+
localChanges: ChangeResult[];
|
|
13
|
+
remoteChanges: ChangeResult[];
|
|
14
|
+
projectPath: string;
|
|
15
|
+
forceIgnore: ForceIgnore;
|
|
16
|
+
}) => ChangeResult[];
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDedupedConflictsFromChanges = exports.findConflictsInComponentSet = exports.throwIfConflicts = void 0;
|
|
4
|
+
/*
|
|
5
|
+
* Copyright (c) 2020, salesforce.com, inc.
|
|
6
|
+
* All rights reserved.
|
|
7
|
+
* Licensed under the BSD 3-Clause license.
|
|
8
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
9
|
+
*/
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const types_1 = require("./types");
|
|
12
|
+
const functions_1 = require("./functions");
|
|
13
|
+
const populateTypesAndNames_1 = require("./populateTypesAndNames");
|
|
14
|
+
const throwIfConflicts = (conflicts) => {
|
|
15
|
+
if (conflicts.length > 0) {
|
|
16
|
+
const conflictError = new types_1.SourceConflictError(`${conflicts.length} conflicts detected`, 'SourceConflictError');
|
|
17
|
+
conflictError.setData(conflicts);
|
|
18
|
+
throw conflictError;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.throwIfConflicts = throwIfConflicts;
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @param cs ComponentSet to compare
|
|
25
|
+
* @param conflicts ChangeResult[] representing conflicts from SourceTracking.getConflicts
|
|
26
|
+
* @returns ConflictResponse[] de-duped and formatted for json or table display
|
|
27
|
+
*/
|
|
28
|
+
const findConflictsInComponentSet = (cs, conflicts) => {
|
|
29
|
+
// map do dedupe by name-type-filename
|
|
30
|
+
const conflictMap = new Map();
|
|
31
|
+
conflicts
|
|
32
|
+
.filter((cr) => cr.name && cr.type && cs.has({ fullName: cr.name, type: cr.type }))
|
|
33
|
+
.forEach((cr) => {
|
|
34
|
+
var _a;
|
|
35
|
+
(_a = cr.filenames) === null || _a === void 0 ? void 0 : _a.forEach((f) => {
|
|
36
|
+
conflictMap.set(`${cr.name}#${cr.type}#${f}`, {
|
|
37
|
+
state: 'Conflict',
|
|
38
|
+
// the following 2 type assertions are valid because of previous filter statement
|
|
39
|
+
// they can be removed once TS is smarter about filtering
|
|
40
|
+
fullName: cr.name,
|
|
41
|
+
type: cr.type,
|
|
42
|
+
filePath: (0, path_1.resolve)(f),
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
const reformattedConflicts = Array.from(conflictMap.values());
|
|
47
|
+
return reformattedConflicts;
|
|
48
|
+
};
|
|
49
|
+
exports.findConflictsInComponentSet = findConflictsInComponentSet;
|
|
50
|
+
const getDedupedConflictsFromChanges = ({ localChanges = [], remoteChanges = [], projectPath, forceIgnore, }) => {
|
|
51
|
+
// index the remoteChanges by filename
|
|
52
|
+
const fileNameIndex = new Map();
|
|
53
|
+
const metadataKeyIndex = new Map();
|
|
54
|
+
remoteChanges.map((change) => {
|
|
55
|
+
var _a;
|
|
56
|
+
if (change.name && change.type) {
|
|
57
|
+
metadataKeyIndex.set((0, functions_1.getMetadataKey)(change.name, change.type), change);
|
|
58
|
+
}
|
|
59
|
+
(_a = change.filenames) === null || _a === void 0 ? void 0 : _a.map((filename) => {
|
|
60
|
+
fileNameIndex.set(filename, change);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
const conflicts = new Set();
|
|
64
|
+
(0, populateTypesAndNames_1.populateTypesAndNames)({ elements: localChanges, excludeUnresolvable: true, projectPath, forceIgnore }).map((change) => {
|
|
65
|
+
var _a;
|
|
66
|
+
const metadataKey = (0, functions_1.getMetadataKey)(change.name, change.type);
|
|
67
|
+
// option 1: name and type match
|
|
68
|
+
if (metadataKeyIndex.has(metadataKey)) {
|
|
69
|
+
conflicts.add({ ...metadataKeyIndex.get(metadataKey) });
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// option 2: some of the filenames match
|
|
73
|
+
(_a = change.filenames) === null || _a === void 0 ? void 0 : _a.map((filename) => {
|
|
74
|
+
if (fileNameIndex.has(filename)) {
|
|
75
|
+
conflicts.add({ ...fileNameIndex.get(filename) });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
// deeply de-dupe
|
|
81
|
+
return Array.from(conflicts);
|
|
82
|
+
};
|
|
83
|
+
exports.getDedupedConflictsFromChanges = getDedupedConflictsFromChanges;
|
|
84
|
+
//# sourceMappingURL=conflicts.js.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2020, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.calculateExpectedSourceMembers = void 0;
|
|
10
|
+
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
11
|
+
const metadataKeys_1 = require("./metadataKeys");
|
|
12
|
+
const typesToNoPollFor = [
|
|
13
|
+
'CustomObject',
|
|
14
|
+
'EmailFolder',
|
|
15
|
+
'EmailTemplateFolder',
|
|
16
|
+
'StandardValueSet',
|
|
17
|
+
'Portal',
|
|
18
|
+
'StandardValueSetTranslation',
|
|
19
|
+
'SharingRules',
|
|
20
|
+
'SharingCriteriaRule',
|
|
21
|
+
'GlobalValueSetTranslation',
|
|
22
|
+
'AssignmentRules',
|
|
23
|
+
'InstalledPackage',
|
|
24
|
+
];
|
|
25
|
+
const typesNotToPollForIfNamespace = ['CustomLabels', 'CustomMetadata', 'DuplicateRule', 'WebLink'];
|
|
26
|
+
const isEncodedTypeWithPercentSign = (type, filePath) => ['Layout', 'Profile', 'HomePageComponent', 'HomePageLayout', 'MilestoneType'].includes(type) &&
|
|
27
|
+
Boolean(filePath === null || filePath === void 0 ? void 0 : filePath.includes('%'));
|
|
28
|
+
// aura xml aren't tracked as SourceMembers
|
|
29
|
+
const isSpecialAuraXml = (filePath) => Boolean(filePath &&
|
|
30
|
+
(filePath.endsWith('.cmp-meta.xml') ||
|
|
31
|
+
filePath.endsWith('.tokens-meta.xml') ||
|
|
32
|
+
filePath.endsWith('.evt-meta.xml') ||
|
|
33
|
+
filePath.endsWith('.app-meta.xml') ||
|
|
34
|
+
filePath.endsWith('.intf-meta.xml')));
|
|
35
|
+
const calculateExpectedSourceMembers = (expectedMembers) => {
|
|
36
|
+
const outstandingSourceMembers = new Map();
|
|
37
|
+
expectedMembers
|
|
38
|
+
.filter((fileResponse) => {
|
|
39
|
+
var _a, _b, _c, _d;
|
|
40
|
+
// unchanged files will never be in the sourceMembers. Not really sure why SDR returns them.
|
|
41
|
+
return fileResponse.state !== source_deploy_retrieve_1.ComponentStatus.Unchanged &&
|
|
42
|
+
// 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
|
|
43
|
+
// we don't know which email folder type might be there, so don't require either
|
|
44
|
+
// Portal doesn't support source tracking, according to the coverage report
|
|
45
|
+
!typesToNoPollFor.includes(fileResponse.type) &&
|
|
46
|
+
// don't wait for standard fields on standard objects
|
|
47
|
+
!(fileResponse.type === 'CustomField' && !((_a = fileResponse.filePath) === null || _a === void 0 ? void 0 : _a.includes('__c'))) &&
|
|
48
|
+
// deleted fields
|
|
49
|
+
!(fileResponse.type === 'CustomField' && ((_b = fileResponse.filePath) === null || _b === void 0 ? void 0 : _b.includes('_del__c'))) &&
|
|
50
|
+
// built-in report type ReportType__screen_flows_prebuilt_crt
|
|
51
|
+
!(fileResponse.type === 'ReportType' && ((_c = fileResponse.filePath) === null || _c === void 0 ? void 0 : _c.includes('screen_flows_prebuilt_crt'))) &&
|
|
52
|
+
// they're settings to mdapi, and FooSettings in sourceMembers
|
|
53
|
+
!fileResponse.type.includes('Settings') &&
|
|
54
|
+
// mdapi encodes these, sourceMembers don't have encoding
|
|
55
|
+
!isEncodedTypeWithPercentSign(fileResponse.type, fileResponse.filePath) &&
|
|
56
|
+
!(typesNotToPollForIfNamespace.includes(fileResponse.type) && ((_d = fileResponse.filePath) === null || _d === void 0 ? void 0 : _d.includes('__'))) &&
|
|
57
|
+
// don't wait on workflow children
|
|
58
|
+
!fileResponse.type.startsWith('Workflow') &&
|
|
59
|
+
!isSpecialAuraXml(fileResponse.filePath);
|
|
60
|
+
})
|
|
61
|
+
.map((member) => {
|
|
62
|
+
(0, metadataKeys_1.getMetadataKeyFromFileResponse)(member)
|
|
63
|
+
// remove some individual members known to not work with tracking even when their type does
|
|
64
|
+
.filter((key) =>
|
|
65
|
+
// CustomObject could have been re-added by the key generator from one of its fields
|
|
66
|
+
!key.startsWith('CustomObject') &&
|
|
67
|
+
key !== 'Profile__Standard' &&
|
|
68
|
+
key !== 'CustomTab__standard-home' &&
|
|
69
|
+
key !== 'AssignmentRules__Case' &&
|
|
70
|
+
key !== 'ListView__CollaborationGroup.All_ChatterGroups')
|
|
71
|
+
.map((key) => outstandingSourceMembers.set(key, member));
|
|
72
|
+
});
|
|
73
|
+
return outstandingSourceMembers;
|
|
74
|
+
};
|
|
75
|
+
exports.calculateExpectedSourceMembers = calculateExpectedSourceMembers;
|
|
76
|
+
//# sourceMappingURL=expectedSourceMembers.js.map
|
|
@@ -3,9 +3,11 @@ import { RemoteChangeElement, ChangeResult } from './types';
|
|
|
3
3
|
export declare const getMetadataKey: (metadataType: string, metadataName: string) => string;
|
|
4
4
|
export declare const getKeyFromObject: (element: RemoteChangeElement | ChangeResult) => string;
|
|
5
5
|
export declare const isBundle: (cmp: SourceComponent) => boolean;
|
|
6
|
+
export declare const isLwcLocalOnlyTest: (filePath: string) => boolean;
|
|
6
7
|
/**
|
|
7
8
|
* Verify that a filepath starts exactly with a complete parent path
|
|
8
9
|
* ex: '/foo/bar-extra/baz'.startsWith('foo/bar') would be true, but this function understands that they are not in the same folder
|
|
9
10
|
*/
|
|
10
11
|
export declare const pathIsInFolder: (filePath: string, folder: string) => boolean;
|
|
11
12
|
export declare const chunkArray: <T>(arr: T[], size: number) => T[][];
|
|
13
|
+
export declare const ensureRelative: (filePath: string, projectPath: string) => string;
|
package/lib/shared/functions.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.chunkArray = exports.pathIsInFolder = exports.isBundle = exports.getKeyFromObject = exports.getMetadataKey = void 0;
|
|
9
|
+
exports.ensureRelative = exports.chunkArray = exports.pathIsInFolder = exports.isLwcLocalOnlyTest = exports.isBundle = exports.getKeyFromObject = exports.getMetadataKey = void 0;
|
|
10
10
|
const path_1 = require("path");
|
|
11
11
|
const ts_types_1 = require("@salesforce/ts-types");
|
|
12
12
|
const getMetadataKey = (metadataType, metadataName) => {
|
|
@@ -22,6 +22,8 @@ const getKeyFromObject = (element) => {
|
|
|
22
22
|
exports.getKeyFromObject = getKeyFromObject;
|
|
23
23
|
const isBundle = (cmp) => { var _a; return ((_a = cmp.type.strategies) === null || _a === void 0 ? void 0 : _a.adapter) === 'bundle'; };
|
|
24
24
|
exports.isBundle = isBundle;
|
|
25
|
+
const isLwcLocalOnlyTest = (filePath) => filePath.includes('__utam__') || filePath.includes('__tests__');
|
|
26
|
+
exports.isLwcLocalOnlyTest = isLwcLocalOnlyTest;
|
|
25
27
|
/**
|
|
26
28
|
* Verify that a filepath starts exactly with a complete parent path
|
|
27
29
|
* ex: '/foo/bar-extra/baz'.startsWith('foo/bar') would be true, but this function understands that they are not in the same folder
|
|
@@ -40,4 +42,6 @@ const nonEmptyStringFilter = (value) => {
|
|
|
40
42
|
// adapted for TS from https://github.com/30-seconds/30-seconds-of-code/blob/master/snippets/chunk.md
|
|
41
43
|
const chunkArray = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size));
|
|
42
44
|
exports.chunkArray = chunkArray;
|
|
45
|
+
const ensureRelative = (filePath, projectPath) => (0, path_1.isAbsolute)(filePath) ? (0, path_1.relative)(projectPath, filePath) : filePath;
|
|
46
|
+
exports.ensureRelative = ensureRelative;
|
|
43
47
|
//# sourceMappingURL=functions.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { NamedPackageDir } from '@salesforce/core';
|
|
2
|
+
import { ComponentSet } from '@salesforce/source-deploy-retrieve';
|
|
3
|
+
interface GroupedFileInput {
|
|
4
|
+
packageDirs: NamedPackageDir[];
|
|
5
|
+
nonDeletes: string[];
|
|
6
|
+
deletes: string[];
|
|
7
|
+
}
|
|
8
|
+
interface GroupedFile {
|
|
9
|
+
path: string;
|
|
10
|
+
nonDeletes: string[];
|
|
11
|
+
deletes: string[];
|
|
12
|
+
}
|
|
13
|
+
export declare const getGroupedFiles: (input: GroupedFileInput, byPackageDir?: boolean) => GroupedFile[];
|
|
14
|
+
export declare const getComponentSets: (groupings: GroupedFile[], sourceApiVersion?: string) => ComponentSet[];
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getComponentSets = exports.getGroupedFiles = void 0;
|
|
4
|
+
/*
|
|
5
|
+
* Copyright (c) 2020, salesforce.com, inc.
|
|
6
|
+
* All rights reserved.
|
|
7
|
+
* Licensed under the BSD 3-Clause license.
|
|
8
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
9
|
+
*/
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const path_1 = require("path");
|
|
12
|
+
const core_1 = require("@salesforce/core");
|
|
13
|
+
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
14
|
+
const guards_1 = require("./guards");
|
|
15
|
+
const functions_1 = require("./functions");
|
|
16
|
+
const getGroupedFiles = (input, byPackageDir = false) => {
|
|
17
|
+
return (byPackageDir ? getSequential(input) : getNonSequential(input)).filter((group) => group.deletes.length || group.nonDeletes.length);
|
|
18
|
+
};
|
|
19
|
+
exports.getGroupedFiles = getGroupedFiles;
|
|
20
|
+
const getSequential = ({ packageDirs, nonDeletes, deletes }) => packageDirs.map((pkgDir) => ({
|
|
21
|
+
path: pkgDir.name,
|
|
22
|
+
nonDeletes: nonDeletes.filter((f) => (0, functions_1.pathIsInFolder)(f, pkgDir.name)),
|
|
23
|
+
deletes: deletes.filter((f) => (0, functions_1.pathIsInFolder)(f, pkgDir.name)),
|
|
24
|
+
}));
|
|
25
|
+
const getNonSequential = ({ packageDirs, nonDeletes: nonDeletes, deletes: deletes, }) => [
|
|
26
|
+
{
|
|
27
|
+
nonDeletes,
|
|
28
|
+
deletes,
|
|
29
|
+
path: packageDirs.map((dir) => dir.name).join(';'),
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
const getComponentSets = (groupings, sourceApiVersion) => {
|
|
33
|
+
const logger = core_1.Logger.childFromRoot('localComponentSetArray');
|
|
34
|
+
// optimistic resolution...some files may not be possible to resolve
|
|
35
|
+
const resolverForNonDeletes = new source_deploy_retrieve_1.MetadataResolver();
|
|
36
|
+
return groupings
|
|
37
|
+
.map((grouping) => {
|
|
38
|
+
logger.debug(`building componentSet for ${grouping.path} (deletes: ${grouping.deletes.length} nonDeletes: ${grouping.nonDeletes.length})`);
|
|
39
|
+
const componentSet = new source_deploy_retrieve_1.ComponentSet();
|
|
40
|
+
if (sourceApiVersion) {
|
|
41
|
+
componentSet.sourceApiVersion = sourceApiVersion;
|
|
42
|
+
}
|
|
43
|
+
// we need virtual components for the deletes.
|
|
44
|
+
// TODO: could we use the same for the non-deletes?
|
|
45
|
+
const resolverForDeletes = new source_deploy_retrieve_1.MetadataResolver(undefined, source_deploy_retrieve_1.VirtualTreeContainer.fromFilePaths(grouping.deletes));
|
|
46
|
+
grouping.deletes
|
|
47
|
+
.flatMap((filename) => resolverForDeletes.getComponentsFromPath(filename))
|
|
48
|
+
.filter(guards_1.sourceComponentGuard)
|
|
49
|
+
.map((component) => {
|
|
50
|
+
// if the component is a file in a bundle type AND there are files from the bundle that are not deleted, set the bundle for deploy, not for delete
|
|
51
|
+
if ((0, functions_1.isBundle)(component) && component.content && fs.existsSync(component.content)) {
|
|
52
|
+
// all bundle types have a directory name
|
|
53
|
+
try {
|
|
54
|
+
resolverForNonDeletes
|
|
55
|
+
.getComponentsFromPath((0, path_1.resolve)(component.content))
|
|
56
|
+
.filter(guards_1.sourceComponentGuard)
|
|
57
|
+
.map((nonDeletedComponent) => componentSet.add(nonDeletedComponent));
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
logger.warn(`unable to find component at ${component.content}. That's ok if it was supposed to be deleted`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
componentSet.add(component, source_deploy_retrieve_1.DestructiveChangesType.POST);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
grouping.nonDeletes
|
|
68
|
+
.flatMap((filename) => {
|
|
69
|
+
try {
|
|
70
|
+
return resolverForNonDeletes.getComponentsFromPath((0, path_1.resolve)(filename));
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
logger.warn(`unable to resolve ${filename}`);
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
.filter(guards_1.sourceComponentGuard)
|
|
78
|
+
.map((component) => componentSet.add(component));
|
|
79
|
+
return componentSet;
|
|
80
|
+
})
|
|
81
|
+
.filter((componentSet) => componentSet.size > 0);
|
|
82
|
+
};
|
|
83
|
+
exports.getComponentSets = getComponentSets;
|
|
84
|
+
//# sourceMappingURL=localComponentSetArray.js.map
|
|
@@ -97,7 +97,7 @@ class ShadowRepo {
|
|
|
97
97
|
// no hidden files
|
|
98
98
|
!f.includes(`${path.sep}.`) &&
|
|
99
99
|
// no lwc tests
|
|
100
|
-
!
|
|
100
|
+
!(0, functions_1.isLwcLocalOnlyTest)(f) &&
|
|
101
101
|
// no gitignore files
|
|
102
102
|
!f.endsWith('.gitignore') &&
|
|
103
103
|
// isogit uses `startsWith` for filepaths so it's possible to get a false positive
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { RemoteSyncInput } from './types';
|
|
2
2
|
export declare const getMetadataKeyFromFileResponse: (fileResponse: RemoteSyncInput) => string[];
|
|
3
3
|
export declare const mappingsForSourceMemberTypesToMetadataType: Map<string, string>;
|
|
4
|
+
export declare const registrySupportsType: (type: string) => boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.mappingsForSourceMemberTypesToMetadataType = exports.getMetadataKeyFromFileResponse = void 0;
|
|
3
|
+
exports.registrySupportsType = exports.mappingsForSourceMemberTypesToMetadataType = exports.getMetadataKeyFromFileResponse = void 0;
|
|
4
4
|
/*
|
|
5
5
|
* Copyright (c) 2020, salesforce.com, inc.
|
|
6
6
|
* All rights reserved.
|
|
@@ -9,6 +9,7 @@ exports.mappingsForSourceMemberTypesToMetadataType = exports.getMetadataKeyFromF
|
|
|
9
9
|
*/
|
|
10
10
|
const path_1 = require("path");
|
|
11
11
|
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
12
|
+
const core_1 = require("@salesforce/core");
|
|
12
13
|
const functions_1 = require("./functions");
|
|
13
14
|
// See UT for examples of the complexity this must handle
|
|
14
15
|
// keys always use forward slashes, even on Windows
|
|
@@ -69,4 +70,19 @@ exports.mappingsForSourceMemberTypesToMetadataType = new Map([
|
|
|
69
70
|
['AuraDefinition', 'AuraDefinitionBundle'],
|
|
70
71
|
['LightningComponentResource', 'LightningComponentBundle'],
|
|
71
72
|
]);
|
|
73
|
+
const registrySupportsType = (type) => {
|
|
74
|
+
try {
|
|
75
|
+
if (exports.mappingsForSourceMemberTypesToMetadataType.has(type)) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
// this must use getTypeByName because findType doesn't support addressable child types (ex: customField!)
|
|
79
|
+
registry.getTypeByName(type);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
void core_1.Lifecycle.getInstance().emitWarning(`Unable to find type ${type} in registry`);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
exports.registrySupportsType = registrySupportsType;
|
|
72
88
|
//# sourceMappingURL=metadataKeys.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ChangeResult } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Will build a component set, crawling your local directory, to get paths for remote changes
|
|
4
|
+
*
|
|
5
|
+
* @param elements ChangeResults that may or may not have filepaths in their filenames parameters
|
|
6
|
+
* @param packageDirPaths Array of paths from PackageDirectories
|
|
7
|
+
* @returns
|
|
8
|
+
*/
|
|
9
|
+
export declare const populateFilePaths: (elements: ChangeResult[], packageDirPaths: string[]) => ChangeResult[];
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.populateFilePaths = void 0;
|
|
4
|
+
/*
|
|
5
|
+
* Copyright (c) 2020, salesforce.com, inc.
|
|
6
|
+
* All rights reserved.
|
|
7
|
+
* Licensed under the BSD 3-Clause license.
|
|
8
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
9
|
+
*/
|
|
10
|
+
const os_1 = require("os");
|
|
11
|
+
const core_1 = require("@salesforce/core");
|
|
12
|
+
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
13
|
+
const guards_1 = require("./guards");
|
|
14
|
+
const functions_1 = require("./functions");
|
|
15
|
+
const logger = core_1.Logger.childFromRoot('SourceTracking.PopulateFilePaths');
|
|
16
|
+
/**
|
|
17
|
+
* Will build a component set, crawling your local directory, to get paths for remote changes
|
|
18
|
+
*
|
|
19
|
+
* @param elements ChangeResults that may or may not have filepaths in their filenames parameters
|
|
20
|
+
* @param packageDirPaths Array of paths from PackageDirectories
|
|
21
|
+
* @returns
|
|
22
|
+
*/
|
|
23
|
+
const populateFilePaths = (elements, packageDirPaths) => {
|
|
24
|
+
if (elements.length === 0) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
logger.debug('populateFilePaths for change elements', elements);
|
|
28
|
+
// component set generated from an array of MetadataMember from all the remote changes
|
|
29
|
+
// but exclude the ones that aren't in the registry
|
|
30
|
+
const remoteChangesAsMetadataMember = elements
|
|
31
|
+
.map((element) => {
|
|
32
|
+
if (typeof element.type === 'string' && typeof element.name === 'string') {
|
|
33
|
+
return {
|
|
34
|
+
type: element.type,
|
|
35
|
+
fullName: element.name,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
.filter(guards_1.metadataMemberGuard);
|
|
40
|
+
const remoteChangesAsComponentSet = new source_deploy_retrieve_1.ComponentSet(remoteChangesAsMetadataMember);
|
|
41
|
+
logger.debug(` the generated component set has ${remoteChangesAsComponentSet.size.toString()} items`);
|
|
42
|
+
if (remoteChangesAsComponentSet.size < elements.length) {
|
|
43
|
+
// there *could* be something missing
|
|
44
|
+
// some types (ex: LWC) show up as multiple files in the remote changes, but only one in the component set
|
|
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 === null || element === void 0 ? void 0 : element.type, fullName: element === null || element === void 0 ? void 0 : element.name }));
|
|
47
|
+
// Throw if anything was actually missing
|
|
48
|
+
if (missingComponents.length > 0) {
|
|
49
|
+
throw new Error(`unable to generate complete component set for ${elements
|
|
50
|
+
.map((element) => `${element.name} (${element.type})`)
|
|
51
|
+
.join(os_1.EOL)}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const matchingLocalSourceComponentsSet = source_deploy_retrieve_1.ComponentSet.fromSource({
|
|
55
|
+
fsPaths: packageDirPaths,
|
|
56
|
+
include: remoteChangesAsComponentSet,
|
|
57
|
+
});
|
|
58
|
+
logger.debug(` local source-backed component set has ${matchingLocalSourceComponentsSet.size.toString()} items from remote`);
|
|
59
|
+
// make it simpler to find things later
|
|
60
|
+
const elementMap = new Map(elements.map((e) => [(0, functions_1.getKeyFromObject)(e), e]));
|
|
61
|
+
// iterates the local components and sets their filenames
|
|
62
|
+
for (const matchingComponent of matchingLocalSourceComponentsSet.getSourceComponents().toArray()) {
|
|
63
|
+
if (matchingComponent.fullName && matchingComponent.type.name) {
|
|
64
|
+
logger.debug(`${matchingComponent.fullName}|${matchingComponent.type.name} matches ${matchingComponent.xml} and maybe ${matchingComponent.walkContent().toString()}`);
|
|
65
|
+
const key = (0, functions_1.getMetadataKey)(matchingComponent.type.name, matchingComponent.fullName);
|
|
66
|
+
elementMap.set(key, {
|
|
67
|
+
...elementMap.get(key),
|
|
68
|
+
modified: true,
|
|
69
|
+
origin: 'remote',
|
|
70
|
+
filenames: [matchingComponent.xml, ...matchingComponent.walkContent()].filter((filename) => filename),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return Array.from(elementMap.values());
|
|
75
|
+
};
|
|
76
|
+
exports.populateFilePaths = populateFilePaths;
|
|
77
|
+
//# sourceMappingURL=populateFilePaths.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ForceIgnore } from '@salesforce/source-deploy-retrieve';
|
|
2
|
+
import { ChangeResult } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* uses SDR to translate remote metadata records into local file paths (which only typically have the filename).
|
|
5
|
+
*
|
|
6
|
+
* @input elements: ChangeResult[]
|
|
7
|
+
* @input projectPath
|
|
8
|
+
* @input forceIgnore: ForceIgnore. If provided, result will indicate whether the file is ignored
|
|
9
|
+
* @input excludeUnresolvable: boolean Filter out components where you can't get the name and type (that is, it's probably not a valid source component)
|
|
10
|
+
* @input resolveDeleted: constructs a virtualTree instead of the actual filesystem--useful when the files no longer exist
|
|
11
|
+
*/
|
|
12
|
+
export declare const populateTypesAndNames: ({ elements, projectPath, forceIgnore, excludeUnresolvable, resolveDeleted, }: {
|
|
13
|
+
elements: ChangeResult[];
|
|
14
|
+
projectPath: string;
|
|
15
|
+
forceIgnore?: ForceIgnore | undefined;
|
|
16
|
+
excludeUnresolvable?: boolean | undefined;
|
|
17
|
+
resolveDeleted?: boolean | undefined;
|
|
18
|
+
}) => ChangeResult[];
|