@docupace/pipeline 1.0.61-alpha.0 → 1.0.61

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.
@@ -1,474 +0,0 @@
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
- function mergeIntoTarget(
183
- sourceBranch,
184
- targetBranch,
185
- mergeBranchName,
186
- verbose = false,
187
- ) {
188
- if (verbose)
189
- console.log(`🔀 Merging ${mergeBranchName} into ${targetBranch}`);
190
-
191
- execSync(`git checkout ${targetBranch}`, {
192
- stdio: verbose ? 'inherit' : 'pipe',
193
- });
194
-
195
- execSync(`git merge ${mergeBranchName}`, {
196
- stdio: verbose ? 'inherit' : 'pipe',
197
- });
198
-
199
- execSync(`git push origin ${targetBranch}`, {
200
- stdio: verbose ? 'inherit' : 'pipe',
201
- });
202
-
203
- // Clean up merge branch
204
- execSync(`git branch -d ${mergeBranchName}`, {
205
- stdio: verbose ? 'inherit' : 'pipe',
206
- });
207
-
208
- if (verbose) console.log(`✅ Successfully merged into ${targetBranch}`);
209
- }
210
-
211
- /**
212
- * Create pull request for merge branch
213
- */
214
- async function createMergePR(
215
- sourceBranch,
216
- targetBranch,
217
- mergeBranchName,
218
- reason,
219
- verbose = false,
220
- ) {
221
- if (verbose) console.log('📋 Creating pull request...');
222
-
223
- const prTitle = `Merge ${sourceBranch} into ${targetBranch}`;
224
- const prDescription = `Automated merge with changeset.\n\nReason: ${reason}`;
225
-
226
- const prResult = await createBitbucketPR(
227
- mergeBranchName,
228
- targetBranch,
229
- prTitle,
230
- prDescription,
231
- );
232
-
233
- if (prResult.success) {
234
- console.log(`✅ Pull request created: ${prResult.url}`);
235
- } else if (prResult.manual) {
236
- console.log(`📋 Please create PR manually: ${prResult.url}`);
237
- } else {
238
- console.log(`❌ Failed to create pull request: ${prResult.error}`);
239
- }
240
- }
241
-
242
- /**
243
- * Clean up failed merge
244
- */
245
- function cleanupFailedMerge(verbose = false) {
246
- try {
247
- execSync('git merge --abort', { stdio: 'pipe' });
248
- if (verbose) console.log('🧹 Cleaned up failed merge');
249
- } catch (cleanupError) {
250
- // Ignore cleanup errors
251
- }
252
- }
253
-
254
- export function setupMerge(program) {
255
- program
256
- .command('merge')
257
- .description(
258
- 'Merge source branch into target branch with automatic conflict resolution',
259
- )
260
- .argument('<sourceBranch>', 'Source branch to merge from')
261
- .argument('<targetBranch>', 'Target branch to merge into')
262
- .requiredOption('-b, --build <script>', 'Build script to run after merge')
263
- .option('-v, --verbose', 'Verbose output')
264
- .option('--no-push', 'Do not push changes automatically')
265
- .option('--no-pr', 'Do not create pull request if conflicts remain')
266
- .option(
267
- '--prepare-only',
268
- 'Always create PR instead of direct merge, even if build passes',
269
- )
270
- .option('--merge-success', 'Merge with success')
271
- .option('--merge-fail <reason>', 'Merge with with fail')
272
- .action(async (sourceBranch, targetBranch, options) => {
273
- try {
274
- const {
275
- verbose,
276
- push = true,
277
- pr = true,
278
- build,
279
- prepareOnly = false,
280
- mergeSuccess = false,
281
- mergeFail = '',
282
- } = options;
283
- const isDevMode = process.env.DEV_MODE === 'true';
284
-
285
- if (verbose) {
286
- console.log(
287
- `🔄 Starting merge of ${sourceBranch} into ${targetBranch}`,
288
- );
289
- }
290
-
291
- // 1. Create merge branch from target branch
292
- const mergeBranchName = createMergeBranch(
293
- sourceBranch,
294
- targetBranch,
295
- mergeSuccess || mergeFail,
296
- verbose,
297
- );
298
-
299
- if (!mergeFail && !mergeSuccess) {
300
- // 2. Attempt merge
301
- const { hasConflicts, hasChanges } = attemptMerge(
302
- sourceBranch,
303
- targetBranch,
304
- verbose,
305
- );
306
-
307
- // 3. If no changes, exit
308
- if (!hasChanges) {
309
- console.log('✅ No changes to merge');
310
- execSync(`git checkout ${targetBranch}`, { stdio: 'pipe' });
311
- execSync(`git branch -d ${mergeBranchName}`, { stdio: 'pipe' });
312
- return;
313
- }
314
-
315
- // 4. If conflicts, try auto-resolve
316
- let allConflictsResolved = true;
317
- if (hasConflicts) {
318
- if (verbose) console.log('🤖 Running auto-conflict resolution...');
319
-
320
- const autoResult = await autoResolveConflicts({ verbose });
321
- allConflictsResolved = autoResult.success;
322
- }
323
-
324
- // Get changed packages
325
- const changedPackages = getChangedPackages(verbose);
326
-
327
- if (!allConflictsResolved) {
328
- // 5. Cannot resolve conflicts
329
- if (verbose)
330
- console.log('⚠️ Cannot resolve all conflicts automatically');
331
-
332
- // 5a) Get changed packages (already done above)
333
- // 5b) Abort merge
334
- cleanupFailedMerge(verbose);
335
-
336
- // 5c) Create changeset
337
- await createAndCommitChangeset(
338
- sourceBranch,
339
- targetBranch,
340
- changedPackages,
341
- verbose,
342
- );
343
-
344
- if (pr && !prepareOnly) {
345
- // 5d) Push and create PR
346
- if (push) {
347
- execSync(`git push -u origin ${mergeBranchName}`, {
348
- stdio: verbose ? 'inherit' : 'pipe',
349
- });
350
- }
351
-
352
- await createMergePR(
353
- sourceBranch,
354
- targetBranch,
355
- mergeBranchName,
356
- 'Unresolved conflicts',
357
- verbose,
358
- );
359
- } else {
360
- console.log(
361
- `⚠️ Merge completed with unresolved conflicts on branch: ${mergeBranchName}`,
362
- );
363
- process.exit(2);
364
- }
365
-
366
- console.log(
367
- `⚠️ Merge completed with unresolved conflicts on branch: ${mergeBranchName}`,
368
- );
369
- return;
370
- }
371
-
372
- // 6. Can resolve conflicts
373
- if (verbose) console.log('✅ All conflicts resolved');
374
-
375
- // 6a) Get changed packages (already done above)
376
- // 6b) Create changeset
377
- await createAndCommitChangeset(
378
- sourceBranch,
379
- targetBranch,
380
- changedPackages,
381
- verbose,
382
- );
383
-
384
- // 6c) Run build
385
- const buildPassed = runBuild(build, verbose);
386
-
387
- if (buildPassed && !isDevMode && !prepareOnly) {
388
- // 6d) Build passed - merge into target
389
- mergeIntoTarget(
390
- sourceBranch,
391
- targetBranch,
392
- mergeBranchName,
393
- verbose,
394
- );
395
- console.log(
396
- `🎉 Successfully merged ${sourceBranch} into ${targetBranch}`,
397
- );
398
- } else if (prepareOnly) {
399
- if (push) {
400
- execSync(`git push -u origin ${mergeBranchName}`, {
401
- stdio: verbose ? 'inherit' : 'pipe',
402
- });
403
- }
404
- if (buildPassed) {
405
- process.exit(0);
406
- } else {
407
- process.exit(3);
408
- }
409
- } else {
410
- // 6e) Build failed, dev mode, or prepare-only - create PR
411
- if (push) {
412
- execSync(`git push -u origin ${mergeBranchName}`, {
413
- stdio: verbose ? 'inherit' : 'pipe',
414
- });
415
- }
416
-
417
- if (pr) {
418
- let reason;
419
- if (isDevMode) {
420
- reason = 'Dev mode enabled';
421
- } else {
422
- reason = 'Build failed';
423
- }
424
-
425
- await createMergePR(
426
- sourceBranch,
427
- targetBranch,
428
- mergeBranchName,
429
- reason,
430
- verbose,
431
- );
432
- }
433
-
434
- let reason;
435
- if (prepareOnly) {
436
- reason = 'prepare-only mode';
437
- } else if (isDevMode) {
438
- reason = 'dev mode';
439
- } else {
440
- reason = 'build failure';
441
- }
442
-
443
- console.log(
444
- `⚠️ Merge completed but creating PR due to ${reason}: ${mergeBranchName}`,
445
- );
446
- }
447
- } else {
448
- if (mergeSuccess) {
449
- mergeIntoTarget(
450
- sourceBranch,
451
- targetBranch,
452
- mergeBranchName,
453
- verbose,
454
- );
455
- } else {
456
- execSync(`git push -u origin ${mergeBranchName}`, {
457
- stdio: verbose ? 'inherit' : 'pipe',
458
- });
459
- await createMergePR(
460
- sourceBranch,
461
- targetBranch,
462
- mergeBranchName,
463
- mergeFail,
464
- verbose,
465
- );
466
- }
467
- }
468
- } catch (error) {
469
- console.error(`❌ Merge failed: ${error.message}`);
470
- cleanupFailedMerge();
471
- process.exit(1);
472
- }
473
- });
474
- }