@docupace/pipeline 1.0.77 ā 1.0.78
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/.prettierrc.cjs +12 -12
- package/README.md +135 -135
- package/bin/azuread_update_callbacks_for_app.sh +58 -58
- package/bin/next-changeset-validate.sh +8 -8
- package/bitbucket-pipelines.yml +59 -59
- package/eslint.config.js +49 -49
- package/jest.config.js +15 -15
- package/next/changeset.sh +75 -75
- package/next/copy.sh +34 -34
- package/next/deploy.sh +40 -40
- package/next/execute.sh +123 -123
- package/next/sonar.sh +23 -23
- package/package.json +1 -1
- package/src/auth0/alias.js +79 -79
- package/src/auth0/alias.test.js +172 -172
- package/src/auth0/cli.js +82 -82
- package/src/auth0/configure.js +902 -902
- package/src/auth0/configure.test.js +167 -167
- package/src/auth0/export.js +48 -48
- package/src/auth0/export.test.js +103 -103
- package/src/auth0/metadata.js +141 -141
- package/src/auth0/metadata.test.js +186 -186
- package/src/auth0/vault.js +60 -60
- package/src/auth0/vault.test.js +134 -134
- package/src/changeset/changelog-wiki.js +328 -328
- package/src/changeset/changeset-config.js +34 -34
- package/src/changeset/cli.js +237 -237
- package/src/changeset/create.js +215 -215
- package/src/changeset/package-util.js +87 -87
- package/src/changeset/util.js +43 -43
- package/src/changeset/validate.js +91 -91
- package/src/changeset/version.js +102 -102
- package/src/jenkins/setParams.groovy +58 -58
- package/src/lib/merge-driver.js +204 -204
- package/src/merge/cli-merge-all.js +507 -507
- package/src/merge/cli-merge.js +492 -492
- package/src/merge/cli-resolve.js +399 -399
- package/src/merge/cli.js +38 -38
- package/src/merge/merge-changelog.js +87 -87
- package/src/merge/merge-package.js +106 -106
- package/src/merge/merge-types.js +82 -82
- package/src/merge/pr.js +231 -231
- package/src/micro/deploy-microservice.js +153 -0
- package/src/micro/{ms-publish.js ā publish-ms.js} +8 -6
- package/src/next/alias.js +53 -53
- package/src/next/apache.js +81 -81
- package/src/next/cli.js +10 -1
- package/src/next/config.js +137 -137
- package/src/next/connect.js +226 -226
- package/src/next/copy.js +61 -61
- package/src/next/deploy.js +633 -633
- package/src/next/git-to-semver.js +79 -79
- package/src/next/haproxy.js +76 -76
- package/src/next/jenkins.js +123 -123
- package/src/next/jira.js +84 -84
- package/src/next/logger.js +17 -17
- package/src/next/pipline.js +114 -114
- package/src/next/publish.js +71 -71
- package/src/next/pull.js +7 -7
- package/src/next/sonar.js +23 -23
- package/src/next/test.js +5 -5
- package/src/next/util.js +95 -93
- package/src/next/vault.js +45 -45
- package/terraform/apply.sh +37 -37
- package/terraform/init.sh +72 -72
- package/terraform/plan.sh +76 -76
- package/terraform/validate.sh +17 -17
- package/src/micro/cli.js +0 -71
- package/src/micro/ms-deploy.js +0 -271
package/src/merge/cli-resolve.js
CHANGED
|
@@ -1,399 +1,399 @@
|
|
|
1
|
-
import { mergeChangelogFile } from './merge-changelog.js';
|
|
2
|
-
import mergeTypes, { mergeTypesFile } from './merge-types.js';
|
|
3
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
4
|
-
import mergePackageFile from './merge-package.js';
|
|
5
|
-
import { execSync } from 'child_process';
|
|
6
|
-
|
|
7
|
-
// Default merge configuration
|
|
8
|
-
const defaultMergeConfig = {
|
|
9
|
-
'CHANGELOG.md': 'changelog',
|
|
10
|
-
'*/CHANGELOG.md': 'changelog',
|
|
11
|
-
'**/CHANGELOG.md': 'changelog',
|
|
12
|
-
'src/types/graphql.ts': 'types',
|
|
13
|
-
'codegen.ts': 'ours',
|
|
14
|
-
'package.json': 'package',
|
|
15
|
-
'*/package.json': 'package',
|
|
16
|
-
'**/package.json': 'package',
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// Available merge strategies
|
|
20
|
-
const mergeStrategies = {
|
|
21
|
-
changelog: mergeChangelogFile,
|
|
22
|
-
package: mergePackageFile,
|
|
23
|
-
types: mergeTypesFile,
|
|
24
|
-
ours: (filePath) => {
|
|
25
|
-
// Keep our version by checking out the HEAD version (removes conflicts)
|
|
26
|
-
try {
|
|
27
|
-
execSync(`git checkout --ours ${filePath}`);
|
|
28
|
-
execSync(`git add ${filePath}`);
|
|
29
|
-
console.log(
|
|
30
|
-
`š Using 'ours' strategy for ${filePath} - reset to HEAD version and marked as resolved`,
|
|
31
|
-
);
|
|
32
|
-
return true;
|
|
33
|
-
} catch (error) {
|
|
34
|
-
throw new Error(`Failed to apply 'ours' strategy: ${error.message}`);
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
theirs: (filePath) => {
|
|
38
|
-
// Take their version
|
|
39
|
-
try {
|
|
40
|
-
execSync(`git checkout --theirs ${filePath}`);
|
|
41
|
-
execSync(`git add ${filePath}`);
|
|
42
|
-
console.log(
|
|
43
|
-
`š Using 'theirs' strategy for ${filePath} - marked as resolved`,
|
|
44
|
-
);
|
|
45
|
-
return true;
|
|
46
|
-
} catch (error) {
|
|
47
|
-
throw new Error(`Failed to apply 'theirs' strategy: ${error.message}`);
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Get list of conflicted files from git status
|
|
54
|
-
*/
|
|
55
|
-
function getConflictedFiles() {
|
|
56
|
-
try {
|
|
57
|
-
const statusOutput = execSync('git status --porcelain', {
|
|
58
|
-
encoding: 'utf-8',
|
|
59
|
-
});
|
|
60
|
-
const conflictedFiles = statusOutput
|
|
61
|
-
.split('\n')
|
|
62
|
-
.filter(
|
|
63
|
-
(line) =>
|
|
64
|
-
line.startsWith('UU ') ||
|
|
65
|
-
line.startsWith('AA ') ||
|
|
66
|
-
line.startsWith('DD '),
|
|
67
|
-
)
|
|
68
|
-
.map((line) => line.substring(3).trim())
|
|
69
|
-
.filter((file) => file.length > 0);
|
|
70
|
-
return conflictedFiles;
|
|
71
|
-
} catch (error) {
|
|
72
|
-
throw new Error(`Failed to get git status: ${error.message}`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Load merge configuration from .mergerc file or use defaults
|
|
78
|
-
*/
|
|
79
|
-
function loadMergeConfig() {
|
|
80
|
-
const configPath = '.mergerc';
|
|
81
|
-
|
|
82
|
-
if (existsSync(configPath)) {
|
|
83
|
-
try {
|
|
84
|
-
const configContent = readFileSync(configPath, 'utf-8');
|
|
85
|
-
const config = {};
|
|
86
|
-
|
|
87
|
-
configContent.split('\n').forEach((line) => {
|
|
88
|
-
line = line.trim();
|
|
89
|
-
if (line && !line.startsWith('#')) {
|
|
90
|
-
const [pattern, strategy] = line
|
|
91
|
-
.split(/\s+merge=/)
|
|
92
|
-
.map((s) => s.trim());
|
|
93
|
-
if (pattern && strategy) {
|
|
94
|
-
config[pattern] = strategy;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
return config;
|
|
100
|
-
} catch (error) {
|
|
101
|
-
console.warn(
|
|
102
|
-
`Warning: Could not read ${configPath}, using defaults: ${error.message}`,
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return defaultMergeConfig;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Match file path against patterns (supports * and ** wildcards)
|
|
112
|
-
*/
|
|
113
|
-
function matchPattern(filePath, pattern) {
|
|
114
|
-
// Handle ** at the beginning of pattern
|
|
115
|
-
if (pattern.startsWith('**/')) {
|
|
116
|
-
// Remove the **/ and check if the path ends with the remaining pattern
|
|
117
|
-
const remainingPattern = pattern.slice(3);
|
|
118
|
-
const regexPattern = remainingPattern
|
|
119
|
-
.replace(/\*/g, '[^/]*')
|
|
120
|
-
.replace(/\./g, '\\.')
|
|
121
|
-
.replace(/\//g, '\\/');
|
|
122
|
-
|
|
123
|
-
const regex = new RegExp(`(^|/)${regexPattern}$`);
|
|
124
|
-
return regex.test(filePath);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// For other cases, convert pattern to regex
|
|
128
|
-
const regexPattern = pattern
|
|
129
|
-
.replace(/\*\*/g, '___DOUBLESTAR___')
|
|
130
|
-
.replace(/\*/g, '[^/]*')
|
|
131
|
-
.replace(/___DOUBLESTAR___/g, '.*?')
|
|
132
|
-
.replace(/\./g, '\\.')
|
|
133
|
-
.replace(/\//g, '\\/');
|
|
134
|
-
|
|
135
|
-
const regex = new RegExp(`^${regexPattern}$`);
|
|
136
|
-
return regex.test(filePath);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Find merge strategy for a given file
|
|
141
|
-
*/
|
|
142
|
-
function findMergeStrategy(filePath, config) {
|
|
143
|
-
// Check exact match first
|
|
144
|
-
if (config[filePath]) {
|
|
145
|
-
return config[filePath];
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Check pattern matches
|
|
149
|
-
for (const [pattern, strategy] of Object.entries(config)) {
|
|
150
|
-
if (matchPattern(filePath, pattern)) {
|
|
151
|
-
return strategy;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Create default .mergerc file
|
|
160
|
-
*/
|
|
161
|
-
function createDefaultConfig() {
|
|
162
|
-
const configContent = `# Merge configuration file
|
|
163
|
-
# Format: <file-pattern> merge=<strategy>
|
|
164
|
-
# Strategies: changelog, package, types, ours, theirs
|
|
165
|
-
|
|
166
|
-
CHANGELOG.md merge=changelog
|
|
167
|
-
*/CHANGELOG.md merge=changelog
|
|
168
|
-
**/CHANGELOG.md merge=changelog
|
|
169
|
-
src/types/graphql.ts merge=types
|
|
170
|
-
codegen.ts merge=ours
|
|
171
|
-
package.json merge=package
|
|
172
|
-
*/package.json merge=package
|
|
173
|
-
**/package.json merge=package
|
|
174
|
-
`;
|
|
175
|
-
|
|
176
|
-
writeFileSync('.mergerc', configContent);
|
|
177
|
-
console.log('ā
Created default .mergerc configuration file');
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export async function autoResolveConflicts(options = {}) {
|
|
181
|
-
const { dryRun = false, verbose = false } = options;
|
|
182
|
-
|
|
183
|
-
// Get conflicted files
|
|
184
|
-
const conflictedFiles = getConflictedFiles();
|
|
185
|
-
|
|
186
|
-
if (conflictedFiles.length === 0) {
|
|
187
|
-
if (verbose) console.log('ā
No conflicted files found');
|
|
188
|
-
return { success: true, resolvedCount: 0, skippedCount: 0, totalCount: 0 };
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (verbose) {
|
|
192
|
-
console.log(`Found ${conflictedFiles.length} conflicted files:`);
|
|
193
|
-
conflictedFiles.forEach((file) => console.log(` - ${file}`));
|
|
194
|
-
console.log('');
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Load configuration
|
|
198
|
-
const config = loadMergeConfig();
|
|
199
|
-
|
|
200
|
-
if (verbose) {
|
|
201
|
-
console.log('Merge configuration:');
|
|
202
|
-
Object.entries(config).forEach(([pattern, strategy]) => {
|
|
203
|
-
console.log(` ${pattern} -> ${strategy}`);
|
|
204
|
-
});
|
|
205
|
-
console.log('');
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
let resolvedCount = 0;
|
|
209
|
-
let skippedCount = 0;
|
|
210
|
-
|
|
211
|
-
// Process each conflicted file
|
|
212
|
-
for (const filePath of conflictedFiles) {
|
|
213
|
-
const strategy = findMergeStrategy(filePath, config);
|
|
214
|
-
|
|
215
|
-
if (!strategy) {
|
|
216
|
-
if (verbose)
|
|
217
|
-
console.log(`ā ļø No strategy found for ${filePath} - skipping`);
|
|
218
|
-
skippedCount++;
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const mergeFunction = mergeStrategies[strategy];
|
|
223
|
-
if (!mergeFunction) {
|
|
224
|
-
if (verbose)
|
|
225
|
-
console.log(
|
|
226
|
-
`ā ļø Unknown strategy '${strategy}' for ${filePath} - skipping`,
|
|
227
|
-
);
|
|
228
|
-
skippedCount++;
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (dryRun) {
|
|
233
|
-
if (verbose)
|
|
234
|
-
console.log(`Would apply '${strategy}' strategy to ${filePath}`);
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
try {
|
|
239
|
-
if (verbose)
|
|
240
|
-
console.log(`š§ Applying '${strategy}' strategy to ${filePath}`);
|
|
241
|
-
const result = await mergeFunction(filePath);
|
|
242
|
-
if (result.success) {
|
|
243
|
-
resolvedCount++;
|
|
244
|
-
} else {
|
|
245
|
-
skippedCount++;
|
|
246
|
-
}
|
|
247
|
-
} catch (error) {
|
|
248
|
-
console.error(`ā Failed to resolve ${filePath}: ${error.message}`);
|
|
249
|
-
skippedCount++;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const result = {
|
|
254
|
-
success: skippedCount === 0,
|
|
255
|
-
resolvedCount,
|
|
256
|
-
skippedCount,
|
|
257
|
-
totalCount: conflictedFiles.length,
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
// Summary
|
|
261
|
-
if (verbose) {
|
|
262
|
-
console.log(`\nš Summary:`);
|
|
263
|
-
console.log(` Resolved: ${resolvedCount}`);
|
|
264
|
-
console.log(` Skipped: ${skippedCount}`);
|
|
265
|
-
console.log(` Total: ${conflictedFiles.length}`);
|
|
266
|
-
|
|
267
|
-
if (resolvedCount > 0 && !dryRun) {
|
|
268
|
-
console.log(`\nā
Successfully resolved ${resolvedCount} conflicts`);
|
|
269
|
-
if (skippedCount === 0) {
|
|
270
|
-
console.log(
|
|
271
|
-
'š All conflicts resolved! You can now commit the changes.',
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return result;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
export function setupResolve(program) {
|
|
281
|
-
program
|
|
282
|
-
.command('resolve-conflicts')
|
|
283
|
-
.description('Automatically resolve conflicts based on configuration')
|
|
284
|
-
.option(
|
|
285
|
-
'-c, --config <path>',
|
|
286
|
-
'Path to merge configuration file',
|
|
287
|
-
'.mergerc',
|
|
288
|
-
)
|
|
289
|
-
.option('-n, --dry-run', 'Show what would be done without making changes')
|
|
290
|
-
.option('-v, --verbose', 'Verbose output')
|
|
291
|
-
.action(async (options) => {
|
|
292
|
-
try {
|
|
293
|
-
const result = await autoResolveConflicts(options);
|
|
294
|
-
|
|
295
|
-
if (!result.success) {
|
|
296
|
-
console.error(
|
|
297
|
-
`ā Auto-resolve failed: ${result.skippedCount} files could not be resolved`,
|
|
298
|
-
);
|
|
299
|
-
process.exit(1);
|
|
300
|
-
}
|
|
301
|
-
} catch (error) {
|
|
302
|
-
console.error(`ā Auto-resolve failed: ${error.message}`);
|
|
303
|
-
process.exit(1);
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
// New merge command
|
|
308
|
-
|
|
309
|
-
// Individual strategy commands
|
|
310
|
-
program
|
|
311
|
-
.command('resolve-changelog-conflicts')
|
|
312
|
-
.description('Merge changelog files by removing conflict markers')
|
|
313
|
-
.argument('<file>', 'File with merge conflicts')
|
|
314
|
-
.action(async (file) => {
|
|
315
|
-
try {
|
|
316
|
-
mergeChangelogFile(file);
|
|
317
|
-
console.log('ā
Changelog merge completed successfully');
|
|
318
|
-
} catch (error) {
|
|
319
|
-
console.error(`ā Changelog merge failed: ${error.message}`);
|
|
320
|
-
process.exit(1);
|
|
321
|
-
}
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
program
|
|
325
|
-
.command('resolve-package-conflicts')
|
|
326
|
-
.description('Merge package.json files by resolving version conflicts')
|
|
327
|
-
.argument('<file>', 'File with merge conflicts')
|
|
328
|
-
.action(async (file) => {
|
|
329
|
-
try {
|
|
330
|
-
await mergePackageFile(file);
|
|
331
|
-
console.log('ā
Package merge completed successfully');
|
|
332
|
-
} catch (error) {
|
|
333
|
-
console.error(`ā Package merge failed: ${error.message}`);
|
|
334
|
-
process.exit(1);
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
program
|
|
339
|
-
.command('resolve-type-conflicts')
|
|
340
|
-
.description('Merge types files with balanced brace checking')
|
|
341
|
-
.argument('<file>', 'File with merge conflicts')
|
|
342
|
-
.action(async (file) => {
|
|
343
|
-
try {
|
|
344
|
-
await mergeTypes(file);
|
|
345
|
-
console.log('ā
Types merge completed successfully');
|
|
346
|
-
} catch (error) {
|
|
347
|
-
console.error(`ā Types merge failed: ${error.message}`);
|
|
348
|
-
process.exit(1);
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
// Configuration commands
|
|
353
|
-
program
|
|
354
|
-
.command('init')
|
|
355
|
-
.description('Create default .mergerc configuration file')
|
|
356
|
-
.action(() => {
|
|
357
|
-
if (existsSync('.mergerc')) {
|
|
358
|
-
console.log('ā ļø .mergerc already exists. Use --force to overwrite.');
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
createDefaultConfig();
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
program
|
|
365
|
-
.command('config')
|
|
366
|
-
.description('Show current merge configuration')
|
|
367
|
-
.action(() => {
|
|
368
|
-
const config = loadMergeConfig();
|
|
369
|
-
console.log('Current merge configuration:');
|
|
370
|
-
Object.entries(config).forEach(([pattern, strategy]) => {
|
|
371
|
-
console.log(` ${pattern.padEnd(30)} -> ${strategy}`);
|
|
372
|
-
});
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
program
|
|
376
|
-
.command('status')
|
|
377
|
-
.description('Show conflicted files and their assigned strategies')
|
|
378
|
-
.action(() => {
|
|
379
|
-
try {
|
|
380
|
-
const conflictedFiles = getConflictedFiles();
|
|
381
|
-
const config = loadMergeConfig();
|
|
382
|
-
|
|
383
|
-
if (conflictedFiles.length === 0) {
|
|
384
|
-
console.log('ā
No conflicted files found');
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
console.log('Conflicted files and their strategies:');
|
|
389
|
-
conflictedFiles.forEach((file) => {
|
|
390
|
-
const strategy = findMergeStrategy(file, config);
|
|
391
|
-
const status = strategy ? `-> ${strategy}` : '-> no strategy';
|
|
392
|
-
console.log(` ${file.padEnd(40)} ${status}`);
|
|
393
|
-
});
|
|
394
|
-
} catch (error) {
|
|
395
|
-
console.error(`ā Failed to get status: ${error.message}`);
|
|
396
|
-
process.exit(1);
|
|
397
|
-
}
|
|
398
|
-
});
|
|
399
|
-
}
|
|
1
|
+
import { mergeChangelogFile } from './merge-changelog.js';
|
|
2
|
+
import mergeTypes, { mergeTypesFile } from './merge-types.js';
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
4
|
+
import mergePackageFile from './merge-package.js';
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
|
|
7
|
+
// Default merge configuration
|
|
8
|
+
const defaultMergeConfig = {
|
|
9
|
+
'CHANGELOG.md': 'changelog',
|
|
10
|
+
'*/CHANGELOG.md': 'changelog',
|
|
11
|
+
'**/CHANGELOG.md': 'changelog',
|
|
12
|
+
'src/types/graphql.ts': 'types',
|
|
13
|
+
'codegen.ts': 'ours',
|
|
14
|
+
'package.json': 'package',
|
|
15
|
+
'*/package.json': 'package',
|
|
16
|
+
'**/package.json': 'package',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Available merge strategies
|
|
20
|
+
const mergeStrategies = {
|
|
21
|
+
changelog: mergeChangelogFile,
|
|
22
|
+
package: mergePackageFile,
|
|
23
|
+
types: mergeTypesFile,
|
|
24
|
+
ours: (filePath) => {
|
|
25
|
+
// Keep our version by checking out the HEAD version (removes conflicts)
|
|
26
|
+
try {
|
|
27
|
+
execSync(`git checkout --ours ${filePath}`);
|
|
28
|
+
execSync(`git add ${filePath}`);
|
|
29
|
+
console.log(
|
|
30
|
+
`š Using 'ours' strategy for ${filePath} - reset to HEAD version and marked as resolved`,
|
|
31
|
+
);
|
|
32
|
+
return true;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(`Failed to apply 'ours' strategy: ${error.message}`);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
theirs: (filePath) => {
|
|
38
|
+
// Take their version
|
|
39
|
+
try {
|
|
40
|
+
execSync(`git checkout --theirs ${filePath}`);
|
|
41
|
+
execSync(`git add ${filePath}`);
|
|
42
|
+
console.log(
|
|
43
|
+
`š Using 'theirs' strategy for ${filePath} - marked as resolved`,
|
|
44
|
+
);
|
|
45
|
+
return true;
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new Error(`Failed to apply 'theirs' strategy: ${error.message}`);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get list of conflicted files from git status
|
|
54
|
+
*/
|
|
55
|
+
function getConflictedFiles() {
|
|
56
|
+
try {
|
|
57
|
+
const statusOutput = execSync('git status --porcelain', {
|
|
58
|
+
encoding: 'utf-8',
|
|
59
|
+
});
|
|
60
|
+
const conflictedFiles = statusOutput
|
|
61
|
+
.split('\n')
|
|
62
|
+
.filter(
|
|
63
|
+
(line) =>
|
|
64
|
+
line.startsWith('UU ') ||
|
|
65
|
+
line.startsWith('AA ') ||
|
|
66
|
+
line.startsWith('DD '),
|
|
67
|
+
)
|
|
68
|
+
.map((line) => line.substring(3).trim())
|
|
69
|
+
.filter((file) => file.length > 0);
|
|
70
|
+
return conflictedFiles;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
throw new Error(`Failed to get git status: ${error.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Load merge configuration from .mergerc file or use defaults
|
|
78
|
+
*/
|
|
79
|
+
function loadMergeConfig() {
|
|
80
|
+
const configPath = '.mergerc';
|
|
81
|
+
|
|
82
|
+
if (existsSync(configPath)) {
|
|
83
|
+
try {
|
|
84
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
85
|
+
const config = {};
|
|
86
|
+
|
|
87
|
+
configContent.split('\n').forEach((line) => {
|
|
88
|
+
line = line.trim();
|
|
89
|
+
if (line && !line.startsWith('#')) {
|
|
90
|
+
const [pattern, strategy] = line
|
|
91
|
+
.split(/\s+merge=/)
|
|
92
|
+
.map((s) => s.trim());
|
|
93
|
+
if (pattern && strategy) {
|
|
94
|
+
config[pattern] = strategy;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return config;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.warn(
|
|
102
|
+
`Warning: Could not read ${configPath}, using defaults: ${error.message}`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return defaultMergeConfig;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Match file path against patterns (supports * and ** wildcards)
|
|
112
|
+
*/
|
|
113
|
+
function matchPattern(filePath, pattern) {
|
|
114
|
+
// Handle ** at the beginning of pattern
|
|
115
|
+
if (pattern.startsWith('**/')) {
|
|
116
|
+
// Remove the **/ and check if the path ends with the remaining pattern
|
|
117
|
+
const remainingPattern = pattern.slice(3);
|
|
118
|
+
const regexPattern = remainingPattern
|
|
119
|
+
.replace(/\*/g, '[^/]*')
|
|
120
|
+
.replace(/\./g, '\\.')
|
|
121
|
+
.replace(/\//g, '\\/');
|
|
122
|
+
|
|
123
|
+
const regex = new RegExp(`(^|/)${regexPattern}$`);
|
|
124
|
+
return regex.test(filePath);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// For other cases, convert pattern to regex
|
|
128
|
+
const regexPattern = pattern
|
|
129
|
+
.replace(/\*\*/g, '___DOUBLESTAR___')
|
|
130
|
+
.replace(/\*/g, '[^/]*')
|
|
131
|
+
.replace(/___DOUBLESTAR___/g, '.*?')
|
|
132
|
+
.replace(/\./g, '\\.')
|
|
133
|
+
.replace(/\//g, '\\/');
|
|
134
|
+
|
|
135
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
136
|
+
return regex.test(filePath);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Find merge strategy for a given file
|
|
141
|
+
*/
|
|
142
|
+
function findMergeStrategy(filePath, config) {
|
|
143
|
+
// Check exact match first
|
|
144
|
+
if (config[filePath]) {
|
|
145
|
+
return config[filePath];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Check pattern matches
|
|
149
|
+
for (const [pattern, strategy] of Object.entries(config)) {
|
|
150
|
+
if (matchPattern(filePath, pattern)) {
|
|
151
|
+
return strategy;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Create default .mergerc file
|
|
160
|
+
*/
|
|
161
|
+
function createDefaultConfig() {
|
|
162
|
+
const configContent = `# Merge configuration file
|
|
163
|
+
# Format: <file-pattern> merge=<strategy>
|
|
164
|
+
# Strategies: changelog, package, types, ours, theirs
|
|
165
|
+
|
|
166
|
+
CHANGELOG.md merge=changelog
|
|
167
|
+
*/CHANGELOG.md merge=changelog
|
|
168
|
+
**/CHANGELOG.md merge=changelog
|
|
169
|
+
src/types/graphql.ts merge=types
|
|
170
|
+
codegen.ts merge=ours
|
|
171
|
+
package.json merge=package
|
|
172
|
+
*/package.json merge=package
|
|
173
|
+
**/package.json merge=package
|
|
174
|
+
`;
|
|
175
|
+
|
|
176
|
+
writeFileSync('.mergerc', configContent);
|
|
177
|
+
console.log('ā
Created default .mergerc configuration file');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export async function autoResolveConflicts(options = {}) {
|
|
181
|
+
const { dryRun = false, verbose = false } = options;
|
|
182
|
+
|
|
183
|
+
// Get conflicted files
|
|
184
|
+
const conflictedFiles = getConflictedFiles();
|
|
185
|
+
|
|
186
|
+
if (conflictedFiles.length === 0) {
|
|
187
|
+
if (verbose) console.log('ā
No conflicted files found');
|
|
188
|
+
return { success: true, resolvedCount: 0, skippedCount: 0, totalCount: 0 };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (verbose) {
|
|
192
|
+
console.log(`Found ${conflictedFiles.length} conflicted files:`);
|
|
193
|
+
conflictedFiles.forEach((file) => console.log(` - ${file}`));
|
|
194
|
+
console.log('');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Load configuration
|
|
198
|
+
const config = loadMergeConfig();
|
|
199
|
+
|
|
200
|
+
if (verbose) {
|
|
201
|
+
console.log('Merge configuration:');
|
|
202
|
+
Object.entries(config).forEach(([pattern, strategy]) => {
|
|
203
|
+
console.log(` ${pattern} -> ${strategy}`);
|
|
204
|
+
});
|
|
205
|
+
console.log('');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let resolvedCount = 0;
|
|
209
|
+
let skippedCount = 0;
|
|
210
|
+
|
|
211
|
+
// Process each conflicted file
|
|
212
|
+
for (const filePath of conflictedFiles) {
|
|
213
|
+
const strategy = findMergeStrategy(filePath, config);
|
|
214
|
+
|
|
215
|
+
if (!strategy) {
|
|
216
|
+
if (verbose)
|
|
217
|
+
console.log(`ā ļø No strategy found for ${filePath} - skipping`);
|
|
218
|
+
skippedCount++;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const mergeFunction = mergeStrategies[strategy];
|
|
223
|
+
if (!mergeFunction) {
|
|
224
|
+
if (verbose)
|
|
225
|
+
console.log(
|
|
226
|
+
`ā ļø Unknown strategy '${strategy}' for ${filePath} - skipping`,
|
|
227
|
+
);
|
|
228
|
+
skippedCount++;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (dryRun) {
|
|
233
|
+
if (verbose)
|
|
234
|
+
console.log(`Would apply '${strategy}' strategy to ${filePath}`);
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
if (verbose)
|
|
240
|
+
console.log(`š§ Applying '${strategy}' strategy to ${filePath}`);
|
|
241
|
+
const result = await mergeFunction(filePath);
|
|
242
|
+
if (result.success) {
|
|
243
|
+
resolvedCount++;
|
|
244
|
+
} else {
|
|
245
|
+
skippedCount++;
|
|
246
|
+
}
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.error(`ā Failed to resolve ${filePath}: ${error.message}`);
|
|
249
|
+
skippedCount++;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const result = {
|
|
254
|
+
success: skippedCount === 0,
|
|
255
|
+
resolvedCount,
|
|
256
|
+
skippedCount,
|
|
257
|
+
totalCount: conflictedFiles.length,
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// Summary
|
|
261
|
+
if (verbose) {
|
|
262
|
+
console.log(`\nš Summary:`);
|
|
263
|
+
console.log(` Resolved: ${resolvedCount}`);
|
|
264
|
+
console.log(` Skipped: ${skippedCount}`);
|
|
265
|
+
console.log(` Total: ${conflictedFiles.length}`);
|
|
266
|
+
|
|
267
|
+
if (resolvedCount > 0 && !dryRun) {
|
|
268
|
+
console.log(`\nā
Successfully resolved ${resolvedCount} conflicts`);
|
|
269
|
+
if (skippedCount === 0) {
|
|
270
|
+
console.log(
|
|
271
|
+
'š All conflicts resolved! You can now commit the changes.',
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export function setupResolve(program) {
|
|
281
|
+
program
|
|
282
|
+
.command('resolve-conflicts')
|
|
283
|
+
.description('Automatically resolve conflicts based on configuration')
|
|
284
|
+
.option(
|
|
285
|
+
'-c, --config <path>',
|
|
286
|
+
'Path to merge configuration file',
|
|
287
|
+
'.mergerc',
|
|
288
|
+
)
|
|
289
|
+
.option('-n, --dry-run', 'Show what would be done without making changes')
|
|
290
|
+
.option('-v, --verbose', 'Verbose output')
|
|
291
|
+
.action(async (options) => {
|
|
292
|
+
try {
|
|
293
|
+
const result = await autoResolveConflicts(options);
|
|
294
|
+
|
|
295
|
+
if (!result.success) {
|
|
296
|
+
console.error(
|
|
297
|
+
`ā Auto-resolve failed: ${result.skippedCount} files could not be resolved`,
|
|
298
|
+
);
|
|
299
|
+
process.exit(1);
|
|
300
|
+
}
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.error(`ā Auto-resolve failed: ${error.message}`);
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// New merge command
|
|
308
|
+
|
|
309
|
+
// Individual strategy commands
|
|
310
|
+
program
|
|
311
|
+
.command('resolve-changelog-conflicts')
|
|
312
|
+
.description('Merge changelog files by removing conflict markers')
|
|
313
|
+
.argument('<file>', 'File with merge conflicts')
|
|
314
|
+
.action(async (file) => {
|
|
315
|
+
try {
|
|
316
|
+
mergeChangelogFile(file);
|
|
317
|
+
console.log('ā
Changelog merge completed successfully');
|
|
318
|
+
} catch (error) {
|
|
319
|
+
console.error(`ā Changelog merge failed: ${error.message}`);
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
program
|
|
325
|
+
.command('resolve-package-conflicts')
|
|
326
|
+
.description('Merge package.json files by resolving version conflicts')
|
|
327
|
+
.argument('<file>', 'File with merge conflicts')
|
|
328
|
+
.action(async (file) => {
|
|
329
|
+
try {
|
|
330
|
+
await mergePackageFile(file);
|
|
331
|
+
console.log('ā
Package merge completed successfully');
|
|
332
|
+
} catch (error) {
|
|
333
|
+
console.error(`ā Package merge failed: ${error.message}`);
|
|
334
|
+
process.exit(1);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
program
|
|
339
|
+
.command('resolve-type-conflicts')
|
|
340
|
+
.description('Merge types files with balanced brace checking')
|
|
341
|
+
.argument('<file>', 'File with merge conflicts')
|
|
342
|
+
.action(async (file) => {
|
|
343
|
+
try {
|
|
344
|
+
await mergeTypes(file);
|
|
345
|
+
console.log('ā
Types merge completed successfully');
|
|
346
|
+
} catch (error) {
|
|
347
|
+
console.error(`ā Types merge failed: ${error.message}`);
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// Configuration commands
|
|
353
|
+
program
|
|
354
|
+
.command('init')
|
|
355
|
+
.description('Create default .mergerc configuration file')
|
|
356
|
+
.action(() => {
|
|
357
|
+
if (existsSync('.mergerc')) {
|
|
358
|
+
console.log('ā ļø .mergerc already exists. Use --force to overwrite.');
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
createDefaultConfig();
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
program
|
|
365
|
+
.command('config')
|
|
366
|
+
.description('Show current merge configuration')
|
|
367
|
+
.action(() => {
|
|
368
|
+
const config = loadMergeConfig();
|
|
369
|
+
console.log('Current merge configuration:');
|
|
370
|
+
Object.entries(config).forEach(([pattern, strategy]) => {
|
|
371
|
+
console.log(` ${pattern.padEnd(30)} -> ${strategy}`);
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
program
|
|
376
|
+
.command('status')
|
|
377
|
+
.description('Show conflicted files and their assigned strategies')
|
|
378
|
+
.action(() => {
|
|
379
|
+
try {
|
|
380
|
+
const conflictedFiles = getConflictedFiles();
|
|
381
|
+
const config = loadMergeConfig();
|
|
382
|
+
|
|
383
|
+
if (conflictedFiles.length === 0) {
|
|
384
|
+
console.log('ā
No conflicted files found');
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
console.log('Conflicted files and their strategies:');
|
|
389
|
+
conflictedFiles.forEach((file) => {
|
|
390
|
+
const strategy = findMergeStrategy(file, config);
|
|
391
|
+
const status = strategy ? `-> ${strategy}` : '-> no strategy';
|
|
392
|
+
console.log(` ${file.padEnd(40)} ${status}`);
|
|
393
|
+
});
|
|
394
|
+
} catch (error) {
|
|
395
|
+
console.error(`ā Failed to get status: ${error.message}`);
|
|
396
|
+
process.exit(1);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
}
|