@jayree/sfdx-plugin-manifest 2.9.1 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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, basename, sep, posix, dirname, relative, resolve } from 'node:path';
7
+ import { join, dirname } from 'node:path';
8
8
  import { fileURLToPath } from 'node:url';
9
- import { format } from 'node:util';
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 { Logger, Listr } from 'listr2';
15
- import { env } from '@salesforce/kit';
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 equal from 'fast-deep-equal';
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
- const logger = new Logger({ useIcons: false });
29
- const debug = Debug('jayree:manifest:git:diff');
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
- const { flags, args } = await this.parse(GitDiff);
34
- const sourcepath = flags['source-dir'];
35
- this.destructiveChangesOnly = flags['destructive-changes-only'];
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.projectRoot = this.project.getPath();
38
- this.sourceApiVersion = (await this.getSourceApiVersion());
39
- this.destructiveChanges = join(this.outputDir, 'destructiveChanges.xml');
40
- this.manifest = join(this.outputDir, 'package.xml');
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
- const isContentTypeJSON = env.getString('SFDX_CONTENT_TYPE', '').toUpperCase() === 'JSON';
46
- this.isOutputEnabled = !(this.argv.find((arg) => arg === '--json') ?? isContentTypeJSON);
47
- const gitArgs = await getGitArgsFromArgv(args.ref1, args.ref2, this.argv, this.projectRoot);
48
- debug({ gitArgs });
49
- const tasks = new Listr([
50
- {
51
- title: `Execute 'git --no-pager diff --name-status --no-renames ${gitArgs.refString}'`,
52
- task: async (ctx, task) => {
53
- const { gitlines, warnings } = await getGitDiff(gitArgs.ref1, gitArgs.ref2, this.projectRoot);
54
- this.gitLines = gitlines;
55
- this.outputWarnings = warnings;
56
- task.output = `Changed files: ${this.gitLines.length}`;
57
- },
58
- options: { persistentOutput: true },
59
- },
60
- {
61
- // title: 'Warning output',
62
- skip: () => !this.outputWarnings?.length,
63
- task: (ctx, task) => {
64
- debug({ warnings: this.outputWarnings });
65
- const moreWarnings = this.outputWarnings.splice(5);
66
- for (const message of this.outputWarnings) {
67
- task.output = `Warning: unstaged file ${message}`;
68
- }
69
- task.output = moreWarnings.length ? `... ${moreWarnings.length} more warnings` : '';
70
- },
71
- options: { persistentOutput: true, bottomBar: 6 },
72
- },
73
- {
74
- title: 'Create virtual tree container',
75
- skip: () => !this.gitLines.length,
76
- task: (ctx, task) => task.newListr([
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
- const { manifest, output } = await getGitResults(this.gitLines, this.ref1VirtualTreeContainer, this.ref2VirtualTreeContainer, this.destructiveChangesOnly, this.fsPaths);
107
- task.output = `Added: ${output.counts.added}, Deleted: ${output.counts.deleted}, Modified: ${output.counts.modified}, Unchanged: ${output.counts.unchanged}, Ignored: ${output.counts.ignored}${output.counts.error ? `, Errors: ${output.counts.error}` : ''}`;
108
- this.outputErrors = output.errors;
109
- debug({ manifest });
110
- this.componentSet = fixComponentSetChilds(manifest);
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
- task.output = moreErrors.length ? `... ${moreErrors.length} more errors` : '';
125
- },
126
- options: { persistentOutput: true, bottomBar: 6 },
127
- },
128
- {
129
- title: 'Generate manifests',
130
- skip: () => !this.componentSet?.size,
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
- destructiveChanges: await this.componentSet?.getObject(DestructiveChangesType.POST),
161
- manifest: await this.componentSet?.getObject(),
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
- catch (e) {
165
- if (debug.enabled && this.isOutputEnabled) {
166
- logger.fail(e.message);
167
- }
168
- throw e;
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
- GitDiff.summary = messages.getMessage('summary');
177
- GitDiff.description = messages.getMessage('description');
178
- GitDiff.examples = messages.getMessages('examples');
179
- GitDiff.args = {
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
- GitDiff.requiresProject = true;
189
- GitDiff.flags = {
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