pagan-artifact 0.3.1 → 0.3.3
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/bin/art.js +213 -59
- package/branching/index.js +266 -110
- package/caches/index.js +257 -77
- package/changes/index.js +93 -29
- package/contributions/index.js +251 -100
- package/index.js +2 -2
- package/package.json +1 -1
- package/setup/index.js +190 -55
- package/utils/constants.js +15 -0
- package/utils/getStateByHash/index.js +135 -78
- package/utils/shouldIgnore/index.js +44 -3
- package/workflow/index.js +256 -132
package/branching/index.js
CHANGED
|
@@ -1,51 +1,84 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Artifact - Modern version control.
|
|
3
|
+
* @author Benny Schmidt (https://github.com/bennyschmidt)
|
|
4
|
+
* @project https://github.com/bennyschmidt/artifact
|
|
5
|
+
* Module: Branching (v0.3.3)
|
|
4
6
|
*/
|
|
5
7
|
|
|
6
8
|
const fs = require('fs');
|
|
7
9
|
const path = require('path');
|
|
8
10
|
|
|
9
11
|
const getStateByHash = require('../utils/getStateByHash');
|
|
10
|
-
|
|
11
|
-
const MAX_PART_SIZE = 32000000;
|
|
12
|
+
const { MAX_PART_SIZE } = require('../utils/constants');
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
* Lists, creates
|
|
15
|
+
* Lists all existing branches, creates a new branch from the current HEAD,
|
|
16
|
+
* or deletes an existing branch from the local and remote history.
|
|
17
|
+
* * @param {Object} options - The branch options.
|
|
18
|
+
* @param {string} options.name - The name of the branch to create or delete.
|
|
19
|
+
* @param {boolean} options.isDelete - Whether the operation is a deletion.
|
|
20
|
+
* @returns {string|string[]} - A message or an array of branch names.
|
|
15
21
|
*/
|
|
16
22
|
|
|
17
23
|
function branch ({ name, isDelete = false } = {}) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Define core paths for the .art directory and internal history structures.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const artifactPath = path.join(process.cwd(), '.art');
|
|
29
|
+
const localHistoryPath = path.join(artifactPath, 'history/local');
|
|
30
|
+
const remoteHistoryPath = path.join(artifactPath, 'history/remote');
|
|
31
|
+
const artifactJsonPath = path.join(artifactPath, 'art.json');
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* If no branch name is provided, return a list of all local branches.
|
|
35
|
+
* Filters out system files like .DS_Store or thumbs.db.
|
|
36
|
+
*/
|
|
22
37
|
|
|
23
38
|
if (!name) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
39
|
+
const branchList = [];
|
|
40
|
+
const entries = fs.readdirSync(localHistoryPath);
|
|
41
|
+
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
if (entry !== '.DS_Store' && entry !== 'desktop.ini' && entry !== 'thumbs.db') {
|
|
44
|
+
branchList.push(entry);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return branchList;
|
|
27
49
|
}
|
|
28
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Validate the branch name against illegal characters and naming patterns.
|
|
53
|
+
*/
|
|
54
|
+
|
|
29
55
|
const normalizedName = name.toLowerCase();
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
56
|
+
const illegalRegularExpression = /[\/\\]/g;
|
|
57
|
+
const controlRegularExpression = /[\x00-\x1f\x80-\x9f]/g;
|
|
58
|
+
const reservedRegularExpression = /^\.+$/;
|
|
33
59
|
|
|
34
|
-
if (
|
|
60
|
+
if (illegalRegularExpression.test(name) || controlRegularExpression.test(name) || reservedRegularExpression.test(name)) {
|
|
35
61
|
throw new Error(`Invalid branch name: "${name}". Branch names cannot contain slashes or illegal characters.`);
|
|
36
62
|
}
|
|
37
63
|
|
|
38
64
|
const branchLocalPath = path.join(localHistoryPath, name);
|
|
39
65
|
const branchRemotePath = path.join(remoteHistoryPath, name);
|
|
40
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Pass `isDelete: true` to delete the branch in question.
|
|
69
|
+
* This is automatically set to true with CLI flags: --delete, -d, -D.
|
|
70
|
+
*/
|
|
71
|
+
|
|
41
72
|
if (isDelete) {
|
|
42
73
|
if (!fs.existsSync(branchLocalPath)) {
|
|
43
74
|
throw new Error(`Local branch "${name}" does not exist.`);
|
|
44
75
|
}
|
|
45
76
|
|
|
46
|
-
const
|
|
77
|
+
const artifactJson = JSON.parse(
|
|
78
|
+
fs.readFileSync(artifactJsonPath, 'utf8')
|
|
79
|
+
);
|
|
47
80
|
|
|
48
|
-
if (
|
|
81
|
+
if (artifactJson.active.branch === name) {
|
|
49
82
|
throw new Error(`Local branch "${name}" is in use and can't be deleted right now.`);
|
|
50
83
|
}
|
|
51
84
|
|
|
@@ -58,20 +91,37 @@ function branch ({ name, isDelete = false } = {}) {
|
|
|
58
91
|
return `Deleted local branch "${name}".`;
|
|
59
92
|
}
|
|
60
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Check if the branch already exists before attempting creation.
|
|
96
|
+
*/
|
|
97
|
+
|
|
61
98
|
if (fs.existsSync(branchLocalPath)) {
|
|
62
99
|
throw new Error(`Local branch "${name}" already exists.`);
|
|
63
100
|
}
|
|
64
101
|
|
|
65
|
-
|
|
66
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Read the active branch manifest to determine the starting commit history.
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
const artifactJson = JSON.parse(
|
|
107
|
+
fs.readFileSync(artifactJsonPath, 'utf8')
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const sourceBranchName = artifactJson.active.branch;
|
|
67
111
|
const currentBranchManifest = path.join(localHistoryPath, sourceBranchName, 'manifest.json');
|
|
68
112
|
|
|
69
113
|
let initialCommits = [];
|
|
70
114
|
|
|
71
115
|
if (fs.existsSync(currentBranchManifest)) {
|
|
72
|
-
initialCommits = JSON.parse(
|
|
116
|
+
initialCommits = JSON.parse(
|
|
117
|
+
fs.readFileSync(currentBranchManifest, 'utf8')
|
|
118
|
+
).commits;
|
|
73
119
|
}
|
|
74
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Create the local branch directory and initialize the manifest file.
|
|
123
|
+
*/
|
|
124
|
+
|
|
75
125
|
fs.mkdirSync(branchLocalPath, { recursive: true });
|
|
76
126
|
|
|
77
127
|
fs.writeFileSync(
|
|
@@ -79,6 +129,11 @@ function branch ({ name, isDelete = false } = {}) {
|
|
|
79
129
|
JSON.stringify({ commits: initialCommits }, null, 2)
|
|
80
130
|
);
|
|
81
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Initialize the remote tracking directory for the new branch
|
|
134
|
+
* (if it doesn't exist).
|
|
135
|
+
*/
|
|
136
|
+
|
|
82
137
|
if (!fs.existsSync(branchRemotePath)) {
|
|
83
138
|
fs.mkdirSync(branchRemotePath, { recursive: true });
|
|
84
139
|
|
|
@@ -88,31 +143,37 @@ function branch ({ name, isDelete = false } = {}) {
|
|
|
88
143
|
);
|
|
89
144
|
}
|
|
90
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Copy all commit data and files from the source branch to the new branch.
|
|
148
|
+
*/
|
|
149
|
+
|
|
91
150
|
if (initialCommits.length > 0) {
|
|
92
151
|
const sourceBranchPath = path.join(localHistoryPath, sourceBranchName);
|
|
93
152
|
const sourceRemotePath = path.join(remoteHistoryPath, sourceBranchName);
|
|
94
153
|
|
|
95
154
|
for (const hash of initialCommits) {
|
|
96
155
|
let masterFile = path.join(sourceBranchPath, `${hash}.json`);
|
|
97
|
-
let
|
|
156
|
+
let currentSourceDirectory = sourceBranchPath;
|
|
98
157
|
|
|
99
158
|
if (!fs.existsSync(masterFile)) {
|
|
100
159
|
masterFile = path.join(sourceRemotePath, `${hash}.json`);
|
|
101
|
-
|
|
160
|
+
currentSourceDirectory = sourceRemotePath;
|
|
102
161
|
}
|
|
103
162
|
|
|
104
163
|
if (fs.existsSync(masterFile)) {
|
|
105
164
|
fs.copyFileSync(masterFile, path.join(branchLocalPath, `${hash}.json`));
|
|
106
165
|
|
|
107
|
-
const commitMaster = JSON.parse(
|
|
166
|
+
const commitMaster = JSON.parse(
|
|
167
|
+
fs.readFileSync(masterFile, 'utf8')
|
|
168
|
+
);
|
|
108
169
|
|
|
109
170
|
if (commitMaster.parts && Array.isArray(commitMaster.parts)) {
|
|
110
171
|
for (const partName of commitMaster.parts) {
|
|
111
|
-
const
|
|
112
|
-
const
|
|
172
|
+
const sourcePart = path.join(currentSourceDirectory, partName);
|
|
173
|
+
const destinationPart = path.join(branchLocalPath, partName);
|
|
113
174
|
|
|
114
|
-
if (fs.existsSync(
|
|
115
|
-
fs.copyFileSync(
|
|
175
|
+
if (fs.existsSync(sourcePart)) {
|
|
176
|
+
fs.copyFileSync(sourcePart, destinationPart);
|
|
116
177
|
}
|
|
117
178
|
}
|
|
118
179
|
}
|
|
@@ -124,29 +185,52 @@ function branch ({ name, isDelete = false } = {}) {
|
|
|
124
185
|
}
|
|
125
186
|
|
|
126
187
|
/**
|
|
127
|
-
* Updates the active pointer and reconstructs the working directory
|
|
188
|
+
* Updates the active branch pointer and reconstructs the working directory
|
|
189
|
+
* based on the state of the target branch's latest commit.
|
|
190
|
+
* * @param {string} branchName - The name of the branch to switch to.
|
|
191
|
+
* @param {Object} options - Checkout options.
|
|
192
|
+
* @param {boolean} options.force - Whether to ignore local changes.
|
|
193
|
+
* @returns {string} - Success message.
|
|
128
194
|
*/
|
|
129
195
|
|
|
130
196
|
function checkout (branchName, { force = false } = {}) {
|
|
197
|
+
/**
|
|
198
|
+
* Setup paths and ensure the target branch exists, creating it if necessary.
|
|
199
|
+
*/
|
|
200
|
+
|
|
131
201
|
const root = process.cwd();
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
const branchPath = path.join(
|
|
202
|
+
const artifactPath = path.join(root, '.art');
|
|
203
|
+
const artifactJsonPath = path.join(artifactPath, 'art.json');
|
|
204
|
+
const branchPath = path.join(artifactPath, 'history/local', branchName);
|
|
135
205
|
|
|
136
206
|
if (!fs.existsSync(branchPath)) {
|
|
137
207
|
branch({ name: branchName });
|
|
138
208
|
}
|
|
139
209
|
|
|
140
|
-
|
|
141
|
-
|
|
210
|
+
/**
|
|
211
|
+
* Retrieve current state to check for uncommitted changes.
|
|
212
|
+
*/
|
|
213
|
+
|
|
214
|
+
const artifactJson = JSON.parse(
|
|
215
|
+
fs.readFileSync(artifactJsonPath, 'utf8')
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const currentState = getStateByHash(artifactJson.active.branch, artifactJson.active.parent) || {};
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Verify if the working directory is dirty.
|
|
222
|
+
* Throws an error unless `force: true` is passed.
|
|
223
|
+
*/
|
|
142
224
|
|
|
143
225
|
if (!force) {
|
|
144
|
-
const
|
|
145
|
-
.filter(
|
|
226
|
+
const allWorkingDirectoryFiles = fs.readdirSync(root, { recursive: true })
|
|
227
|
+
.filter(file => {
|
|
228
|
+
return !file.startsWith('.art') && !fs.statSync(path.join(root, file)).isDirectory();
|
|
229
|
+
});
|
|
146
230
|
|
|
147
231
|
let isDirty = false;
|
|
148
232
|
|
|
149
|
-
for (const file of
|
|
233
|
+
for (const file of allWorkingDirectoryFiles) {
|
|
150
234
|
const currentContent = fs.readFileSync(path.join(root, file), 'utf8');
|
|
151
235
|
|
|
152
236
|
if (currentContent !== currentState[file]) {
|
|
@@ -171,7 +255,13 @@ function checkout (branchName, { force = false } = {}) {
|
|
|
171
255
|
}
|
|
172
256
|
}
|
|
173
257
|
|
|
174
|
-
|
|
258
|
+
/**
|
|
259
|
+
* Identify the latest commit hash for the target branch.
|
|
260
|
+
*/
|
|
261
|
+
|
|
262
|
+
const manifest = JSON.parse(
|
|
263
|
+
fs.readFileSync(path.join(branchPath, 'manifest.json'), 'utf8')
|
|
264
|
+
);
|
|
175
265
|
|
|
176
266
|
const targetHash = manifest.commits.length > 0
|
|
177
267
|
? manifest.commits[manifest.commits.length - 1]
|
|
@@ -179,6 +269,10 @@ function checkout (branchName, { force = false } = {}) {
|
|
|
179
269
|
|
|
180
270
|
const targetState = getStateByHash(branchName, targetHash);
|
|
181
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Clean up files that exist in the current state but not in the target state.
|
|
274
|
+
*/
|
|
275
|
+
|
|
182
276
|
for (const filePath of Object.keys(currentState)) {
|
|
183
277
|
if (!targetState[filePath]) {
|
|
184
278
|
const fullPath = path.join(root, filePath);
|
|
@@ -189,6 +283,10 @@ function checkout (branchName, { force = false } = {}) {
|
|
|
189
283
|
}
|
|
190
284
|
}
|
|
191
285
|
|
|
286
|
+
/**
|
|
287
|
+
* Write target state files to the working directory.
|
|
288
|
+
*/
|
|
289
|
+
|
|
192
290
|
for (const [filePath, content] of Object.entries(targetState)) {
|
|
193
291
|
const fullPath = path.join(root, filePath);
|
|
194
292
|
|
|
@@ -196,108 +294,166 @@ function checkout (branchName, { force = false } = {}) {
|
|
|
196
294
|
fs.writeFileSync(fullPath, content);
|
|
197
295
|
}
|
|
198
296
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
297
|
+
/**
|
|
298
|
+
* Update the active branch and parent pointers in art.json.
|
|
299
|
+
*/
|
|
300
|
+
|
|
301
|
+
artifactJson.active.branch = branchName;
|
|
302
|
+
artifactJson.active.parent = targetHash;
|
|
303
|
+
fs.writeFileSync(artifactJsonPath, JSON.stringify(artifactJson, null, 2));
|
|
202
304
|
|
|
203
305
|
return `Switched to branch "${branchName}".`;
|
|
204
306
|
}
|
|
205
307
|
|
|
206
308
|
/**
|
|
207
|
-
* Performs a three-way merge
|
|
309
|
+
* Performs a three-way merge between the active branch and the target branch.
|
|
310
|
+
* If conflicts are detected, the working directory is updated with markers.
|
|
311
|
+
* * @param {string} targetBranch - The branch to merge into the active branch.
|
|
312
|
+
* @returns {string} - Success message.
|
|
208
313
|
*/
|
|
209
314
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const artJson = JSON.parse(fs.readFileSync(path.join(artPath, 'art.json'), 'utf8'));
|
|
215
|
-
const activeBranch = artJson.active.branch;
|
|
315
|
+
function merge (targetBranch) {
|
|
316
|
+
/**
|
|
317
|
+
* Initialize staging environment and load manifests for the merge operation.
|
|
318
|
+
*/
|
|
216
319
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
320
|
+
const root = process.cwd();
|
|
321
|
+
const artifactPath = path.join(root, '.art');
|
|
322
|
+
const stageDirectory = path.join(artifactPath, 'stage');
|
|
323
|
+
const artifactJson = JSON.parse(
|
|
324
|
+
fs.readFileSync(path.join(artifactPath, 'art.json'), 'utf8')
|
|
325
|
+
);
|
|
326
|
+
const activeBranch = artifactJson.active.branch;
|
|
327
|
+
|
|
328
|
+
if (fs.existsSync(stageDirectory)) {
|
|
329
|
+
fs.rmSync(stageDirectory, { recursive: true, force: true });
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
fs.mkdirSync(stageDirectory, { recursive: true });
|
|
333
|
+
|
|
334
|
+
const activeManifest = JSON.parse(
|
|
335
|
+
fs.readFileSync(path.join(artifactPath, `history/local/${activeBranch}/manifest.json`), 'utf8')
|
|
336
|
+
);
|
|
337
|
+
const targetManifest = JSON.parse(
|
|
338
|
+
fs.readFileSync(path.join(artifactPath, `history/local/${targetBranch}/manifest.json`), 'utf8')
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Locate the most recent common ancestor hash between both branches.
|
|
343
|
+
*/
|
|
344
|
+
|
|
345
|
+
const commonAncestorHash = [...activeManifest.commits].reverse().find(hash => {
|
|
346
|
+
return targetManifest.commits.includes(hash);
|
|
347
|
+
}) || null;
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Capture the file states for the base (ancestor), active, and target branches.
|
|
351
|
+
*/
|
|
352
|
+
|
|
353
|
+
const baseState = commonAncestorHash ? getStateByHash(activeBranch, commonAncestorHash) : {};
|
|
354
|
+
const activeState = getStateByHash(activeBranch, artifactJson.active.parent);
|
|
355
|
+
const lastTargetHash = targetManifest.commits[targetManifest.commits.length - 1];
|
|
356
|
+
const targetState = getStateByHash(targetBranch, lastTargetHash);
|
|
357
|
+
const allFiles = new Set([...Object.keys(activeState), ...Object.keys(targetState)]);
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Prepare the staging mechanism for multi-part change tracking.
|
|
361
|
+
*/
|
|
220
362
|
|
|
221
|
-
|
|
363
|
+
let currentPartChanges = {};
|
|
364
|
+
let currentPartSize = 0;
|
|
365
|
+
let partCount = 0;
|
|
222
366
|
|
|
223
|
-
|
|
224
|
-
|
|
367
|
+
const saveStagePart = () => {
|
|
368
|
+
if (Object.keys(currentPartChanges).length === 0) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
225
371
|
|
|
226
|
-
|
|
372
|
+
const partPath = path.join(stageDirectory, `part.${partCount}.json`);
|
|
227
373
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
374
|
+
fs.writeFileSync(partPath, JSON.stringify({ changes: currentPartChanges }, null, 2));
|
|
375
|
+
currentPartChanges = {};
|
|
376
|
+
currentPartSize = 0;
|
|
377
|
+
partCount++;
|
|
378
|
+
};
|
|
232
379
|
|
|
233
|
-
|
|
380
|
+
/**
|
|
381
|
+
* Iterate through all unique files to determine merge actions.
|
|
382
|
+
*/
|
|
234
383
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
384
|
+
for (const filePath of allFiles) {
|
|
385
|
+
const base = baseState[filePath];
|
|
386
|
+
const active = activeState[filePath];
|
|
387
|
+
const target = targetState[filePath];
|
|
388
|
+
const fullPath = path.join(root, filePath);
|
|
238
389
|
|
|
239
|
-
|
|
240
|
-
|
|
390
|
+
if (active === target) {
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
241
393
|
|
|
242
|
-
|
|
394
|
+
let change = null;
|
|
243
395
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
};
|
|
396
|
+
/**
|
|
397
|
+
* Logic for applying target changes if they don't conflict with active
|
|
398
|
+
* local modifications.
|
|
399
|
+
*/
|
|
249
400
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
401
|
+
if (base === active && base !== target) {
|
|
402
|
+
if (target === undefined) {
|
|
403
|
+
if (fs.existsSync(fullPath)) {
|
|
404
|
+
fs.unlinkSync(fullPath);
|
|
405
|
+
}
|
|
255
406
|
|
|
256
|
-
|
|
407
|
+
change = { type: 'deleteFile' };
|
|
408
|
+
} else {
|
|
409
|
+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
410
|
+
fs.writeFileSync(fullPath, target);
|
|
411
|
+
change = { type: 'createFile', content: target };
|
|
412
|
+
}
|
|
413
|
+
} else if (base !== active && base !== target && active !== target) {
|
|
414
|
+
/**
|
|
415
|
+
* Handle three-way merge conflicts by injecting markers into the target file.
|
|
416
|
+
*/
|
|
257
417
|
|
|
258
|
-
|
|
418
|
+
const conflictContent = `<<<<<<< active\n${active || ''}\n=======\n${target || ''}\n>>>>>>> ${targetBranch}`;
|
|
259
419
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
} else {
|
|
265
|
-
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
266
|
-
fs.writeFileSync(fullPath, target);
|
|
267
|
-
change = { type: 'createFile', content: target };
|
|
268
|
-
}
|
|
269
|
-
} else if (base !== active && base !== target && active !== target) {
|
|
270
|
-
const conflictContent = `<<<<<<< active\n${active || ''}\n=======\n${target || ''}\n>>>>>>> ${targetBranch}`;
|
|
420
|
+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
421
|
+
fs.writeFileSync(fullPath, conflictContent);
|
|
422
|
+
change = { type: 'createFile', content: conflictContent };
|
|
423
|
+
}
|
|
271
424
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
425
|
+
/**
|
|
426
|
+
* Calculate change size and partition the stage.
|
|
427
|
+
*/
|
|
276
428
|
|
|
277
|
-
|
|
278
|
-
|
|
429
|
+
if (change) {
|
|
430
|
+
const changeSize = JSON.stringify(change).length;
|
|
279
431
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
432
|
+
if (currentPartSize + changeSize > MAX_PART_SIZE) {
|
|
433
|
+
saveStagePart();
|
|
434
|
+
}
|
|
283
435
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
436
|
+
currentPartChanges[filePath] = change;
|
|
437
|
+
currentPartSize += changeSize;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Finalize the merge by saving the last stage part and the manifest summary.
|
|
443
|
+
*/
|
|
288
444
|
|
|
289
|
-
|
|
445
|
+
saveStagePart();
|
|
290
446
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
447
|
+
fs.writeFileSync(
|
|
448
|
+
path.join(stageDirectory, 'manifest.json'),
|
|
449
|
+
JSON.stringify({ parts: Array.from({ length: partCount }, (_, index) => `part.${index}.json`) }, null, 2)
|
|
450
|
+
);
|
|
295
451
|
|
|
296
|
-
|
|
297
|
-
|
|
452
|
+
return `Merged ${targetBranch}.`;
|
|
453
|
+
}
|
|
298
454
|
|
|
299
455
|
module.exports = {
|
|
300
|
-
__libraryVersion: '0.3.
|
|
456
|
+
__libraryVersion: '0.3.3',
|
|
301
457
|
__libraryAPIName: 'Branching',
|
|
302
458
|
branch,
|
|
303
459
|
checkout,
|