@jayree/sfdx-plugin-manifest 2.9.0 → 3.0.0
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 +21 -0
- package/README.md +91 -6
- package/lib/commands/jayree/manifest/git/diff.d.ts +23 -20
- package/lib/commands/jayree/manifest/git/diff.js +87 -584
- package/lib/commands/jayree/manifest/git/diff.js.map +1 -1
- package/lib/commands/jayree/manifest/legacy/git/diff.d.ts +37 -0
- package/lib/commands/jayree/manifest/legacy/git/diff.js +640 -0
- package/lib/commands/jayree/manifest/legacy/git/diff.js.map +1 -0
- package/oclif.manifest.json +22 -14
- package/package.json +22 -14
- package/schemas/jayree-manifest-git-diff.json +24 -5
- package/schemas/jayree-manifest-legacy-git-diff.json +19 -0
- package/lib/commands/jayree/manifest/beta/git/diff.d.ts +0 -38
- package/lib/commands/jayree/manifest/beta/git/diff.js +0 -141
- package/lib/commands/jayree/manifest/beta/git/diff.js.map +0 -1
- package/schemas/jayree-manifest-beta-git-diff.json +0 -38
@@ -4,179 +4,108 @@
|
|
4
4
|
* Licensed under the BSD 3-Clause license.
|
5
5
|
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
6
6
|
*/
|
7
|
-
import { join,
|
7
|
+
import { join, dirname } from 'node:path';
|
8
8
|
import { fileURLToPath } from 'node:url';
|
9
|
-
import {
|
10
|
-
import { SfCommand, Flags, arrayWithDeprecation } from '@salesforce/sf-plugins-core';
|
11
|
-
import { Messages, SfError, SfProject } from '@salesforce/core';
|
12
|
-
import { Args } from '@oclif/core';
|
9
|
+
import { Messages } from '@salesforce/core';
|
13
10
|
import fs from 'fs-extra';
|
14
|
-
import {
|
15
|
-
import {
|
11
|
+
import { DestructiveChangesType } from '@salesforce/source-deploy-retrieve';
|
12
|
+
import { SfCommand, Flags, orgApiVersionFlagWithDeprecations, arrayWithDeprecation } from '@salesforce/sf-plugins-core';
|
13
|
+
import { Args } from '@oclif/core';
|
16
14
|
import { getString } from '@salesforce/ts-types';
|
17
|
-
import
|
18
|
-
import { ComponentSet, RegistryAccess, registry, VirtualTreeContainer, MetadataResolver, DestructiveChangesType, } from '@salesforce/source-deploy-retrieve';
|
19
|
-
import { parseMetadataXml } from '@salesforce/source-deploy-retrieve/lib/src/utils/index.js';
|
20
|
-
import Debug from 'debug';
|
21
|
-
import git from 'isomorphic-git';
|
15
|
+
import { ComponentSetExtra } from '../../../../SDR-extra/index.js';
|
22
16
|
// eslint-disable-next-line no-underscore-dangle
|
23
17
|
const __filename = fileURLToPath(import.meta.url);
|
24
18
|
// eslint-disable-next-line no-underscore-dangle
|
25
19
|
const __dirname = dirname(__filename);
|
26
20
|
Messages.importMessagesDirectory(__dirname);
|
27
21
|
const messages = Messages.loadMessages('@jayree/sfdx-plugin-manifest', 'gitdiff');
|
28
|
-
|
29
|
-
|
30
|
-
const registryAccess = new RegistryAccess();
|
31
|
-
export default class GitDiff extends SfCommand {
|
22
|
+
export default class GitDiffCommand extends SfCommand {
|
23
|
+
// eslint-disable-next-line sf-plugin/should-parse-flags
|
32
24
|
async run() {
|
33
|
-
|
34
|
-
|
35
|
-
|
25
|
+
await this.createManifest();
|
26
|
+
return this.formatResult();
|
27
|
+
}
|
28
|
+
async getSourceApiVersion() {
|
29
|
+
const projectConfig = await this.project.resolveProjectConfig();
|
30
|
+
return getString(projectConfig, 'sourceApiVersion') ?? undefined;
|
31
|
+
}
|
32
|
+
async createManifest() {
|
33
|
+
const { flags, args } = await this.parse(GitDiffCommand);
|
34
|
+
this.manifestName = 'package.xml';
|
35
|
+
this.destructiveChangesName = 'destructiveChanges.xml';
|
36
36
|
this.outputDir = flags['output-dir'];
|
37
|
-
this.
|
38
|
-
this.
|
39
|
-
|
40
|
-
|
41
|
-
debug({
|
42
|
-
outputDir: this.outputDir,
|
43
|
-
projectRoot: this.projectRoot,
|
37
|
+
this.destructiveChangesOnly = flags['destructive-changes-only'];
|
38
|
+
this.componentSet = await ComponentSetExtra.fromGitDiff({
|
39
|
+
ref: [args.ref1, args.ref2],
|
40
|
+
fsPaths: flags['source-dir'],
|
44
41
|
});
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
title: `ref1: ${gitArgs.ref1}`,
|
79
|
-
task: async () => {
|
80
|
-
this.ref1VirtualTreeContainer = await createVirtualTreeContainer(gitArgs.ref1, this.projectRoot, this.gitLines.filter((l) => l.status === 'M').map((l) => l.path));
|
81
|
-
},
|
82
|
-
},
|
83
|
-
{
|
84
|
-
title: gitArgs.ref2 !== '' ? `ref2: ${gitArgs.ref2}` : 'ref2: (staging area)',
|
85
|
-
task: async () => {
|
86
|
-
this.ref2VirtualTreeContainer = await createVirtualTreeContainer(gitArgs.ref2, this.projectRoot, this.gitLines.filter((l) => l.status === 'M').map((l) => l.path));
|
87
|
-
},
|
88
|
-
},
|
89
|
-
], { concurrent: true }),
|
90
|
-
},
|
91
|
-
{
|
92
|
-
title: 'Analyze git diff results',
|
93
|
-
skip: () => !this.gitLines.length,
|
94
|
-
task: async (ctx, task) => {
|
95
|
-
if (sourcepath) {
|
96
|
-
this.fsPaths = sourcepath.map((filepath) => {
|
97
|
-
filepath = resolve(filepath);
|
98
|
-
if (!this.ref1VirtualTreeContainer.exists(filepath) &&
|
99
|
-
!this.ref2VirtualTreeContainer.exists(filepath)) {
|
100
|
-
throw new SfError(`The sourcepath "${filepath}" is not a valid source file path.`);
|
101
|
-
}
|
102
|
-
return filepath;
|
103
|
-
});
|
104
|
-
debug(`fsPaths: ${this.fsPaths.join(', ')}`);
|
42
|
+
this.componentSet.sourceApiVersion = flags['api-version'] ?? (await this.getSourceApiVersion());
|
43
|
+
if (this.outputDir) {
|
44
|
+
await fs.ensureDir(this.outputDir);
|
45
|
+
this.outputPath = join(this.outputDir, this.manifestName);
|
46
|
+
}
|
47
|
+
else {
|
48
|
+
this.outputPath = this.manifestName;
|
49
|
+
}
|
50
|
+
if (this.componentSet.size) {
|
51
|
+
if (this.componentSet.getTypesOfDestructiveChanges().length) {
|
52
|
+
await fs.writeFile(join(this.outputDir, this.destructiveChangesName), await this.componentSet.getPackageXml(undefined, DestructiveChangesType.POST));
|
53
|
+
}
|
54
|
+
if (this.destructiveChangesOnly) {
|
55
|
+
if (this.componentSet.getTypesOfDestructiveChanges().length) {
|
56
|
+
const emptyCompSet = new ComponentSetExtra();
|
57
|
+
emptyCompSet.sourceApiVersion = this.componentSet.sourceApiVersion;
|
58
|
+
return fs.writeFile(this.outputPath, await emptyCompSet.getPackageXml());
|
59
|
+
}
|
60
|
+
return;
|
61
|
+
}
|
62
|
+
return fs.writeFile(this.outputPath, await this.componentSet.getPackageXml());
|
63
|
+
}
|
64
|
+
}
|
65
|
+
formatResult() {
|
66
|
+
if (!this.jsonEnabled()) {
|
67
|
+
if (this.componentSet.size) {
|
68
|
+
if (this.destructiveChangesOnly && !this.componentSet.getTypesOfDestructiveChanges().length) {
|
69
|
+
this.log(messages.getMessage('noComponents'));
|
70
|
+
}
|
71
|
+
else if (this.outputDir) {
|
72
|
+
this.log(messages.getMessage('successOutputDir', [this.manifestName, this.outputDir]));
|
73
|
+
if (this.componentSet.getTypesOfDestructiveChanges().length) {
|
74
|
+
this.log(messages.getMessage('successOutputDir', [this.destructiveChangesName, this.outputDir]));
|
105
75
|
}
|
106
|
-
|
107
|
-
|
108
|
-
this.
|
109
|
-
|
110
|
-
|
111
|
-
this.componentSet.sourceApiVersion = this.sourceApiVersion;
|
112
|
-
},
|
113
|
-
options: { persistentOutput: true },
|
114
|
-
},
|
115
|
-
{
|
116
|
-
// title: 'Error output',
|
117
|
-
skip: () => !this.outputErrors?.length,
|
118
|
-
task: (ctx, task) => {
|
119
|
-
debug({ errors: this.outputErrors });
|
120
|
-
const moreErrors = this.outputErrors.splice(5);
|
121
|
-
for (const message of this.outputErrors) {
|
122
|
-
task.output = `Error: ${message}`;
|
76
|
+
}
|
77
|
+
else {
|
78
|
+
this.log(messages.getMessage('success', [this.manifestName]));
|
79
|
+
if (this.componentSet.getTypesOfDestructiveChanges().length) {
|
80
|
+
this.log(messages.getMessage('success', [this.destructiveChangesName]));
|
123
81
|
}
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
task: (ctx, task) => task.newListr([
|
132
|
-
{
|
133
|
-
title: this.manifest,
|
134
|
-
skip: () => !this.isOutputEnabled,
|
135
|
-
task: async () => {
|
136
|
-
await fs.ensureDir(dirname(this.manifest));
|
137
|
-
await fs.writeFile(this.manifest, await this.componentSet.getPackageXml());
|
138
|
-
},
|
139
|
-
options: { persistentOutput: true },
|
140
|
-
},
|
141
|
-
{
|
142
|
-
title: this.destructiveChanges,
|
143
|
-
skip: () => !this.componentSet.getTypesOfDestructiveChanges().length || !this.isOutputEnabled,
|
144
|
-
task: async () => {
|
145
|
-
await fs.ensureDir(dirname(this.destructiveChanges));
|
146
|
-
await fs.writeFile(this.destructiveChanges, await this.componentSet.getPackageXml(undefined, DestructiveChangesType.POST));
|
147
|
-
},
|
148
|
-
options: { persistentOutput: true },
|
149
|
-
},
|
150
|
-
], { concurrent: true }),
|
151
|
-
},
|
152
|
-
], {
|
153
|
-
rendererOptions: { showTimer: true, collapse: false, lazy: true, collapseErrors: false },
|
154
|
-
rendererSilent: !this.isOutputEnabled,
|
155
|
-
rendererFallback: debug.enabled,
|
156
|
-
});
|
157
|
-
try {
|
158
|
-
await tasks.run();
|
82
|
+
}
|
83
|
+
}
|
84
|
+
else {
|
85
|
+
this.log(messages.getMessage('noComponents'));
|
86
|
+
}
|
87
|
+
}
|
88
|
+
if (this.componentSet.getTypesOfDestructiveChanges().length) {
|
159
89
|
return {
|
160
|
-
|
161
|
-
|
90
|
+
manifest: { path: this.outputPath, name: this.manifestName },
|
91
|
+
destructiveChanges: {
|
92
|
+
path: join(this.outputDir, this.destructiveChangesName),
|
93
|
+
name: this.destructiveChangesName,
|
94
|
+
},
|
162
95
|
};
|
163
96
|
}
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
97
|
+
else if (this.componentSet.size && !this.destructiveChangesOnly) {
|
98
|
+
return { manifest: { path: this.outputPath, name: this.manifestName } };
|
99
|
+
}
|
100
|
+
else {
|
101
|
+
return {};
|
169
102
|
}
|
170
|
-
}
|
171
|
-
async getSourceApiVersion() {
|
172
|
-
const projectConfig = await this.project.resolveProjectConfig();
|
173
|
-
return getString(projectConfig, 'sourceApiVersion') ?? undefined;
|
174
103
|
}
|
175
104
|
}
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
105
|
+
GitDiffCommand.summary = messages.getMessage('summary');
|
106
|
+
GitDiffCommand.description = messages.getMessage('description');
|
107
|
+
GitDiffCommand.examples = messages.getMessages('examples');
|
108
|
+
GitDiffCommand.args = {
|
180
109
|
ref1: Args.string({
|
181
110
|
required: true,
|
182
111
|
description: messages.getMessage('args.ref1.description'),
|
@@ -185,8 +114,11 @@ GitDiff.args = {
|
|
185
114
|
description: messages.getMessage('args.ref2.description'),
|
186
115
|
}),
|
187
116
|
};
|
188
|
-
|
189
|
-
|
117
|
+
GitDiffCommand.requiresProject = true;
|
118
|
+
GitDiffCommand.deprecateAliases = true;
|
119
|
+
GitDiffCommand.aliases = ['jayree:manifest:beta:git:diff'];
|
120
|
+
GitDiffCommand.flags = {
|
121
|
+
'api-version': orgApiVersionFlagWithDeprecations,
|
190
122
|
'source-dir': arrayWithDeprecation({
|
191
123
|
char: 'd',
|
192
124
|
summary: messages.getMessage('flags.source-dir.summary'),
|
@@ -208,433 +140,4 @@ GitDiff.flags = {
|
|
208
140
|
aliases: ['destructivechangesonly'],
|
209
141
|
}),
|
210
142
|
};
|
211
|
-
async function resolveRef(refOrig, dir) {
|
212
|
-
if (refOrig === '') {
|
213
|
-
return '';
|
214
|
-
}
|
215
|
-
const getCommitLog = async (ref) => {
|
216
|
-
try {
|
217
|
-
const [log] = await git.log({
|
218
|
-
fs,
|
219
|
-
dir,
|
220
|
-
ref,
|
221
|
-
depth: 1,
|
222
|
-
});
|
223
|
-
return { oid: log.oid, parents: log.commit.parent };
|
224
|
-
}
|
225
|
-
catch (error) {
|
226
|
-
throw new Error(`ambiguous argument '${ref}': unknown revision or path not in the working tree.
|
227
|
-
See more help with --help`);
|
228
|
-
}
|
229
|
-
};
|
230
|
-
if (!['~', '^'].some((el) => refOrig.includes(el))) {
|
231
|
-
return (await getCommitLog(refOrig)).oid;
|
232
|
-
}
|
233
|
-
const firstIndex = [refOrig.indexOf('^'), refOrig.indexOf('~')]
|
234
|
-
.filter((a) => a >= 0)
|
235
|
-
.reduce((a, b) => Math.min(a, b));
|
236
|
-
let path = refOrig.substring(firstIndex);
|
237
|
-
let ref = refOrig.substring(0, firstIndex);
|
238
|
-
while (path.length && ref !== undefined) {
|
239
|
-
if (path.startsWith('^')) {
|
240
|
-
path = path.substring(1);
|
241
|
-
let next = Number(path.substring(0, 1));
|
242
|
-
path = next ? path.substring(1) : path;
|
243
|
-
next = next ? next : 1;
|
244
|
-
// eslint-disable-next-line no-await-in-loop
|
245
|
-
ref = (await getCommitLog(ref)).parents[next - 1];
|
246
|
-
}
|
247
|
-
else if (path.startsWith('~')) {
|
248
|
-
path = path.substring(1);
|
249
|
-
let next = Number(path.substring(0, 1));
|
250
|
-
path = next ? path.substring(1) : path;
|
251
|
-
next = next ? next : 1;
|
252
|
-
for (let index = 0; index <= next - 1; index++) {
|
253
|
-
// eslint-disable-next-line no-await-in-loop
|
254
|
-
ref = (await getCommitLog(ref)).parents[0];
|
255
|
-
}
|
256
|
-
}
|
257
|
-
else {
|
258
|
-
ref = undefined;
|
259
|
-
}
|
260
|
-
}
|
261
|
-
if (ref === undefined) {
|
262
|
-
throw new Error(`ambiguous argument '${refOrig}': unknown revision or path not in the working tree.`);
|
263
|
-
}
|
264
|
-
return ref;
|
265
|
-
}
|
266
|
-
async function getGitArgsFromArgv(ref1, ref2, argv, dir) {
|
267
|
-
const newArgv = [];
|
268
|
-
while (argv.length) {
|
269
|
-
let [e] = argv.splice(0, 1);
|
270
|
-
if (e.includes('=')) {
|
271
|
-
// skip parameter=value
|
272
|
-
}
|
273
|
-
else if (e.includes('-')) {
|
274
|
-
// remove value
|
275
|
-
if (argv[0] && !argv[0].includes('-') && ![ref1, ref2].includes(argv[0])) {
|
276
|
-
[e] = argv.splice(0, 1);
|
277
|
-
}
|
278
|
-
}
|
279
|
-
else {
|
280
|
-
newArgv.push(e);
|
281
|
-
}
|
282
|
-
}
|
283
|
-
argv = newArgv;
|
284
|
-
let refString = ref1;
|
285
|
-
const a = argv.join('.').split('.');
|
286
|
-
if ((a.length === 3 || a.length === 4) && typeof ref2 === 'undefined') {
|
287
|
-
ref1 = a[0];
|
288
|
-
ref2 = a[a.length - 1];
|
289
|
-
}
|
290
|
-
else if (a.length === 2 && typeof ref2 !== 'undefined') {
|
291
|
-
refString = `${ref1}..${ref2}`;
|
292
|
-
}
|
293
|
-
else if (a.length === 1) {
|
294
|
-
ref2 = '';
|
295
|
-
}
|
296
|
-
else {
|
297
|
-
throw new Error(`Ambiguous ${format('argument%s', argv.length === 1 ? '' : 's')}: ${argv.join(', ')}
|
298
|
-
See more help with --help`);
|
299
|
-
}
|
300
|
-
ref1 = await resolveRef(ref1, dir);
|
301
|
-
ref2 = await resolveRef(ref2, dir);
|
302
|
-
if (a.length === 4) {
|
303
|
-
ref1 = (await git.findMergeBase({
|
304
|
-
fs,
|
305
|
-
dir,
|
306
|
-
oids: [ref2, ref1],
|
307
|
-
}))[0];
|
308
|
-
}
|
309
|
-
return { ref1, ref2, refString };
|
310
|
-
}
|
311
|
-
function ensureOSPath(path) {
|
312
|
-
return path.split(posix.sep).join(sep);
|
313
|
-
}
|
314
|
-
function ensureGitRelPath(dir, path) {
|
315
|
-
return relative(dir, path).split(sep).join(posix.sep);
|
316
|
-
}
|
317
|
-
async function createVirtualTreeContainer(ref, dir, modifiedFiles) {
|
318
|
-
const paths = (await git.listFiles({ fs, dir, ref })).map((p) => join(dir, ensureOSPath(p)));
|
319
|
-
const oid = ref ? await git.resolveRef({ fs, dir, ref }) : '';
|
320
|
-
const virtualDirectoryByFullPath = new Map();
|
321
|
-
for await (const filename of paths) {
|
322
|
-
let dirPath = dirname(filename);
|
323
|
-
virtualDirectoryByFullPath.set(dirPath, {
|
324
|
-
dirPath,
|
325
|
-
children: Array.from(new Set(virtualDirectoryByFullPath.get(dirPath)?.children ?? []).add({
|
326
|
-
name: basename(filename),
|
327
|
-
data: parseMetadataXml(filename) && modifiedFiles.includes(filename)
|
328
|
-
? oid
|
329
|
-
? Buffer.from((await git.readBlob({ fs, dir, oid, filepath: ensureGitRelPath(dir, filename) })).blob)
|
330
|
-
: await fs.readFile(ensureOSPath(filename))
|
331
|
-
: Buffer.from(''),
|
332
|
-
})),
|
333
|
-
});
|
334
|
-
const splits = filename.split(sep);
|
335
|
-
for (let i = 1; i < splits.length - 1; i++) {
|
336
|
-
dirPath = splits.slice(0, i + 1).join(sep);
|
337
|
-
virtualDirectoryByFullPath.set(dirPath, {
|
338
|
-
dirPath,
|
339
|
-
children: Array.from(new Set(virtualDirectoryByFullPath.get(dirPath)?.children ?? []).add(splits[i + 1])),
|
340
|
-
});
|
341
|
-
}
|
342
|
-
}
|
343
|
-
return new VirtualTreeContainer(Array.from(virtualDirectoryByFullPath.values()));
|
344
|
-
}
|
345
|
-
async function analyzeFile(path, ref1VirtualTreeContainer, ref2VirtualTreeContainer) {
|
346
|
-
if (!parseMetadataXml(path)) {
|
347
|
-
return { path, status: 0 };
|
348
|
-
}
|
349
|
-
const ref2resolver = new MetadataResolver(registryAccess, ref2VirtualTreeContainer);
|
350
|
-
const [ref2Component] = ref2resolver.getComponentsFromPath(path); // git path only conaints files
|
351
|
-
const ref1resolver = new MetadataResolver(registryAccess, ref1VirtualTreeContainer);
|
352
|
-
const [ref1Component] = ref1resolver.getComponentsFromPath(path); // git path only conaints files
|
353
|
-
if (ref1resolver.forceIgnoredPaths.has(path) || ref2resolver.forceIgnoredPaths.has(path)) {
|
354
|
-
return { path, status: -2 };
|
355
|
-
}
|
356
|
-
if (equal(await ref1Component.parseXml(), await ref2Component.parseXml())) {
|
357
|
-
return { path, status: -1 };
|
358
|
-
}
|
359
|
-
if (ref1Component.type.strictDirectoryName === true || !ref1Component.type.children) {
|
360
|
-
return { path, status: 0 };
|
361
|
-
}
|
362
|
-
const ref2ChildUniqueIdArray = ref2Component
|
363
|
-
.getChildren()
|
364
|
-
.map((childComponent) => getUniqueIdentifier(childComponent));
|
365
|
-
const ref1ChildUniqueIdArray = ref1Component
|
366
|
-
.getChildren()
|
367
|
-
.map((childComponent) => getUniqueIdentifier(childComponent));
|
368
|
-
const childComponentsNotInRef2 = ref1Component
|
369
|
-
.getChildren()
|
370
|
-
.filter((childComponent) => !ref2ChildUniqueIdArray.includes(getUniqueIdentifier(childComponent))); // deleted
|
371
|
-
const childComponentsNotInRef1 = ref2Component
|
372
|
-
.getChildren()
|
373
|
-
.filter((childComponent) => !ref1ChildUniqueIdArray.includes(getUniqueIdentifier(childComponent))); // added
|
374
|
-
const childComponentsInRef1AndRef2 = ref1Component
|
375
|
-
.getChildren()
|
376
|
-
.filter((childComponent) => ref2ChildUniqueIdArray.includes(getUniqueIdentifier(childComponent))); // modified?
|
377
|
-
debug({ childComponentsNotInRef2, childComponentsNotInRef1, childComponentsInRef1AndRef2 });
|
378
|
-
for await (const childComponentRef1 of childComponentsInRef1AndRef2) {
|
379
|
-
const [childComponentRef2] = ref2Component
|
380
|
-
.getChildren()
|
381
|
-
.filter((childComponent) => getUniqueIdentifier(childComponentRef1) === getUniqueIdentifier(childComponent));
|
382
|
-
if (!equal(await childComponentRef1.parseXml(), await childComponentRef2.parseXml())) {
|
383
|
-
childComponentsNotInRef1.push(childComponentRef2); // modified! -> add to added
|
384
|
-
}
|
385
|
-
}
|
386
|
-
debug({ childComponentsNotInRef1 });
|
387
|
-
return {
|
388
|
-
path,
|
389
|
-
status: 1 + childComponentsNotInRef2.length + childComponentsNotInRef1.length,
|
390
|
-
toManifest: childComponentsNotInRef1,
|
391
|
-
toDestructiveChanges: childComponentsNotInRef2,
|
392
|
-
};
|
393
|
-
}
|
394
|
-
function getUniqueIdentifier(component) {
|
395
|
-
return `${component.type.name}#${getString(component, component.type.uniqueIdElement)}`;
|
396
|
-
}
|
397
|
-
async function getFileStateChanges(commitHash1, commitHash2, dir) {
|
398
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
399
|
-
return git.walk({
|
400
|
-
fs,
|
401
|
-
dir,
|
402
|
-
trees: [git.TREE({ ref: commitHash1 }), git.TREE({ ref: commitHash2 })],
|
403
|
-
async map(filepath, [A, B]) {
|
404
|
-
if (filepath === '.' || (await A?.type()) === 'tree' || (await B?.type()) === 'tree') {
|
405
|
-
return;
|
406
|
-
}
|
407
|
-
const Aoid = await A?.oid();
|
408
|
-
const Boid = await B?.oid();
|
409
|
-
let type = 'EQ';
|
410
|
-
if (Aoid !== Boid) {
|
411
|
-
type = 'M';
|
412
|
-
}
|
413
|
-
if (Aoid === undefined) {
|
414
|
-
type = 'A';
|
415
|
-
}
|
416
|
-
if (Boid === undefined) {
|
417
|
-
type = 'D';
|
418
|
-
}
|
419
|
-
if (type !== 'EQ') {
|
420
|
-
return {
|
421
|
-
path: join(dir, ensureOSPath(filepath)),
|
422
|
-
status: type,
|
423
|
-
};
|
424
|
-
}
|
425
|
-
},
|
426
|
-
});
|
427
|
-
}
|
428
|
-
async function getStatusMatrix(dir, ref) {
|
429
|
-
const getStatus = (row) => {
|
430
|
-
if ([
|
431
|
-
[0, 2, 2],
|
432
|
-
[0, 2, 3], // added, staged, with unstaged changes
|
433
|
-
].some((a) => a.every((val, index) => val === row[index]))) {
|
434
|
-
return 'A';
|
435
|
-
}
|
436
|
-
if ([
|
437
|
-
[1, 0, 0],
|
438
|
-
[1, 0, 1],
|
439
|
-
[1, 1, 0],
|
440
|
-
[1, 2, 0],
|
441
|
-
[1, 0, 3], // modified, staged, with unstaged deletion
|
442
|
-
].some((a) => a.every((val, index) => val === row[index]))) {
|
443
|
-
return 'D';
|
444
|
-
}
|
445
|
-
if ([
|
446
|
-
[1, 2, 1],
|
447
|
-
[1, 2, 2],
|
448
|
-
[1, 2, 3], // modified, staged, with unstaged changes
|
449
|
-
].some((a) => a.every((val, index) => val === row[index]))) {
|
450
|
-
return 'M';
|
451
|
-
}
|
452
|
-
return undefined;
|
453
|
-
};
|
454
|
-
const statusMatrix = await git.statusMatrix({ fs, dir, ref });
|
455
|
-
const warnings = statusMatrix
|
456
|
-
.filter((row) => [
|
457
|
-
[0, 2, 0],
|
458
|
-
[0, 0, 3],
|
459
|
-
[0, 2, 3],
|
460
|
-
[1, 2, 1],
|
461
|
-
[1, 0, 3],
|
462
|
-
[1, 1, 3],
|
463
|
-
[1, 2, 3],
|
464
|
-
[1, 1, 0],
|
465
|
-
[1, 2, 0],
|
466
|
-
[1, 0, 1], // deleted, unstaged
|
467
|
-
].some((a) => a.every((val, index) => val === row.slice(1)[index])))
|
468
|
-
.map((row) => join(dir, ensureOSPath(row[0])));
|
469
|
-
const gitlines = statusMatrix
|
470
|
-
.filter((row) => ![
|
471
|
-
[0, 0, 0],
|
472
|
-
[1, 1, 1],
|
473
|
-
[0, 0, 3],
|
474
|
-
[0, 2, 0],
|
475
|
-
[1, 1, 3], // modified, staged, with unstaged original file
|
476
|
-
].some((a) => a.every((val, index) => val === row.slice(1)[index])))
|
477
|
-
.map((row) => ({
|
478
|
-
path: join(dir, ensureOSPath(row[0])),
|
479
|
-
status: getStatus(row.slice(1)),
|
480
|
-
}));
|
481
|
-
return { warnings, lines: gitlines };
|
482
|
-
}
|
483
|
-
async function getGitDiff(ref1, ref2, dir) {
|
484
|
-
let gitlines;
|
485
|
-
let warnings = [];
|
486
|
-
const proj = await SfProject.resolve();
|
487
|
-
const resolveSourcePaths = proj.getUniquePackageDirectories().map((pDir) => pDir.fullPath);
|
488
|
-
if (ref2) {
|
489
|
-
gitlines = (await getFileStateChanges(ref1, ref2, dir)).filter((l) => resolveSourcePaths.some((f) => l.path.startsWith(f)));
|
490
|
-
}
|
491
|
-
else {
|
492
|
-
const { warnings: warn, lines } = await getStatusMatrix(dir, ref1);
|
493
|
-
warnings = warn.filter((l) => resolveSourcePaths.some((f) => l.startsWith(f)));
|
494
|
-
gitlines = lines.filter((l) => resolveSourcePaths.some((f) => l.path.startsWith(f)));
|
495
|
-
}
|
496
|
-
gitlines = gitlines.filter((line) => {
|
497
|
-
if (line.status === 'D') {
|
498
|
-
for (const sourcePath of resolveSourcePaths) {
|
499
|
-
const defaultFolder = join(sourcePath, 'main', 'default');
|
500
|
-
const filePath = line.path.replace(line.path.startsWith(defaultFolder) ? defaultFolder : sourcePath, '');
|
501
|
-
const target = gitlines.find((t) => t.path.endsWith(filePath) && t.status === 'A');
|
502
|
-
if (target) {
|
503
|
-
debug(`rename: ${line.path} -> ${target.path}`);
|
504
|
-
return false;
|
505
|
-
}
|
506
|
-
}
|
507
|
-
}
|
508
|
-
return true;
|
509
|
-
});
|
510
|
-
debug({ gitlines, warnings });
|
511
|
-
return { gitlines, warnings };
|
512
|
-
}
|
513
|
-
// eslint-disable-next-line complexity
|
514
|
-
async function getGitResults(gitLines, ref1VirtualTreeContainer, ref2VirtualTreeContainer, destructiveChangesOnly, fsPaths) {
|
515
|
-
const results = {
|
516
|
-
manifest: new ComponentSet(undefined, registryAccess),
|
517
|
-
output: {
|
518
|
-
unchanged: [],
|
519
|
-
ignored: { ref1: [], ref2: [] },
|
520
|
-
counts: { added: 0, deleted: 0, modified: 0, unchanged: 0, ignored: 0, error: 0 },
|
521
|
-
errors: [],
|
522
|
-
},
|
523
|
-
};
|
524
|
-
const ref1Resolver = new MetadataResolver(registryAccess, ref1VirtualTreeContainer);
|
525
|
-
const ref2Resolver = new MetadataResolver(registryAccess, ref2VirtualTreeContainer);
|
526
|
-
const getComponentsFromPath = (resolver, path) => {
|
527
|
-
let result = [];
|
528
|
-
try {
|
529
|
-
result = resolver.getComponentsFromPath(path);
|
530
|
-
}
|
531
|
-
catch (error) {
|
532
|
-
results.output.counts.error++;
|
533
|
-
results.output.errors.push(error.message);
|
534
|
-
}
|
535
|
-
return result;
|
536
|
-
};
|
537
|
-
const analyzedFilesPromises = [];
|
538
|
-
for (const [, { status, path }] of gitLines.entries()) {
|
539
|
-
if (!fsPaths || fsPaths.some((fsPath) => resolve(path).startsWith(fsPath))) {
|
540
|
-
if (status === 'D') {
|
541
|
-
for (const c of getComponentsFromPath(ref1Resolver, path)) {
|
542
|
-
if (c.xml === path || gitLines.find((x) => x.path === c.xml)) {
|
543
|
-
results.manifest.add(c, DestructiveChangesType.POST);
|
544
|
-
results.output.counts.deleted++;
|
545
|
-
}
|
546
|
-
else {
|
547
|
-
try {
|
548
|
-
if (c.xml) {
|
549
|
-
// in case a binary source file of a bundle was deleted, check if the bundle ist still valid and update instead of delete
|
550
|
-
ref2Resolver.getComponentsFromPath(c.xml);
|
551
|
-
}
|
552
|
-
if (!destructiveChangesOnly) {
|
553
|
-
results.manifest.add(c);
|
554
|
-
results.output.counts.added++;
|
555
|
-
}
|
556
|
-
}
|
557
|
-
catch (error) {
|
558
|
-
results.output.counts.error++;
|
559
|
-
results.output.errors.push(error.message);
|
560
|
-
}
|
561
|
-
}
|
562
|
-
}
|
563
|
-
}
|
564
|
-
else if (status === 'A') {
|
565
|
-
if (!destructiveChangesOnly) {
|
566
|
-
for (const c of getComponentsFromPath(ref2Resolver, path)) {
|
567
|
-
results.manifest.add(c);
|
568
|
-
results.output.counts.added++;
|
569
|
-
}
|
570
|
-
}
|
571
|
-
}
|
572
|
-
else {
|
573
|
-
analyzedFilesPromises.push(analyzeFile(path, ref1VirtualTreeContainer, ref2VirtualTreeContainer));
|
574
|
-
}
|
575
|
-
}
|
576
|
-
else {
|
577
|
-
debug(`${path} not included in sourcepath`);
|
578
|
-
}
|
579
|
-
}
|
580
|
-
for await (const check of analyzedFilesPromises) {
|
581
|
-
if (check.status === 0) {
|
582
|
-
if (!destructiveChangesOnly) {
|
583
|
-
for (const c of getComponentsFromPath(ref2Resolver, check.path)) {
|
584
|
-
results.manifest.add(c);
|
585
|
-
results.output.counts.modified++;
|
586
|
-
}
|
587
|
-
}
|
588
|
-
}
|
589
|
-
else if (check.status === -1) {
|
590
|
-
results.output.unchanged.push(check.path);
|
591
|
-
results.output.counts.unchanged++;
|
592
|
-
}
|
593
|
-
else if (check.status === -2) {
|
594
|
-
results.output.counts.ignored++;
|
595
|
-
results.output.ignored.ref2.push(check.path);
|
596
|
-
}
|
597
|
-
else {
|
598
|
-
if ((check.toDestructiveChanges && check.toDestructiveChanges.length > 0) ||
|
599
|
-
(check.toManifest && check.toManifest.length > 0 && !destructiveChangesOnly)) {
|
600
|
-
results.output.counts.modified++;
|
601
|
-
}
|
602
|
-
if (check.toDestructiveChanges) {
|
603
|
-
for (const c of check.toDestructiveChanges) {
|
604
|
-
results.manifest.add(c, DestructiveChangesType.POST);
|
605
|
-
}
|
606
|
-
}
|
607
|
-
if (!destructiveChangesOnly && check.toManifest) {
|
608
|
-
for (const c of check.toManifest) {
|
609
|
-
results.manifest.add(c);
|
610
|
-
}
|
611
|
-
}
|
612
|
-
}
|
613
|
-
}
|
614
|
-
results.output.ignored = {
|
615
|
-
ref1: Array.from(ref1Resolver.forceIgnoredPaths),
|
616
|
-
ref2: results.output.ignored.ref2.concat(Array.from(ref2Resolver.forceIgnoredPaths)),
|
617
|
-
};
|
618
|
-
results.output.counts.ignored =
|
619
|
-
results.output.counts.ignored + ref1Resolver.forceIgnoredPaths.size + ref2Resolver.forceIgnoredPaths.size;
|
620
|
-
return results;
|
621
|
-
}
|
622
|
-
function fixComponentSetChilds(cs) {
|
623
|
-
let sourceComponents = cs.getSourceComponents();
|
624
|
-
// SDR library is more strict and avoids fixes like this
|
625
|
-
const childsTobeReplacedByParent = [
|
626
|
-
...Object.keys(registry.types.workflow.children?.types ?? {}),
|
627
|
-
...Object.keys(registry.types.sharingrules.children?.types ?? {}),
|
628
|
-
...Object.keys(registry.types.customobjecttranslation.children?.types ?? {}),
|
629
|
-
...Object.keys(registry.types.bot.children?.types ?? {}),
|
630
|
-
];
|
631
|
-
sourceComponents = sourceComponents.map((component) => {
|
632
|
-
if (!component.isMarkedForDelete() && childsTobeReplacedByParent.includes(component.type.id) && component.parent) {
|
633
|
-
debug(`replace: ${component.type.name}:${component.fullName} -> ${component.parent.type.name}:${component.parent.fullName}`);
|
634
|
-
return component.parent;
|
635
|
-
}
|
636
|
-
return component;
|
637
|
-
});
|
638
|
-
return new ComponentSet(sourceComponents, registryAccess);
|
639
|
-
}
|
640
143
|
//# sourceMappingURL=diff.js.map
|