@docupace/pipeline 1.0.61-alpha.1 ā 1.0.62
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/bitbucket-pipelines.yml +28 -0
- package/eslint.config.js +12 -0
- package/package.json +11 -8
- package/src/auth0/configure.js +88 -54
- package/src/changeset/cli.js +0 -46
- package/src/changeset/create.js +5 -15
- package/src/changeset/package-util.js +1 -2
- package/src/changeset/util.js +6 -6
- package/src/changeset/validate.js +24 -23
- package/src/micro/deploy-microservice.js +140 -0
- package/src/micro/publish-ms.js +188 -0
- package/src/next/apache.js +2 -2
- package/src/next/cli.js +9 -1
- package/src/next/connect.js +1 -2
- package/src/changeset/changelog-wiki.js +0 -313
- package/src/lib/merge-driver.js +0 -204
- package/src/merge/cli-merge-all.js +0 -472
- package/src/merge/cli-merge.js +0 -492
- package/src/merge/cli-resolve.js +0 -395
- package/src/merge/cli.js +0 -38
- package/src/merge/merge-changelog.js +0 -87
- package/src/merge/merge-package.js +0 -106
- package/src/merge/merge-types.js +0 -82
- package/src/merge/pr.js +0 -85
package/src/lib/merge-driver.js
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import { execSync } from 'child_process';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import { fileURLToPath } from 'url';
|
|
7
|
-
|
|
8
|
-
// Get __dirname equivalent in ESM
|
|
9
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
-
const __dirname = path.dirname(__filename);
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Default merge logic function - can be overridden
|
|
14
|
-
* @param {string} headContent - The content from HEAD (current branch)
|
|
15
|
-
* @param {string} branchContent - The content from the incoming branch
|
|
16
|
-
* @returns {string} - The merged content
|
|
17
|
-
* @throws {Error} - If the conflict cannot be automatically merged
|
|
18
|
-
*/
|
|
19
|
-
export function defaultMergeLogic(headContent, branchContent) {
|
|
20
|
-
// Default implementation - throws error
|
|
21
|
-
// Users should provide their own implementation
|
|
22
|
-
throw new Error(
|
|
23
|
-
'No merge logic provided - please pass a custom merge function',
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Main merge driver function
|
|
29
|
-
* @param {string} filePath - Path to the file with conflicts
|
|
30
|
-
* @param {Function} customMergeLogic - Custom merge function (optional)
|
|
31
|
-
* @returns {Promise<{success: boolean, totalConflicts: number, resolvedConflicts: number, hasUnresolvedConflicts: boolean}>}
|
|
32
|
-
*/
|
|
33
|
-
export async function mergeDriver(filePath, customMergeLogic = null) {
|
|
34
|
-
// Use provided merge logic or fall back to default
|
|
35
|
-
const mergeLogic = customMergeLogic || defaultMergeLogic;
|
|
36
|
-
|
|
37
|
-
if (!filePath) {
|
|
38
|
-
throw new Error('File path is required');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Check if file exists
|
|
42
|
-
if (!fs.existsSync(filePath)) {
|
|
43
|
-
throw new Error(`File not found: ${filePath}`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
console.log(`Processing conflicts in: ${filePath}`);
|
|
47
|
-
|
|
48
|
-
// Read the file content
|
|
49
|
-
let fileContent;
|
|
50
|
-
try {
|
|
51
|
-
fileContent = fs.readFileSync(filePath, 'utf8');
|
|
52
|
-
} catch (error) {
|
|
53
|
-
throw new Error(`Error reading file: ${error.message}`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Split content into lines for processing
|
|
57
|
-
const lines = fileContent.split('\n');
|
|
58
|
-
const resultLines = [];
|
|
59
|
-
|
|
60
|
-
// Track merge state
|
|
61
|
-
let hasUnresolvedConflicts = false;
|
|
62
|
-
let totalConflicts = 0;
|
|
63
|
-
let resolvedConflicts = 0;
|
|
64
|
-
|
|
65
|
-
// State variables for parsing
|
|
66
|
-
let inConflict = false;
|
|
67
|
-
let headLines = [];
|
|
68
|
-
let branchLines = [];
|
|
69
|
-
let currentSection = null; // 'head' or 'branch'
|
|
70
|
-
|
|
71
|
-
// Process each line
|
|
72
|
-
for (let i = 0; i < lines.length; i++) {
|
|
73
|
-
const line = lines[i];
|
|
74
|
-
|
|
75
|
-
if (line.startsWith('<<<<<<<')) {
|
|
76
|
-
// Start of conflict marker
|
|
77
|
-
inConflict = true;
|
|
78
|
-
currentSection = 'head';
|
|
79
|
-
headLines = [];
|
|
80
|
-
branchLines = [];
|
|
81
|
-
totalConflicts++;
|
|
82
|
-
} else if (inConflict && line.startsWith('=======')) {
|
|
83
|
-
// Middle of conflict - switch from HEAD to branch
|
|
84
|
-
currentSection = 'branch';
|
|
85
|
-
} else if (inConflict && line.startsWith('>>>>>>>')) {
|
|
86
|
-
// End of conflict marker - attempt to merge
|
|
87
|
-
const headContent = headLines.join('\n');
|
|
88
|
-
const branchContent = branchLines.join('\n');
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
// Call custom merge logic
|
|
92
|
-
const mergedContent = mergeLogic(headContent, branchContent);
|
|
93
|
-
|
|
94
|
-
// Add merged content to result
|
|
95
|
-
if (mergedContent !== null && mergedContent !== undefined) {
|
|
96
|
-
resultLines.push(mergedContent);
|
|
97
|
-
resolvedConflicts++;
|
|
98
|
-
console.log(`ā Resolved conflict #${totalConflicts}`);
|
|
99
|
-
}
|
|
100
|
-
} catch (error) {
|
|
101
|
-
// Cannot merge this conflict - keep original conflict markers
|
|
102
|
-
hasUnresolvedConflicts = true;
|
|
103
|
-
|
|
104
|
-
console.log(
|
|
105
|
-
`ā Could not resolve conflict #${totalConflicts}: ${error.message}`,
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
// Preserve the original conflict
|
|
109
|
-
resultLines.push(`<<<<<<< HEAD`);
|
|
110
|
-
resultLines.push(headContent);
|
|
111
|
-
resultLines.push('=======');
|
|
112
|
-
resultLines.push(branchContent);
|
|
113
|
-
resultLines.push(`>>>>>>> branch`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Reset conflict state
|
|
117
|
-
inConflict = false;
|
|
118
|
-
currentSection = null;
|
|
119
|
-
headLines = [];
|
|
120
|
-
branchLines = [];
|
|
121
|
-
} else if (inConflict) {
|
|
122
|
-
// Inside conflict - collect lines
|
|
123
|
-
if (currentSection === 'head') {
|
|
124
|
-
headLines.push(line);
|
|
125
|
-
} else if (currentSection === 'branch') {
|
|
126
|
-
branchLines.push(line);
|
|
127
|
-
}
|
|
128
|
-
} else {
|
|
129
|
-
// Normal line outside of conflict
|
|
130
|
-
resultLines.push(line);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Write the result back to the file
|
|
135
|
-
const resultContent = resultLines.join('\n');
|
|
136
|
-
try {
|
|
137
|
-
fs.writeFileSync(filePath, resultContent, 'utf8');
|
|
138
|
-
console.log(`\nFile updated: ${filePath}`);
|
|
139
|
-
} catch (error) {
|
|
140
|
-
throw new Error(`Error writing file: ${error.message}`);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Summary
|
|
144
|
-
console.log('\n--- Merge Summary ---');
|
|
145
|
-
console.log(`Total conflicts found: ${totalConflicts}`);
|
|
146
|
-
console.log(`Conflicts resolved: ${resolvedConflicts}`);
|
|
147
|
-
console.log(`Conflicts remaining: ${totalConflicts - resolvedConflicts}`);
|
|
148
|
-
|
|
149
|
-
// If all conflicts were resolved, stage the file
|
|
150
|
-
if (!hasUnresolvedConflicts && totalConflicts > 0) {
|
|
151
|
-
try {
|
|
152
|
-
execSync(`git add "${filePath}"`, { stdio: 'inherit' });
|
|
153
|
-
console.log(
|
|
154
|
-
`\nā All conflicts resolved! File has been staged with 'git add'.`,
|
|
155
|
-
);
|
|
156
|
-
} catch (error) {
|
|
157
|
-
console.error(`\nWarning: Could not stage file: ${error.message}`);
|
|
158
|
-
console.log('You may need to run "git add" manually.');
|
|
159
|
-
}
|
|
160
|
-
} else if (hasUnresolvedConflicts) {
|
|
161
|
-
console.log(`\nā Some conflicts could not be resolved automatically.`);
|
|
162
|
-
console.log('Please review and resolve the remaining conflicts manually.');
|
|
163
|
-
} else if (totalConflicts === 0) {
|
|
164
|
-
console.log('\nNo conflicts found in the file.');
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Return result object for programmatic use
|
|
168
|
-
return {
|
|
169
|
-
success: !hasUnresolvedConflicts,
|
|
170
|
-
totalConflicts,
|
|
171
|
-
resolvedConflicts,
|
|
172
|
-
hasUnresolvedConflicts,
|
|
173
|
-
filePath,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Process multiple files with the same merge logic
|
|
179
|
-
* @param {string[]} filePaths - Array of file paths to process
|
|
180
|
-
* @param {Function} customMergeLogic - Custom merge function
|
|
181
|
-
* @returns {Promise<Array>} - Array of results for each file
|
|
182
|
-
*/
|
|
183
|
-
export async function mergeMultipleFiles(filePaths, customMergeLogic) {
|
|
184
|
-
const results = [];
|
|
185
|
-
|
|
186
|
-
for (const filePath of filePaths) {
|
|
187
|
-
try {
|
|
188
|
-
const result = await mergeDriver(filePath, customMergeLogic);
|
|
189
|
-
results.push(result);
|
|
190
|
-
} catch (error) {
|
|
191
|
-
console.error(`Error processing ${filePath}: ${error.message}`);
|
|
192
|
-
results.push({
|
|
193
|
-
success: false,
|
|
194
|
-
error: error.message,
|
|
195
|
-
filePath,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return results;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Default export for convenience
|
|
204
|
-
export default mergeDriver;
|
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
import { execSync } from 'child_process';
|
|
2
|
-
import { readFileSync, existsSync, mkdirSync } from 'fs';
|
|
3
|
-
import { join, dirname } from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
|
|
6
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Read merge configuration from current directory
|
|
10
|
-
*/
|
|
11
|
-
function readMergeConfig(verbose = false) {
|
|
12
|
-
const configPath = join(process.cwd(), 'merge-config.json');
|
|
13
|
-
|
|
14
|
-
if (!existsSync(configPath)) {
|
|
15
|
-
throw new Error('merge-config.json not found in current directory');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
const config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
20
|
-
|
|
21
|
-
if (!config.repositories || !Array.isArray(config.repositories)) {
|
|
22
|
-
throw new Error('Invalid config: repositories array is required');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Validate repository objects
|
|
26
|
-
config.repositories.forEach((repo, index) => {
|
|
27
|
-
if (!repo.url) {
|
|
28
|
-
throw new Error(`Repository at index ${index} is missing 'url' field`);
|
|
29
|
-
}
|
|
30
|
-
if (!repo.buildScript) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
`Repository at index ${index} is missing 'buildScript' field`,
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
if (!repo.name) {
|
|
36
|
-
throw new Error(`Repository at index ${index} is missing 'name' field`);
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
if (!config.mergeBranches || !Array.isArray(config.mergeBranches)) {
|
|
41
|
-
throw new Error('Invalid config: mergeBranches array is required');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Validate merge branches
|
|
45
|
-
config.mergeBranches.forEach((branch, index) => {
|
|
46
|
-
if (!branch.from || !branch.to) {
|
|
47
|
-
throw new Error(
|
|
48
|
-
`Merge branch at index ${index} is missing 'from' or 'to' field`,
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
if (typeof branch.from !== 'object' || typeof branch.to !== 'object') {
|
|
52
|
-
throw new Error(
|
|
53
|
-
`Merge branch at index ${index}: 'from' and 'to' must be objects`,
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
if (!branch.from['*'] || !branch.to['*']) {
|
|
57
|
-
throw new Error(
|
|
58
|
-
`Merge branch at index ${index}: 'from' and 'to' must have '*' default value`,
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
if (verbose) {
|
|
64
|
-
console.log('š Configuration loaded:');
|
|
65
|
-
console.log(` Repositories: ${config.repositories.length}`);
|
|
66
|
-
console.log(` Merge branches: ${config.mergeBranches.length}`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return config;
|
|
70
|
-
} catch (error) {
|
|
71
|
-
throw new Error(`Failed to parse merge-config.json: ${error.message}`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Extract repository name from git URL
|
|
77
|
-
*/
|
|
78
|
-
function getRepoName(gitUrl) {
|
|
79
|
-
const match = gitUrl.match(/\/([^\/]+)\.git$/);
|
|
80
|
-
return match ? match[1] : gitUrl.split('/').pop().replace('.git', '');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Get branch name for a specific repository
|
|
85
|
-
*/
|
|
86
|
-
function getBranchForRepo(branchConfig, repoName) {
|
|
87
|
-
// Check if there's a specific override for this repository
|
|
88
|
-
if (branchConfig[repoName]) {
|
|
89
|
-
return branchConfig[repoName];
|
|
90
|
-
}
|
|
91
|
-
// Fall back to the default branch
|
|
92
|
-
return branchConfig['*'];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Clone or update repository
|
|
97
|
-
*/
|
|
98
|
-
function setupRepository(repository, reposDir, verbose = false) {
|
|
99
|
-
const repoName = getRepoName(repository.url);
|
|
100
|
-
const repoPath = join(reposDir, repoName);
|
|
101
|
-
|
|
102
|
-
if (existsSync(repoPath)) {
|
|
103
|
-
if (verbose) console.log(`š Repository ${repoName} exists, updating...`);
|
|
104
|
-
|
|
105
|
-
execSync('git fetch --all', {
|
|
106
|
-
cwd: repoPath,
|
|
107
|
-
stdio: verbose ? 'inherit' : 'pipe',
|
|
108
|
-
});
|
|
109
|
-
} else {
|
|
110
|
-
if (verbose) console.log(`š„ Cloning repository ${repoName}...`);
|
|
111
|
-
|
|
112
|
-
execSync(`git clone ${repository.url} ${repoName}`, {
|
|
113
|
-
cwd: reposDir,
|
|
114
|
-
stdio: verbose ? 'inherit' : 'pipe',
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return {
|
|
119
|
-
repoName,
|
|
120
|
-
repoPath,
|
|
121
|
-
buildScript: repository.buildScript,
|
|
122
|
-
configName: repository.name,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Run merge command in repository with specific flags
|
|
128
|
-
*/
|
|
129
|
-
function runMergeCommand(
|
|
130
|
-
repoPath,
|
|
131
|
-
fromBranch,
|
|
132
|
-
toBranch,
|
|
133
|
-
buildScript,
|
|
134
|
-
flags = '',
|
|
135
|
-
verbose = false,
|
|
136
|
-
) {
|
|
137
|
-
const cliPath = join(__dirname, 'cli.js');
|
|
138
|
-
const verboseFlag = verbose ? '--verbose' : '';
|
|
139
|
-
|
|
140
|
-
const command =
|
|
141
|
-
`node ${cliPath} merge ${fromBranch} ${toBranch} --build "${buildScript}" ${flags} ${verboseFlag}`.trim();
|
|
142
|
-
|
|
143
|
-
if (verbose) {
|
|
144
|
-
console.log(`š Running command in ${repoPath}`);
|
|
145
|
-
console.log(`Command: ${command}`);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
try {
|
|
149
|
-
execSync(command, {
|
|
150
|
-
cwd: repoPath,
|
|
151
|
-
stdio: verbose ? 'inherit' : 'pipe',
|
|
152
|
-
encoding: 'utf8',
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
return { exitCode: 0, error: null };
|
|
156
|
-
} catch (error) {
|
|
157
|
-
// Extract exit code from error
|
|
158
|
-
const exitCode = error.status || 1;
|
|
159
|
-
return { exitCode, error: error.message };
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Run initial prepare-only phase for all repositories
|
|
165
|
-
*/
|
|
166
|
-
async function runPreparePhase(
|
|
167
|
-
mergeBranch,
|
|
168
|
-
repositories,
|
|
169
|
-
reposDir,
|
|
170
|
-
verbose = false,
|
|
171
|
-
) {
|
|
172
|
-
const { from: fromConfig, to: toConfig } = mergeBranch;
|
|
173
|
-
console.log(`\nš Phase 1: Running prepare-only for all repositories`);
|
|
174
|
-
|
|
175
|
-
const results = [];
|
|
176
|
-
|
|
177
|
-
for (let i = 0; i < repositories.length; i++) {
|
|
178
|
-
const repository = repositories[i];
|
|
179
|
-
const { repoName, repoPath, buildScript, configName } = setupRepository(
|
|
180
|
-
repository,
|
|
181
|
-
reposDir,
|
|
182
|
-
verbose,
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
// Get the specific branches for this repository
|
|
186
|
-
const fromBranch = getBranchForRepo(fromConfig, configName);
|
|
187
|
-
const toBranch = getBranchForRepo(toConfig, configName);
|
|
188
|
-
|
|
189
|
-
console.log(
|
|
190
|
-
`\nš¦ [${i + 1}/${repositories.length}] Testing ${configName} (${repoName}): ${fromBranch} ā ${toBranch}`,
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
const result = runMergeCommand(
|
|
194
|
-
repoPath,
|
|
195
|
-
fromBranch,
|
|
196
|
-
toBranch,
|
|
197
|
-
buildScript,
|
|
198
|
-
'--prepare-only',
|
|
199
|
-
verbose,
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
results.push({
|
|
203
|
-
repository: repoName,
|
|
204
|
-
configName,
|
|
205
|
-
url: repository.url,
|
|
206
|
-
buildScript,
|
|
207
|
-
fromBranch,
|
|
208
|
-
toBranch,
|
|
209
|
-
exitCode: result.exitCode,
|
|
210
|
-
error: result.error,
|
|
211
|
-
repoPath,
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
// Log result based on exit code
|
|
215
|
-
switch (result.exitCode) {
|
|
216
|
-
case 0:
|
|
217
|
-
console.log(`ā
${configName}: Merge and build successful`);
|
|
218
|
-
break;
|
|
219
|
-
case 2:
|
|
220
|
-
console.log(`ā ļø ${configName}: Merge has unresolved conflicts`);
|
|
221
|
-
break;
|
|
222
|
-
case 3:
|
|
223
|
-
console.log(`ā ļø ${configName}: Build failed`);
|
|
224
|
-
break;
|
|
225
|
-
default:
|
|
226
|
-
console.log(
|
|
227
|
-
`ā ${configName}: Unknown error (exit code: ${result.exitCode})`,
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return results;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Run follow-up phase based on prepare phase results
|
|
237
|
-
*/
|
|
238
|
-
async function runFollowUpPhase(prepareResults, verbose = false) {
|
|
239
|
-
console.log(`\nš Phase 2: Running follow-up based on prepare phase results`);
|
|
240
|
-
|
|
241
|
-
// Check if all repositories passed
|
|
242
|
-
const allPassed = prepareResults.every((r) => r.exitCode === 0);
|
|
243
|
-
|
|
244
|
-
for (let i = 0; i < prepareResults.length; i++) {
|
|
245
|
-
const result = prepareResults[i];
|
|
246
|
-
console.log(
|
|
247
|
-
`\nš¦ [${i + 1}/${prepareResults.length}] Processing ${result.configName}`,
|
|
248
|
-
);
|
|
249
|
-
|
|
250
|
-
let flags = '';
|
|
251
|
-
let action = '';
|
|
252
|
-
|
|
253
|
-
if (allPassed) {
|
|
254
|
-
// All passed, merge successfully
|
|
255
|
-
flags = '--merge-success';
|
|
256
|
-
action = 'Merging successfully';
|
|
257
|
-
} else {
|
|
258
|
-
// At least one failed, determine the appropriate action
|
|
259
|
-
switch (result.exitCode) {
|
|
260
|
-
case 0:
|
|
261
|
-
// This one passed but others failed
|
|
262
|
-
flags = '--merge-fail "Waiting for success for other failed merges"';
|
|
263
|
-
action = 'Creating PR (waiting for other repos)';
|
|
264
|
-
break;
|
|
265
|
-
case 2:
|
|
266
|
-
// Merge failed
|
|
267
|
-
flags = '--merge-fail "Merge Failed"';
|
|
268
|
-
action = 'Creating PR (merge conflicts)';
|
|
269
|
-
break;
|
|
270
|
-
case 3:
|
|
271
|
-
// Build failed
|
|
272
|
-
flags = '--merge-fail "Build Failed"';
|
|
273
|
-
action = 'Creating PR (build failed)';
|
|
274
|
-
break;
|
|
275
|
-
default:
|
|
276
|
-
// Unknown error
|
|
277
|
-
flags = '--merge-fail "Unknown Error"';
|
|
278
|
-
action = 'Creating PR (unknown error)';
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
console.log(` Action: ${action}`);
|
|
283
|
-
|
|
284
|
-
const followUpResult = runMergeCommand(
|
|
285
|
-
result.repoPath,
|
|
286
|
-
result.fromBranch,
|
|
287
|
-
result.toBranch,
|
|
288
|
-
result.buildScript,
|
|
289
|
-
flags,
|
|
290
|
-
verbose,
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
// Update the result with follow-up information
|
|
294
|
-
result.followUpExitCode = followUpResult.exitCode;
|
|
295
|
-
result.followUpError = followUpResult.error;
|
|
296
|
-
result.followUpAction = action;
|
|
297
|
-
|
|
298
|
-
if (followUpResult.exitCode === 0) {
|
|
299
|
-
console.log(`ā
${result.configName}: ${action} completed`);
|
|
300
|
-
} else {
|
|
301
|
-
console.log(`ā ${result.configName}: ${action} failed`);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return prepareResults;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Process a single merge branch across all repositories
|
|
310
|
-
*/
|
|
311
|
-
async function processMergeBranch(
|
|
312
|
-
mergeBranch,
|
|
313
|
-
repositories,
|
|
314
|
-
reposDir,
|
|
315
|
-
verbose = false,
|
|
316
|
-
) {
|
|
317
|
-
console.log(`\nš Processing merge branches`);
|
|
318
|
-
|
|
319
|
-
// Phase 1: Run prepare-only for all repositories
|
|
320
|
-
const prepareResults = await runPreparePhase(
|
|
321
|
-
mergeBranch,
|
|
322
|
-
repositories,
|
|
323
|
-
reposDir,
|
|
324
|
-
verbose,
|
|
325
|
-
);
|
|
326
|
-
|
|
327
|
-
// Phase 2: Run follow-up based on results
|
|
328
|
-
const finalResults = await runFollowUpPhase(prepareResults, verbose);
|
|
329
|
-
|
|
330
|
-
// Summary
|
|
331
|
-
const allPassed = prepareResults.every((r) => r.exitCode === 0);
|
|
332
|
-
const mergeFailures = prepareResults.filter((r) => r.exitCode === 2);
|
|
333
|
-
const buildFailures = prepareResults.filter((r) => r.exitCode === 3);
|
|
334
|
-
const successes = prepareResults.filter((r) => r.exitCode === 0);
|
|
335
|
-
|
|
336
|
-
console.log(`\nš Merge summary:`);
|
|
337
|
-
console.log(` ā
Successful: ${successes.length}/${repositories.length}`);
|
|
338
|
-
console.log(` ā ļø Merge conflicts: ${mergeFailures.length}`);
|
|
339
|
-
console.log(` ā ļø Build failures: ${buildFailures.length}`);
|
|
340
|
-
|
|
341
|
-
if (allPassed) {
|
|
342
|
-
console.log(` š All repositories merged successfully!`);
|
|
343
|
-
} else {
|
|
344
|
-
console.log(` ā ļø Some repositories require manual intervention via PRs`);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
return {
|
|
348
|
-
success: allPassed,
|
|
349
|
-
results: finalResults,
|
|
350
|
-
summary: {
|
|
351
|
-
total: repositories.length,
|
|
352
|
-
successes: successes.length,
|
|
353
|
-
mergeFailures: mergeFailures.length,
|
|
354
|
-
buildFailures: buildFailures.length,
|
|
355
|
-
},
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Main merge-all function
|
|
361
|
-
*/
|
|
362
|
-
async function mergeAll(verbose = false) {
|
|
363
|
-
try {
|
|
364
|
-
// Read configuration
|
|
365
|
-
const config = readMergeConfig(verbose);
|
|
366
|
-
|
|
367
|
-
// Setup repos directory
|
|
368
|
-
const reposDir = join(process.cwd(), 'repos');
|
|
369
|
-
if (!existsSync(reposDir)) {
|
|
370
|
-
mkdirSync(reposDir, { recursive: true });
|
|
371
|
-
if (verbose) console.log(`š Created repos directory: ${reposDir}`);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
console.log(`š Starting merge-all process`);
|
|
375
|
-
console.log(`Repositories: ${config.repositories.length}`);
|
|
376
|
-
console.log(`Merge branches: ${config.mergeBranches.length}`);
|
|
377
|
-
|
|
378
|
-
const allResults = [];
|
|
379
|
-
|
|
380
|
-
// Process each merge branch in sequence
|
|
381
|
-
for (let i = 0; i < config.mergeBranches.length; i++) {
|
|
382
|
-
const mergeBranch = config.mergeBranches[i];
|
|
383
|
-
console.log(`\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`);
|
|
384
|
-
console.log(
|
|
385
|
-
`Processing merge branch set ${i + 1}/${config.mergeBranches.length}`,
|
|
386
|
-
);
|
|
387
|
-
console.log(`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`);
|
|
388
|
-
|
|
389
|
-
const branchResult = await processMergeBranch(
|
|
390
|
-
mergeBranch,
|
|
391
|
-
config.repositories,
|
|
392
|
-
reposDir,
|
|
393
|
-
verbose,
|
|
394
|
-
);
|
|
395
|
-
|
|
396
|
-
if (!branchResult.success) {
|
|
397
|
-
console.log(`Exiting due to failure of one or more merges`);
|
|
398
|
-
process.exit(1);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
allResults.push({
|
|
402
|
-
mergeBranch,
|
|
403
|
-
...branchResult,
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Final summary
|
|
408
|
-
console.log(`\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`);
|
|
409
|
-
console.log(`š Final Summary:`);
|
|
410
|
-
console.log(`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`);
|
|
411
|
-
|
|
412
|
-
allResults.forEach((result, index) => {
|
|
413
|
-
const { from, to } = result.mergeBranch;
|
|
414
|
-
const status = result.success ? 'ā
' : 'ā ļø';
|
|
415
|
-
console.log(`\n${status} Merge branch set ${index + 1}:`);
|
|
416
|
-
|
|
417
|
-
if (result.summary) {
|
|
418
|
-
console.log(` Total repositories: ${result.summary.total}`);
|
|
419
|
-
console.log(` Successful merges: ${result.summary.successes}`);
|
|
420
|
-
console.log(` Merge conflicts: ${result.summary.mergeFailures}`);
|
|
421
|
-
console.log(` Build failures: ${result.summary.buildFailures}`);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if (result.results && verbose) {
|
|
425
|
-
console.log(`\n Repository details:`);
|
|
426
|
-
result.results.forEach((repo) => {
|
|
427
|
-
let repoStatus = 'ā';
|
|
428
|
-
if (repo.exitCode === 0) repoStatus = 'ā
';
|
|
429
|
-
else if (repo.exitCode === 2) repoStatus = 'ā ļø (merge)';
|
|
430
|
-
else if (repo.exitCode === 3) repoStatus = 'ā ļø (build)';
|
|
431
|
-
|
|
432
|
-
console.log(
|
|
433
|
-
` ${repoStatus} ${repo.configName}: ${repo.fromBranch} ā ${repo.toBranch}`,
|
|
434
|
-
);
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
const overallSuccess = allResults.every((r) => r.success);
|
|
440
|
-
if (overallSuccess) {
|
|
441
|
-
console.log(`\nš All merge operations completed successfully!`);
|
|
442
|
-
} else {
|
|
443
|
-
console.log(
|
|
444
|
-
`\nā ļø Some merge operations created PRs. Check the repositories for details.`,
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
return { success: overallSuccess, results: allResults };
|
|
449
|
-
} catch (error) {
|
|
450
|
-
console.error(`ā Merge-all failed: ${error.message}`);
|
|
451
|
-
throw error;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
export function setupMergeAll(program) {
|
|
456
|
-
program
|
|
457
|
-
.command('merge-all')
|
|
458
|
-
.description(
|
|
459
|
-
'Merge multiple branches across multiple repositories based on configuration',
|
|
460
|
-
)
|
|
461
|
-
.option('-v, --verbose', 'Verbose output')
|
|
462
|
-
.action(async (options) => {
|
|
463
|
-
try {
|
|
464
|
-
const { verbose } = options;
|
|
465
|
-
|
|
466
|
-
await mergeAll(verbose);
|
|
467
|
-
} catch (error) {
|
|
468
|
-
console.error(`ā merge-all command failed: ${error.message}`);
|
|
469
|
-
process.exit(1);
|
|
470
|
-
}
|
|
471
|
-
});
|
|
472
|
-
}
|