resulgit 1.0.12 → 1.0.14
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/package.json +1 -1
- package/resulgit.js +62 -2
package/package.json
CHANGED
package/resulgit.js
CHANGED
|
@@ -100,6 +100,43 @@ async function request(method, url, body, token) {
|
|
|
100
100
|
return res.text()
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Upload files as blobs via multipart form data
|
|
105
|
+
* @param {string} server - Server URL
|
|
106
|
+
* @param {string} repoId - Repository ID
|
|
107
|
+
* @param {Record<string, string>} files - Map of file paths to content
|
|
108
|
+
* @param {string} token - Auth token
|
|
109
|
+
* @returns {Promise<Record<string, string>>} Map of file paths to blob IDs
|
|
110
|
+
*/
|
|
111
|
+
async function uploadBlobs(server, repoId, files, token) {
|
|
112
|
+
const FormData = (await import('node:buffer')).File ? globalThis.FormData : (await import('undici')).FormData
|
|
113
|
+
const formData = new FormData()
|
|
114
|
+
|
|
115
|
+
for (const [filePath, content] of Object.entries(files)) {
|
|
116
|
+
// Create a Blob/File from the content
|
|
117
|
+
const blob = new Blob([content], { type: 'text/plain' })
|
|
118
|
+
formData.append('files', blob, filePath)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const url = new URL(`/api/repositories/${repoId}/blobs`, server).toString()
|
|
122
|
+
const headers = {}
|
|
123
|
+
if (token) headers['Authorization'] = `Bearer ${token}`
|
|
124
|
+
|
|
125
|
+
const res = await fetch(url, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
headers,
|
|
128
|
+
body: formData
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
if (!res.ok) {
|
|
132
|
+
const text = await res.text()
|
|
133
|
+
throw new Error(`Blob upload failed: ${res.status} ${res.statusText} ${text}`)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const data = await res.json()
|
|
137
|
+
return data.blobs || {}
|
|
138
|
+
}
|
|
139
|
+
|
|
103
140
|
function print(obj, json) {
|
|
104
141
|
if (json) {
|
|
105
142
|
process.stdout.write(JSON.stringify(obj, null, 2) + '\n')
|
|
@@ -1429,8 +1466,31 @@ async function cmdPush(opts) {
|
|
|
1429
1466
|
// Hook doesn't exist or other error, continue
|
|
1430
1467
|
}
|
|
1431
1468
|
|
|
1432
|
-
|
|
1433
|
-
spinnerUpdate(spinner, `
|
|
1469
|
+
// Step 1: Upload files as blobs
|
|
1470
|
+
spinnerUpdate(spinner, `Uploading ${Object.keys(merged).length} file(s)...`)
|
|
1471
|
+
let blobMap = {}
|
|
1472
|
+
try {
|
|
1473
|
+
blobMap = await uploadBlobs(server, remoteMeta.repoId, merged, token)
|
|
1474
|
+
} catch (err) {
|
|
1475
|
+
// If blob upload fails, fall back to sending content directly
|
|
1476
|
+
// (This handles servers that accept content in commits endpoint)
|
|
1477
|
+
spinnerUpdate(spinner, 'Blob upload not available, sending files directly...')
|
|
1478
|
+
blobMap = merged // Use content directly
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
// Step 2: Create commit with blob IDs (or content if blob upload failed)
|
|
1482
|
+
const commitFiles = {}
|
|
1483
|
+
for (const [filePath, content] of Object.entries(merged)) {
|
|
1484
|
+
// Use blob ID if available, otherwise use content
|
|
1485
|
+
commitFiles[filePath] = blobMap[filePath] || content
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
const body = {
|
|
1489
|
+
message: localMeta.pendingCommit?.message || (opts.message || 'Push'),
|
|
1490
|
+
files: commitFiles,
|
|
1491
|
+
branchName: remoteMeta.branch
|
|
1492
|
+
}
|
|
1493
|
+
spinnerUpdate(spinner, `Creating commit on '${remoteMeta.branch}'...`)
|
|
1434
1494
|
const url = new URL(`/api/repositories/${remoteMeta.repoId}/commits`, server).toString()
|
|
1435
1495
|
const data = await request('POST', url, body, token)
|
|
1436
1496
|
localMeta.baseCommitId = data.id || remote.commitId || ''
|