Files
2026-05-17 14:12:09 +02:00

113 lines
3.4 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { validateUploadSecret } from '@/lib/auth'
import { getRemoteFolder, pushAllToGit } from '@/lib/git'
import { buildCommitMessage } from '@/lib/commit-message'
import { classifyFileChanges } from '@/lib/diff-files'
import { getModelFolderPath } from '@/lib/model-paths'
import { cleanupStagingUpload, ensurePreparedStagingAssets, readStagedManifest } from '@/lib/upload-staging'
import { acquireUploadLock, releaseUploadLock } from '@/lib/upload-lock'
import {
readStagingRequestBody,
uploadErrorMessageResponse,
uploadErrorResponse,
uploadLockConflictResponse,
} from '@/lib/upload-request'
import { getErrorMessage } from '@/lib/guards'
export const runtime = 'nodejs'
export const dynamic = 'force-dynamic'
async function cleanupCompletedStagingUpload(stagingId: string) {
await cleanupStagingUpload(stagingId).catch((err) => {
console.warn('[WARN] Git upload -> staging cleanup failed', {
stagingId,
error: getErrorMessage(err),
})
})
}
/**
* POST /api/upload/git
* Upload prepared files and push to the configured Git remote via Octokit.
*/
export async function POST(req: NextRequest) {
const authError = validateUploadSecret(req)
if (authError) return authError
let folderName: string
let stagingId: string
try {
stagingId = (await readStagingRequestBody(req)).stagingId
const manifest = await readStagedManifest(stagingId)
folderName = manifest.folderName
} catch (err) {
return uploadErrorResponse(err, 400)
}
if (!acquireUploadLock(folderName)) {
return uploadLockConflictResponse()
}
try {
const {
filesToPush,
modelFilename,
compressed,
deliveryMode,
compressionError,
assetSummaries,
} = await ensurePreparedStagingAssets(stagingId)
const folderPath = getModelFolderPath(folderName)
const remote = await getRemoteFolder(folderPath)
const remoteFileMap = new Map(remote.files.map((f) => [f.name.toLowerCase(), f.size]))
const isReplace = remoteFileMap.size > 0
const { fileChanges, changedFilesToPush, deletedFileNames, deletePaths } =
classifyFileChanges(filesToPush, remoteFileMap, folderPath)
if (changedFilesToPush.length === 0 && deletePaths.length === 0) {
await cleanupCompletedStagingUpload(stagingId)
return NextResponse.json({
success: true,
folderName,
filesCount: 0,
compressed,
deliveryMode,
compressionError: compressionError || undefined,
message: 'Aucun fichier modifie — rien a envoyer.',
})
}
const commitMessage = buildCommitMessage(
folderName,
modelFilename,
assetSummaries,
isReplace,
fileChanges,
deletedFileNames,
)
const { commitUrl } = await pushAllToGit(changedFilesToPush, deletePaths, commitMessage)
await cleanupCompletedStagingUpload(stagingId)
return NextResponse.json({
success: true,
folderName,
filesCount: changedFilesToPush.length,
compressed,
deliveryMode,
compressionError: compressionError || undefined,
message: `${changedFilesToPush.length} fichier(s) modifie(s) envoye(s) sur Git en un seul commit.`,
commitUrl,
})
} catch (err) {
const message = getErrorMessage(err, 'Erreur Git inconnue')
return uploadErrorMessageResponse(`Upload Git echoue: ${message}`, 500)
} finally {
releaseUploadLock(folderName)
}
}