@docupace/pipeline 1.0.60 → 1.0.61-alpha.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/eslint.config.js +1 -1
- package/package.json +3 -3
- package/src/changeset/changelog-wiki.js +313 -0
- package/src/changeset/cli.js +46 -0
- package/src/changeset/create.js +15 -5
- package/src/changeset/package-util.js +2 -1
- package/src/lib/merge-driver.js +204 -0
- package/src/merge/cli-merge-all.js +472 -0
- package/src/merge/cli-merge.js +492 -0
- package/src/merge/cli-resolve.js +395 -0
- package/src/merge/cli.js +38 -0
- package/src/merge/merge-changelog.js +87 -0
- package/src/merge/merge-package.js +106 -0
- package/src/merge/merge-types.js +82 -0
- package/src/merge/pr.js +85 -0
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { createBitbucketPR } from './pr.js';
|
|
3
|
+
import { autoResolveConflicts } from './cli-resolve.js';
|
|
4
|
+
import { getPackageNames } from '../changeset/package-util.js';
|
|
5
|
+
import { writeChangesetFile } from '../changeset/create.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create and checkout merge branch from target branch
|
|
9
|
+
*/
|
|
10
|
+
function createMergeBranch(
|
|
11
|
+
sourceBranch,
|
|
12
|
+
targetBranch,
|
|
13
|
+
checkoutOnly = false,
|
|
14
|
+
verbose = false,
|
|
15
|
+
) {
|
|
16
|
+
const mergeBranchName = `merge/${sourceBranch.replaceAll('/', '-')}-to-${targetBranch.replaceAll('/', '-')}`;
|
|
17
|
+
|
|
18
|
+
if (!checkoutOnly) {
|
|
19
|
+
if (verbose) console.log(`📋 Checking out target branch: ${targetBranch}`);
|
|
20
|
+
execSync(`git checkout ${targetBranch}`, {
|
|
21
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
22
|
+
});
|
|
23
|
+
execSync(`git pull origin ${targetBranch}`, {
|
|
24
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Check if merge branch exists and delete it (both local and remote)
|
|
28
|
+
try {
|
|
29
|
+
execSync(`git branch -D ${mergeBranchName}`, {
|
|
30
|
+
stdio: 'pipe',
|
|
31
|
+
});
|
|
32
|
+
if (verbose)
|
|
33
|
+
console.log(`🗑️ Deleted existing local branch: ${mergeBranchName}`);
|
|
34
|
+
} catch {
|
|
35
|
+
// Branch doesn't exist, which is fine
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Try to delete remote branch
|
|
39
|
+
try {
|
|
40
|
+
execSync(`git push origin --delete ${mergeBranchName}`, {
|
|
41
|
+
stdio: 'pipe',
|
|
42
|
+
});
|
|
43
|
+
if (verbose)
|
|
44
|
+
console.log(`🗑️ Deleted existing remote branch: ${mergeBranchName}`);
|
|
45
|
+
} catch {
|
|
46
|
+
// Remote branch doesn't exist, which is fine
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (verbose) console.log(`🌿 Creating merge branch: ${mergeBranchName}`);
|
|
50
|
+
execSync(`git checkout -b ${mergeBranchName}`, {
|
|
51
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
console.log('Do nothing. Should be checked out');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return mergeBranchName;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Attempt to merge source branch into current branch
|
|
62
|
+
* Returns: { hasConflicts: boolean, hasChanges: boolean }
|
|
63
|
+
*/
|
|
64
|
+
function attemptMerge(sourceBranch, targetBranch, verbose = false) {
|
|
65
|
+
if (verbose) {
|
|
66
|
+
console.log(`🔀 Merging ${sourceBranch} into current branch`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
execSync(`git merge --no-commit --no-ff origin/${sourceBranch}`, {
|
|
71
|
+
stdio: 'pipe',
|
|
72
|
+
encoding: 'utf8',
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Check if there are any changes
|
|
76
|
+
try {
|
|
77
|
+
execSync('git diff --cached --quiet', { stdio: 'pipe' });
|
|
78
|
+
// No changes
|
|
79
|
+
return { hasConflicts: false, hasChanges: false };
|
|
80
|
+
} catch {
|
|
81
|
+
// Has changes
|
|
82
|
+
if (verbose) console.log('✅ Merge completed with changes, no conflicts');
|
|
83
|
+
return { hasConflicts: false, hasChanges: true };
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (verbose) console.log('⚠️ Merge conflicts detected');
|
|
87
|
+
return { hasConflicts: true, hasChanges: true };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get packages that have changes to be merged
|
|
93
|
+
*/
|
|
94
|
+
function getChangedPackages(verbose = false) {
|
|
95
|
+
try {
|
|
96
|
+
const allPackages = getPackageNames();
|
|
97
|
+
|
|
98
|
+
// Get list of changed files
|
|
99
|
+
const changedFiles = execSync('git diff --cached --name-only', {
|
|
100
|
+
encoding: 'utf8',
|
|
101
|
+
stdio: 'pipe',
|
|
102
|
+
})
|
|
103
|
+
.trim()
|
|
104
|
+
.split('\n')
|
|
105
|
+
.filter(Boolean);
|
|
106
|
+
|
|
107
|
+
if (verbose) {
|
|
108
|
+
console.log('📄 Changed files:', changedFiles);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Filter packages that have changes
|
|
112
|
+
const changedPackages = allPackages.filter((pkg) => {
|
|
113
|
+
const packagePath = pkg.path === '.' ? '' : pkg.path + '/';
|
|
114
|
+
return changedFiles.some((file) => file.startsWith(packagePath));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (verbose) {
|
|
118
|
+
console.log(
|
|
119
|
+
'📦 Changed packages:',
|
|
120
|
+
changedPackages.map((p) => p.name),
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return changedPackages;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (verbose) console.log('Error getting changed packages:', error.message);
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Run build script
|
|
133
|
+
*/
|
|
134
|
+
function runBuild(buildScript, verbose = false) {
|
|
135
|
+
if (verbose) console.log(`🔨 Running build: ${buildScript}`);
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
execSync(buildScript, {
|
|
139
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
140
|
+
});
|
|
141
|
+
if (verbose) console.log('✅ Build passed');
|
|
142
|
+
return true;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if (verbose) console.log('❌ Build failed');
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Create changeset and commit it
|
|
151
|
+
*/
|
|
152
|
+
async function createAndCommitChangeset(
|
|
153
|
+
sourceBranch,
|
|
154
|
+
targetBranch,
|
|
155
|
+
changedPackages,
|
|
156
|
+
verbose = false,
|
|
157
|
+
) {
|
|
158
|
+
const changesetId = `merge-${sourceBranch.replaceAll('/', '-')}-to-${targetBranch.replaceAll('/', '-')}-${Date.now()}`;
|
|
159
|
+
const text = `Merge ${sourceBranch} to ${targetBranch}`;
|
|
160
|
+
|
|
161
|
+
if (verbose) console.log('📝 Creating changeset...');
|
|
162
|
+
|
|
163
|
+
await writeChangesetFile(changedPackages, changesetId, 'patch', text);
|
|
164
|
+
|
|
165
|
+
execSync('git add .', {
|
|
166
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
execSync(
|
|
170
|
+
`git commit -m "Automatic merge operation for ${sourceBranch} to ${targetBranch}"`,
|
|
171
|
+
{
|
|
172
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
if (verbose) console.log('✅ Changeset created and committed');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Merge into target branch
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
function branchExists(branchName) {
|
|
184
|
+
try {
|
|
185
|
+
// This will list branches that match the name
|
|
186
|
+
const result = execSync(`git branch --list ${branchName}`, {
|
|
187
|
+
encoding: 'utf8',
|
|
188
|
+
});
|
|
189
|
+
return result.trim().length > 0;
|
|
190
|
+
} catch (error) {
|
|
191
|
+
// If git fails, you can log or handle differently
|
|
192
|
+
console.error('Error checking branch:', error.message);
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function mergeIntoTarget(
|
|
198
|
+
sourceBranch,
|
|
199
|
+
targetBranch,
|
|
200
|
+
mergeBranchName,
|
|
201
|
+
verbose = false,
|
|
202
|
+
) {
|
|
203
|
+
if (verbose)
|
|
204
|
+
console.log(`🔀 Merging ${mergeBranchName} into ${targetBranch}`);
|
|
205
|
+
|
|
206
|
+
execSync(`git checkout ${targetBranch}`, {
|
|
207
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
if (branchExists(mergeBranchName)) {
|
|
211
|
+
execSync(`git merge ${mergeBranchName}`, {
|
|
212
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
execSync(`git push origin ${targetBranch}`, {
|
|
216
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
execSync(`git branch -d ${mergeBranchName}`, {
|
|
220
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
if (verbose) console.log(`✅ Successfully merged into ${targetBranch}`);
|
|
224
|
+
} else {
|
|
225
|
+
if (verbose) console.log(`✅ Nothing to merge`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Create pull request for merge branch
|
|
231
|
+
*/
|
|
232
|
+
async function createMergePR(
|
|
233
|
+
sourceBranch,
|
|
234
|
+
targetBranch,
|
|
235
|
+
mergeBranchName,
|
|
236
|
+
reason,
|
|
237
|
+
verbose = false,
|
|
238
|
+
) {
|
|
239
|
+
if (verbose) console.log('📋 Creating pull request...');
|
|
240
|
+
|
|
241
|
+
const prTitle = `Merge ${sourceBranch} into ${targetBranch}`;
|
|
242
|
+
const prDescription = `Automated merge with changeset.\n\nReason: ${reason}`;
|
|
243
|
+
|
|
244
|
+
const prResult = await createBitbucketPR(
|
|
245
|
+
mergeBranchName,
|
|
246
|
+
targetBranch,
|
|
247
|
+
prTitle,
|
|
248
|
+
prDescription,
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
if (prResult.success) {
|
|
252
|
+
console.log(`✅ Pull request created: ${prResult.url}`);
|
|
253
|
+
} else if (prResult.manual) {
|
|
254
|
+
console.log(`📋 Please create PR manually: ${prResult.url}`);
|
|
255
|
+
} else {
|
|
256
|
+
console.log(`❌ Failed to create pull request: ${prResult.error}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Clean up failed merge
|
|
262
|
+
*/
|
|
263
|
+
function cleanupFailedMerge(verbose = false) {
|
|
264
|
+
try {
|
|
265
|
+
execSync('git merge --abort', { stdio: 'pipe' });
|
|
266
|
+
if (verbose) console.log('🧹 Cleaned up failed merge');
|
|
267
|
+
} catch (cleanupError) {
|
|
268
|
+
// Ignore cleanup errors
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function setupMerge(program) {
|
|
273
|
+
program
|
|
274
|
+
.command('merge')
|
|
275
|
+
.description(
|
|
276
|
+
'Merge source branch into target branch with automatic conflict resolution',
|
|
277
|
+
)
|
|
278
|
+
.argument('<sourceBranch>', 'Source branch to merge from')
|
|
279
|
+
.argument('<targetBranch>', 'Target branch to merge into')
|
|
280
|
+
.requiredOption('-b, --build <script>', 'Build script to run after merge')
|
|
281
|
+
.option('-v, --verbose', 'Verbose output')
|
|
282
|
+
.option('--no-push', 'Do not push changes automatically')
|
|
283
|
+
.option('--no-pr', 'Do not create pull request if conflicts remain')
|
|
284
|
+
.option(
|
|
285
|
+
'--prepare-only',
|
|
286
|
+
'Always create PR instead of direct merge, even if build passes',
|
|
287
|
+
)
|
|
288
|
+
.option('--merge-success', 'Merge with success')
|
|
289
|
+
.option('--merge-fail <reason>', 'Merge with with fail')
|
|
290
|
+
.action(async (sourceBranch, targetBranch, options) => {
|
|
291
|
+
try {
|
|
292
|
+
const {
|
|
293
|
+
verbose,
|
|
294
|
+
push = true,
|
|
295
|
+
pr = true,
|
|
296
|
+
build,
|
|
297
|
+
prepareOnly = false,
|
|
298
|
+
mergeSuccess = false,
|
|
299
|
+
mergeFail = '',
|
|
300
|
+
} = options;
|
|
301
|
+
const isDevMode = process.env.DEV_MODE === 'true';
|
|
302
|
+
|
|
303
|
+
if (verbose) {
|
|
304
|
+
console.log(
|
|
305
|
+
`🔄 Starting merge of ${sourceBranch} into ${targetBranch}`,
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// 1. Create merge branch from target branch
|
|
310
|
+
const mergeBranchName = createMergeBranch(
|
|
311
|
+
sourceBranch,
|
|
312
|
+
targetBranch,
|
|
313
|
+
mergeSuccess || mergeFail,
|
|
314
|
+
verbose,
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
if (!mergeFail && !mergeSuccess) {
|
|
318
|
+
// 2. Attempt merge
|
|
319
|
+
const { hasConflicts, hasChanges } = attemptMerge(
|
|
320
|
+
sourceBranch,
|
|
321
|
+
targetBranch,
|
|
322
|
+
verbose,
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
// 3. If no changes, exit
|
|
326
|
+
if (!hasChanges) {
|
|
327
|
+
console.log('✅ No changes to merge');
|
|
328
|
+
execSync(`git checkout ${targetBranch}`, { stdio: 'pipe' });
|
|
329
|
+
execSync(`git branch -d ${mergeBranchName}`, { stdio: 'pipe' });
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// 4. If conflicts, try auto-resolve
|
|
334
|
+
let allConflictsResolved = true;
|
|
335
|
+
if (hasConflicts) {
|
|
336
|
+
if (verbose) console.log('🤖 Running auto-conflict resolution...');
|
|
337
|
+
|
|
338
|
+
const autoResult = await autoResolveConflicts({ verbose });
|
|
339
|
+
allConflictsResolved = autoResult.success;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Get changed packages
|
|
343
|
+
const changedPackages = getChangedPackages(verbose);
|
|
344
|
+
|
|
345
|
+
if (!allConflictsResolved) {
|
|
346
|
+
// 5. Cannot resolve conflicts
|
|
347
|
+
if (verbose)
|
|
348
|
+
console.log('⚠️ Cannot resolve all conflicts automatically');
|
|
349
|
+
|
|
350
|
+
// 5a) Get changed packages (already done above)
|
|
351
|
+
// 5b) Abort merge
|
|
352
|
+
cleanupFailedMerge(verbose);
|
|
353
|
+
|
|
354
|
+
// 5c) Create changeset
|
|
355
|
+
await createAndCommitChangeset(
|
|
356
|
+
sourceBranch,
|
|
357
|
+
targetBranch,
|
|
358
|
+
changedPackages,
|
|
359
|
+
verbose,
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
if (pr && !prepareOnly) {
|
|
363
|
+
// 5d) Push and create PR
|
|
364
|
+
if (push) {
|
|
365
|
+
execSync(`git push -u origin ${mergeBranchName}`, {
|
|
366
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
await createMergePR(
|
|
371
|
+
sourceBranch,
|
|
372
|
+
targetBranch,
|
|
373
|
+
mergeBranchName,
|
|
374
|
+
'Unresolved conflicts',
|
|
375
|
+
verbose,
|
|
376
|
+
);
|
|
377
|
+
} else {
|
|
378
|
+
console.log(
|
|
379
|
+
`⚠️ Merge completed with unresolved conflicts on branch: ${mergeBranchName}`,
|
|
380
|
+
);
|
|
381
|
+
process.exit(2);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
console.log(
|
|
385
|
+
`⚠️ Merge completed with unresolved conflicts on branch: ${mergeBranchName}`,
|
|
386
|
+
);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// 6. Can resolve conflicts
|
|
391
|
+
if (verbose) console.log('✅ All conflicts resolved');
|
|
392
|
+
|
|
393
|
+
// 6a) Get changed packages (already done above)
|
|
394
|
+
// 6b) Create changeset
|
|
395
|
+
await createAndCommitChangeset(
|
|
396
|
+
sourceBranch,
|
|
397
|
+
targetBranch,
|
|
398
|
+
changedPackages,
|
|
399
|
+
verbose,
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
// 6c) Run build
|
|
403
|
+
const buildPassed = runBuild(build, verbose);
|
|
404
|
+
|
|
405
|
+
if (buildPassed && !isDevMode && !prepareOnly) {
|
|
406
|
+
// 6d) Build passed - merge into target
|
|
407
|
+
mergeIntoTarget(
|
|
408
|
+
sourceBranch,
|
|
409
|
+
targetBranch,
|
|
410
|
+
mergeBranchName,
|
|
411
|
+
verbose,
|
|
412
|
+
);
|
|
413
|
+
console.log(
|
|
414
|
+
`🎉 Successfully merged ${sourceBranch} into ${targetBranch}`,
|
|
415
|
+
);
|
|
416
|
+
} else if (prepareOnly) {
|
|
417
|
+
if (push) {
|
|
418
|
+
execSync(`git push -u origin ${mergeBranchName}`, {
|
|
419
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
if (buildPassed) {
|
|
423
|
+
process.exit(0);
|
|
424
|
+
} else {
|
|
425
|
+
process.exit(3);
|
|
426
|
+
}
|
|
427
|
+
} else {
|
|
428
|
+
// 6e) Build failed, dev mode, or prepare-only - create PR
|
|
429
|
+
if (push) {
|
|
430
|
+
execSync(`git push -u origin ${mergeBranchName}`, {
|
|
431
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (pr) {
|
|
436
|
+
let reason;
|
|
437
|
+
if (isDevMode) {
|
|
438
|
+
reason = 'Dev mode enabled';
|
|
439
|
+
} else {
|
|
440
|
+
reason = 'Build failed';
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
await createMergePR(
|
|
444
|
+
sourceBranch,
|
|
445
|
+
targetBranch,
|
|
446
|
+
mergeBranchName,
|
|
447
|
+
reason,
|
|
448
|
+
verbose,
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
let reason;
|
|
453
|
+
if (prepareOnly) {
|
|
454
|
+
reason = 'prepare-only mode';
|
|
455
|
+
} else if (isDevMode) {
|
|
456
|
+
reason = 'dev mode';
|
|
457
|
+
} else {
|
|
458
|
+
reason = 'build failure';
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
console.log(
|
|
462
|
+
`⚠️ Merge completed but creating PR due to ${reason}: ${mergeBranchName}`,
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
} else {
|
|
466
|
+
if (mergeSuccess) {
|
|
467
|
+
mergeIntoTarget(
|
|
468
|
+
sourceBranch,
|
|
469
|
+
targetBranch,
|
|
470
|
+
mergeBranchName,
|
|
471
|
+
verbose,
|
|
472
|
+
);
|
|
473
|
+
} else {
|
|
474
|
+
execSync(`git push -u origin ${mergeBranchName}`, {
|
|
475
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
476
|
+
});
|
|
477
|
+
await createMergePR(
|
|
478
|
+
sourceBranch,
|
|
479
|
+
targetBranch,
|
|
480
|
+
mergeBranchName,
|
|
481
|
+
mergeFail,
|
|
482
|
+
verbose,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
} catch (error) {
|
|
487
|
+
console.error(`❌ Merge failed: ${error.message}`);
|
|
488
|
+
cleanupFailedMerge();
|
|
489
|
+
process.exit(1);
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|