@salesforce/source-tracking 1.1.7 → 1.3.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 +23 -0
- package/lib/compatibility.js +11 -6
- package/lib/shared/functions.d.ts +1 -0
- package/lib/shared/functions.js +4 -1
- package/lib/shared/localShadowRepo.d.ts +3 -4
- package/lib/shared/localShadowRepo.js +62 -79
- package/messages/compatibility.json +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
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
|
+
### [1.3.1](https://github.com/forcedotcom/source-tracking/compare/v1.3.0...v1.3.1) (2022-03-25)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- tracking really large repos in chunks, lower limit for windows ([0cb2ce5](https://github.com/forcedotcom/source-tracking/commit/0cb2ce5f3b65b8be9f4e4210aba010e919f692a3))
|
|
10
|
+
|
|
11
|
+
## [1.3.0](https://github.com/forcedotcom/source-tracking/compare/v1.2.0...v1.3.0) (2022-03-25)
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
- gracful-fs for EMFILE: too many open files ([1573828](https://github.com/forcedotcom/source-tracking/commit/1573828f5b3cf5f4f8b2023ff31b5764214d4b06))
|
|
16
|
+
|
|
17
|
+
## [1.2.0](https://github.com/forcedotcom/source-tracking/compare/v1.1.7...v1.2.0) (2022-03-23)
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
- let isogit deal with ignore files ([#135](https://github.com/forcedotcom/source-tracking/issues/135)) ([1ddb2cd](https://github.com/forcedotcom/source-tracking/commit/1ddb2cdb8f23688f7bb4876a893097a85581f4c1))
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
- ga tracking commands compatibility ([3a31a0d](https://github.com/forcedotcom/source-tracking/commit/3a31a0de448993c643ea4661a7a37772e46e8f51))
|
|
26
|
+
- support pkgDir with ./foo ([3b46454](https://github.com/forcedotcom/source-tracking/commit/3b46454b3e57f653cbe80c66fbfee1cac121c2a8))
|
|
27
|
+
|
|
5
28
|
### [1.1.7](https://github.com/forcedotcom/source-tracking/compare/v1.1.6...v1.1.7) (2022-03-16)
|
|
6
29
|
|
|
7
30
|
### Bug Fixes
|
package/lib/compatibility.js
CHANGED
|
@@ -57,13 +57,18 @@ const throwIfInvalid = ({ org, projectPath, toValidate, command, }) => {
|
|
|
57
57
|
throw new core_1.SfdxError(`${messages.getMessage('sourceTrackingFileVersionMismatch', ['new/beta'])}\n\nTry this:\n${messages.getMessage('useOtherVersion', ['new/beta', (0, exports.replaceRenamedCommands)(command.replace(':legacy', ''))])}.\n${messages.getMessage('clearSuggestion', [
|
|
58
58
|
'new/beta',
|
|
59
59
|
(0, exports.replaceRenamedCommands)('sfdx force:source:tracking:clear'),
|
|
60
|
+
(0, exports.replaceRenamedCommands)('sfdx force:source:tracking:reset', true),
|
|
60
61
|
])}.`, 'SourceTrackingFileVersionMismatch');
|
|
61
62
|
}
|
|
62
63
|
// We expected it to be the plugin-source version but it is using the old tracking files
|
|
63
64
|
if (toValidate === 'plugin-source') {
|
|
64
65
|
throw new core_1.SfdxError(messages.getMessage('sourceTrackingFileVersionMismatch', ['old/legacy']), 'SourceTrackingFileVersionMismatch', [
|
|
65
66
|
messages.getMessage('useOtherVersion', ['old/legacy', (0, exports.replaceRenamedCommands)(command, true)]),
|
|
66
|
-
messages.getMessage('clearSuggestion', [
|
|
67
|
+
messages.getMessage('clearSuggestion', [
|
|
68
|
+
'old/legacy',
|
|
69
|
+
'sfdx force:source:legacy:tracking:clear',
|
|
70
|
+
'sfdx force:source:tracking:reset',
|
|
71
|
+
]),
|
|
67
72
|
]);
|
|
68
73
|
}
|
|
69
74
|
};
|
|
@@ -82,10 +87,10 @@ const replaceRenamedCommands = (input, reverse = false) => {
|
|
|
82
87
|
};
|
|
83
88
|
exports.replaceRenamedCommands = replaceRenamedCommands;
|
|
84
89
|
const renames = new Map([
|
|
85
|
-
['force:source:status', 'force:source:
|
|
86
|
-
['force:source:push', 'force:source:
|
|
87
|
-
['force:source:pull', 'force:source:
|
|
88
|
-
['force:source:tracking:reset', 'force:source:
|
|
89
|
-
['force:source:tracking:clear', 'force:source:
|
|
90
|
+
['force:source:legacy:status', 'force:source:status'],
|
|
91
|
+
['force:source:legacy:push', 'force:source:push'],
|
|
92
|
+
['force:source:legacy:pull', 'force:source:pull'],
|
|
93
|
+
['force:source:legacy:tracking:reset', 'force:source:tracking:reset'],
|
|
94
|
+
['force:source:legacy:tracking:clear', 'force:source:tracking:clear'],
|
|
90
95
|
]);
|
|
91
96
|
//# sourceMappingURL=compatibility.js.map
|
|
@@ -8,3 +8,4 @@ export declare const isBundle: (cmp: SourceComponent) => boolean;
|
|
|
8
8
|
* ex: '/foo/bar-extra/baz'.startsWith('foo/bar') would be true, but this function understands that they are not in the same folder
|
|
9
9
|
*/
|
|
10
10
|
export declare const pathIsInFolder: (filePath: string, folder: string) => boolean;
|
|
11
|
+
export declare const chunkArray: <T>(arr: T[], size: number) => T[][];
|
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.pathIsInFolder = exports.isBundle = exports.getKeyFromObject = exports.getMetadataKey = void 0;
|
|
9
|
+
exports.chunkArray = exports.pathIsInFolder = 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) => {
|
|
@@ -37,4 +37,7 @@ exports.pathIsInFolder = pathIsInFolder;
|
|
|
37
37
|
const nonEmptyStringFilter = (value) => {
|
|
38
38
|
return (0, ts_types_1.isString)(value) && value.length > 0;
|
|
39
39
|
};
|
|
40
|
+
// adapted for TS from https://github.com/30-seconds/30-seconds-of-code/blob/master/snippets/chunk.md
|
|
41
|
+
const chunkArray = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size));
|
|
42
|
+
exports.chunkArray = chunkArray;
|
|
40
43
|
//# sourceMappingURL=functions.js.map
|
|
@@ -18,7 +18,9 @@ export declare class ShadowRepo {
|
|
|
18
18
|
private packageDirs;
|
|
19
19
|
private status;
|
|
20
20
|
private logger;
|
|
21
|
-
private
|
|
21
|
+
private isWindows;
|
|
22
|
+
/** do not try to add more than this many files at a time through isogit. You'll hit EMFILE: too many open files even with graceful-fs */
|
|
23
|
+
private maxFileAdd;
|
|
22
24
|
private constructor();
|
|
23
25
|
static getInstance(options: ShadowRepoOptions): Promise<ShadowRepo>;
|
|
24
26
|
init(): Promise<void>;
|
|
@@ -76,8 +78,5 @@ export declare class ShadowRepo {
|
|
|
76
78
|
* @returns sha (string)
|
|
77
79
|
*/
|
|
78
80
|
commitChanges({ deployedFiles, deletedFiles, message, needsUpdatedStatus, }?: CommitRequest): Promise<string>;
|
|
79
|
-
private locateIgnoreFiles;
|
|
80
|
-
private stashIgnoreFile;
|
|
81
|
-
private unStashIgnoreFile;
|
|
82
81
|
}
|
|
83
82
|
export {};
|
|
@@ -5,20 +5,15 @@
|
|
|
5
5
|
* Licensed under the BSD 3-Clause license.
|
|
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
|
-
/* eslint-disable no-console */
|
|
9
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
9
|
exports.ShadowRepo = void 0;
|
|
11
10
|
const path = require("path");
|
|
12
11
|
const os = require("os");
|
|
13
|
-
const fs = require("fs");
|
|
12
|
+
const fs = require("graceful-fs");
|
|
14
13
|
const core_1 = require("@salesforce/core");
|
|
15
14
|
const git = require("isomorphic-git");
|
|
16
15
|
const functions_1 = require("./functions");
|
|
17
|
-
|
|
18
|
-
const stashedGitIgnoreFileName = '.BAK.gitignore';
|
|
19
|
-
/**
|
|
20
|
-
* returns the full path to where we store the shadow repo
|
|
21
|
-
*/
|
|
16
|
+
/** returns the full path to where we store the shadow repo */
|
|
22
17
|
const getGitDir = (orgId, projectPath) => {
|
|
23
18
|
return path.join(projectPath, '.sfdx', 'orgs', orgId, 'localSourceTracking');
|
|
24
19
|
};
|
|
@@ -30,10 +25,11 @@ const HEAD = 1;
|
|
|
30
25
|
const WORKDIR = 2;
|
|
31
26
|
class ShadowRepo {
|
|
32
27
|
constructor(options) {
|
|
33
|
-
this.gitIgnoreLocations = [];
|
|
34
28
|
this.gitDir = getGitDir(options.orgId, options.projectPath);
|
|
35
29
|
this.projectPath = options.projectPath;
|
|
36
30
|
this.packageDirs = options.packageDirs;
|
|
31
|
+
this.isWindows = os.type() === 'Windows_NT';
|
|
32
|
+
this.maxFileAdd = this.isWindows ? 8000 : 15000;
|
|
37
33
|
}
|
|
38
34
|
// think of singleton behavior but unique to the projectPath
|
|
39
35
|
static async getInstance(options) {
|
|
@@ -51,7 +47,6 @@ class ShadowRepo {
|
|
|
51
47
|
this.logger.debug('initializing git repo');
|
|
52
48
|
await this.gitInit();
|
|
53
49
|
}
|
|
54
|
-
await this.locateIgnoreFiles();
|
|
55
50
|
}
|
|
56
51
|
/**
|
|
57
52
|
* Initialize a new source tracking shadow repo. Think of git init
|
|
@@ -86,37 +81,32 @@ class ShadowRepo {
|
|
|
86
81
|
*/
|
|
87
82
|
async getStatus(noCache = false) {
|
|
88
83
|
if (!this.status || noCache) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
this.status = this.status.map((row) => [path.normalize(row[FILE]), row[HEAD], row[WORKDIR], row[3]]);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
finally {
|
|
119
|
-
await this.unStashIgnoreFile();
|
|
84
|
+
// iso-git uses relative, posix paths
|
|
85
|
+
// but packageDirs has already resolved / normalized them
|
|
86
|
+
// so we need to make them project-relative again and convert if windows
|
|
87
|
+
const filepaths = this.packageDirs
|
|
88
|
+
.map((dir) => path.relative(this.projectPath, dir.fullPath))
|
|
89
|
+
.map((p) => (this.isWindows ? p.split(path.sep).join(path.posix.sep) : p));
|
|
90
|
+
// status hasn't been initalized yet
|
|
91
|
+
this.status = await git.statusMatrix({
|
|
92
|
+
fs,
|
|
93
|
+
dir: this.projectPath,
|
|
94
|
+
gitdir: this.gitDir,
|
|
95
|
+
filepaths,
|
|
96
|
+
ignored: true,
|
|
97
|
+
filter: (f) =>
|
|
98
|
+
// no hidden files
|
|
99
|
+
!f.includes(`${path.sep}.`) &&
|
|
100
|
+
// no lwc tests
|
|
101
|
+
!f.includes('__tests__') &&
|
|
102
|
+
// no gitignore files
|
|
103
|
+
!f.endsWith('.gitignore') &&
|
|
104
|
+
// isogit uses `startsWith` for filepaths so it's possible to get a false positive
|
|
105
|
+
filepaths.some((pkgDir) => (0, functions_1.pathIsInFolder)(f, pkgDir)),
|
|
106
|
+
});
|
|
107
|
+
// isomorphic-git stores things in unix-style tree. Convert to windows-style if necessary
|
|
108
|
+
if (this.isWindows) {
|
|
109
|
+
this.status = this.status.map((row) => [path.normalize(row[FILE]), row[HEAD], row[WORKDIR], row[3]]);
|
|
120
110
|
}
|
|
121
111
|
}
|
|
122
112
|
return this.status;
|
|
@@ -180,56 +170,49 @@ class ShadowRepo {
|
|
|
180
170
|
// this is valid, might not be an error
|
|
181
171
|
return 'no files to commit';
|
|
182
172
|
}
|
|
183
|
-
await this.stashIgnoreFile();
|
|
184
173
|
// these are stored in posix/style/path format. We have to convert inbound stuff from windows
|
|
185
174
|
if (os.type() === 'Windows_NT') {
|
|
186
175
|
deployedFiles = deployedFiles.map((filepath) => path.normalize(filepath).split(path.sep).join(path.posix.sep));
|
|
187
176
|
deletedFiles = deletedFiles.map((filepath) => path.normalize(filepath).split(path.sep).join(path.posix.sep));
|
|
188
177
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
178
|
+
if (deployedFiles.length) {
|
|
179
|
+
const chunks = (0, functions_1.chunkArray)([...new Set(deployedFiles)], this.maxFileAdd);
|
|
180
|
+
for (const chunk of chunks) {
|
|
181
|
+
try {
|
|
182
|
+
await git.add({
|
|
183
|
+
fs,
|
|
184
|
+
dir: this.projectPath,
|
|
185
|
+
gitdir: this.gitDir,
|
|
186
|
+
filepath: chunk,
|
|
187
|
+
force: true,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
catch (e) {
|
|
191
|
+
if (e instanceof git.Errors.MultipleGitError) {
|
|
192
|
+
this.logger.error('multiple errors on git.add', e.errors.slice(0, 5));
|
|
193
|
+
const error = new core_1.SfdxError(e.message, e.name, [], 1);
|
|
194
|
+
error.setData(e.errors);
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
throw e;
|
|
198
|
+
}
|
|
206
199
|
}
|
|
207
|
-
return sha;
|
|
208
200
|
}
|
|
209
|
-
|
|
210
|
-
await this.
|
|
201
|
+
for (const filepath of [...new Set(deletedFiles)]) {
|
|
202
|
+
await git.remove({ fs, dir: this.projectPath, gitdir: this.gitDir, filepath });
|
|
211
203
|
}
|
|
212
|
-
|
|
213
|
-
async locateIgnoreFiles() {
|
|
214
|
-
// set the gitIgnoreLocations so we only have to do it once
|
|
215
|
-
this.gitIgnoreLocations = (await git.walk({
|
|
204
|
+
const sha = await git.commit({
|
|
216
205
|
fs,
|
|
217
206
|
dir: this.projectPath,
|
|
218
207
|
gitdir: this.gitDir,
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
// allSettled allows them to fail (example, the file wasn't where it was expected).
|
|
228
|
-
await Promise.allSettled(this.gitIgnoreLocations.map((originalLocation) => fs.promises.rename(originalLocation, originalLocation.replace(gitIgnoreFileName, stashedGitIgnoreFileName))));
|
|
229
|
-
}
|
|
230
|
-
async unStashIgnoreFile() {
|
|
231
|
-
// allSettled allows them to fail (example, the file wasn't where it was expected).
|
|
232
|
-
await Promise.allSettled(this.gitIgnoreLocations.map((originalLocation) => fs.promises.rename(originalLocation.replace(gitIgnoreFileName, stashedGitIgnoreFileName), originalLocation)));
|
|
208
|
+
message,
|
|
209
|
+
author: { name: 'sfdx source tracking' },
|
|
210
|
+
});
|
|
211
|
+
// status changed as a result of the commit. This prevents users from having to run getStatus(true) to avoid cache
|
|
212
|
+
if (needsUpdatedStatus) {
|
|
213
|
+
await this.getStatus(true);
|
|
214
|
+
}
|
|
215
|
+
return sha;
|
|
233
216
|
}
|
|
234
217
|
}
|
|
235
218
|
exports.ShadowRepo = ShadowRepo;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"sourceTrackingFileVersionMismatch": "This project uses the %s version of source tracking files.",
|
|
3
|
-
"clearSuggestion": "
|
|
3
|
+
"clearSuggestion": "Push/Pull any local or remote changes. Then, clear the %s version of the tracking files by running '%s' followed by '%s'.",
|
|
4
4
|
"useOtherVersion": "Use the %s version of the command, '%s' with your existing tracking files."
|
|
5
5
|
}
|
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": "1.1
|
|
4
|
+
"version": "1.3.1",
|
|
5
5
|
"author": "Salesforce",
|
|
6
6
|
"license": "BSD-3-Clause",
|
|
7
7
|
"main": "lib/index.js",
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"@salesforce/core": "^2.33.1",
|
|
47
47
|
"@salesforce/kit": "^1.5.17",
|
|
48
48
|
"@salesforce/source-deploy-retrieve": "^5.9.4",
|
|
49
|
-
"
|
|
49
|
+
"graceful-fs": "^4.2.9",
|
|
50
|
+
"isomorphic-git": "1.17.0",
|
|
50
51
|
"ts-retry-promise": "^0.6.0"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|