refactor: split git provider adapters

This commit is contained in:
Tom Boullay
2026-05-17 14:12:09 +02:00
parent 377ed7cfb3
commit 81c513ee1f
13 changed files with 779 additions and 644 deletions
+102
View File
@@ -0,0 +1,102 @@
import { getRemoteFileEntry, getRequiredContentEntrySha, readRemoteFolder } from '../content'
import { getRepoApiPath, requestGitJson } from '../http'
import { buildLfsPointer, splitLfsFiles, uploadToLfs } from '../lfs'
import type { GitProvider, GitRemoteConfig, LfsPushFile, PushFilesParams } from '../types'
import type { PushFile } from '@/lib/types'
import { isRecord } from '@/lib/guards'
interface GiteaFileOperation {
content?: string
operation: 'create' | 'update' | 'delete'
path: string
sha?: string
}
function getGiteaCommitUrl(value: unknown, remote: GitRemoteConfig, branch: string) {
if (isRecord(value) && isRecord(value.commit)) {
if (typeof value.commit.html_url === 'string') return value.commit.html_url
if (typeof value.commit.sha === 'string') return `${remote.webUrl}/commit/${value.commit.sha}`
}
return `${remote.webUrl}/commits/branch/${branch}`
}
function buildCommittedFiles(regularFiles: PushFile[], lfsFiles: LfsPushFile[]): PushFile[] {
return [
...regularFiles,
...lfsFiles.map((file) => ({
path: file.path,
contentBase64: Buffer.from(buildLfsPointer(file.oid, file.size), 'utf-8').toString('base64'),
})),
]
}
async function buildGiteaOperations(
remote: GitRemoteConfig,
branch: string,
committedFiles: PushFile[],
deletePaths: string[],
) {
const newFilePaths = new Set(committedFiles.map((file) => file.path))
const operations: GiteaFileOperation[] = []
for (const file of committedFiles) {
const existing = await getRemoteFileEntry(remote, file.path, branch)
operations.push({
content: file.contentBase64,
operation: existing ? 'update' : 'create',
path: file.path,
sha: existing ? getRequiredContentEntrySha(existing, file.path) : undefined,
})
}
for (const path of deletePaths) {
if (newFilePaths.has(path)) continue
const existing = await getRemoteFileEntry(remote, path, branch)
if (!existing) continue
operations.push({
operation: 'delete',
path,
sha: getRequiredContentEntrySha(existing, path),
})
}
return operations
}
export function createGiteaProvider(remote: GitRemoteConfig, branch: string): GitProvider {
return {
getRemoteFolder(folderPath) {
return readRemoteFolder(remote, branch, folderPath)
},
async pushFiles({ files, deletePaths, commitMessage }: PushFilesParams) {
const { lfsFiles, regularFiles } = splitLfsFiles(files)
await uploadToLfs(
remote,
lfsFiles.map((file) => ({ oid: file.oid, size: file.size, contentBase64: file.contentBase64 })),
)
const committedFiles = buildCommittedFiles(regularFiles, lfsFiles)
const operations = await buildGiteaOperations(remote, branch, committedFiles, deletePaths)
if (operations.length === 0) {
return { commitUrl: `${remote.webUrl}/commits/branch/${branch}` }
}
const data = await requestGitJson(remote, `${getRepoApiPath(remote)}/contents`, {
method: 'POST',
body: {
branch,
files: operations,
message: commitMessage,
},
})
return { commitUrl: getGiteaCommitUrl(data, remote, branch) }
},
}
}