refactor: split git provider adapters
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import { isRecord } from '@/lib/guards'
|
||||
import type { RemoteFile } from '@/lib/types'
|
||||
import { decodeBase64Content, encodePath, getRepoApiPath, isHttpError, requestGitJson } from './http'
|
||||
import { isLfsFile, parseLfsPointer } from './lfs'
|
||||
import type { GitRemoteConfig } from './types'
|
||||
|
||||
interface GitContentEntry {
|
||||
content?: string
|
||||
name: string
|
||||
path?: string
|
||||
sha?: string
|
||||
size?: number
|
||||
type?: string
|
||||
}
|
||||
|
||||
function isGitContentEntry(value: unknown): value is GitContentEntry {
|
||||
return isRecord(value)
|
||||
&& typeof value.name === 'string'
|
||||
&& (value.path === undefined || typeof value.path === 'string')
|
||||
&& (value.sha === undefined || typeof value.sha === 'string')
|
||||
&& (value.size === undefined || typeof value.size === 'number')
|
||||
&& (value.content === undefined || typeof value.content === 'string')
|
||||
&& (value.type === undefined || typeof value.type === 'string')
|
||||
}
|
||||
|
||||
function getContentEntrySize(entry: GitContentEntry) {
|
||||
return entry.size ?? 0
|
||||
}
|
||||
|
||||
async function getRemoteContent(remote: GitRemoteConfig, path: string, branch: string) {
|
||||
const query = new URLSearchParams({ ref: branch })
|
||||
return requestGitJson(remote, `${getRepoApiPath(remote)}/contents/${encodePath(path)}?${query.toString()}`)
|
||||
}
|
||||
|
||||
export function getRequiredContentEntrySha(entry: GitContentEntry, path: string) {
|
||||
if (!entry.sha) {
|
||||
throw new Error(`SHA Git manquant pour ${path}`)
|
||||
}
|
||||
|
||||
return entry.sha
|
||||
}
|
||||
|
||||
export async function getRemoteFileEntry(remote: GitRemoteConfig, path: string, branch: string): Promise<GitContentEntry | null> {
|
||||
try {
|
||||
const data = await getRemoteContent(remote, path, branch)
|
||||
return isGitContentEntry(data) ? data : null
|
||||
} catch (err) {
|
||||
if (isHttpError(err) && err.status === 404) return null
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
export async function readRemoteFolder(
|
||||
remote: GitRemoteConfig,
|
||||
branch: string,
|
||||
folderPath: string,
|
||||
): Promise<{ exists: boolean; files: RemoteFile[] }> {
|
||||
try {
|
||||
const data = await getRemoteContent(remote, folderPath, branch)
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
throw new Error(`Le chemin distant ${folderPath} existe mais ce n'est pas un dossier`)
|
||||
}
|
||||
|
||||
const files: RemoteFile[] = await Promise.all(
|
||||
data.map(async (entry: unknown): Promise<RemoteFile> => {
|
||||
if (!isGitContentEntry(entry)) {
|
||||
throw new Error(`Reponse Git invalide pour ${folderPath}`)
|
||||
}
|
||||
|
||||
const size = getContentEntrySize(entry)
|
||||
|
||||
if (!isLfsFile(entry.name) || size > 1024) {
|
||||
return { name: entry.name, size }
|
||||
}
|
||||
|
||||
try {
|
||||
const fileData = await getRemoteFileEntry(remote, `${folderPath}/${entry.name}`, branch)
|
||||
|
||||
if (fileData?.content) {
|
||||
const content = decodeBase64Content(fileData.content)
|
||||
const pointer = parseLfsPointer(content)
|
||||
if (pointer) {
|
||||
return { name: entry.name, size: pointer.size }
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (!isHttpError(err) || err.status !== 404) throw err
|
||||
}
|
||||
|
||||
return { name: entry.name, size }
|
||||
}),
|
||||
)
|
||||
|
||||
return { exists: true, files }
|
||||
} catch (err: unknown) {
|
||||
if (isHttpError(err) && err.status === 404) {
|
||||
return { exists: false, files: [] }
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user