Preview: Dev-Modus nur mit dev-Skript waehlbar
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a5cb668853
commit
04b45e4207
5 files changed
+159
-7
No files matched your search
@@ -9,12 +9,14 @@ import * as runnerClient from '../../services/previewRunnerClient.js'
|
||||
import { runDeploy, fetchPreviewConfig } from '../../services/previewDeploy.js'
|
||||
import { withLocks } from '../../services/keyedLock.js'
|
||||
import { getRepoInfo } from '../../services/giteaAdmin.js'
|
||||
import { repoHasDevScript } from '../../services/previewDevScript.js'
|
||||
|
||||
const router = Router()
|
||||
router.use(requireAppwriteStaff)
|
||||
|
||||
const BUSY = 'Server ausgelastet, versuche es gleich noch mal'
|
||||
const MODES = ['auto', 'build', 'dev', 'off']
|
||||
const NO_DEV = 'Dieses Projekt hat kein dev-Skript. Reines HTML braucht keinen Dev-Server – Änderungen erscheinen nach jedem Push automatisch.'
|
||||
const SHA_RE = /^[0-9a-f]{7,40}$/
|
||||
|
||||
function fail(status, message) {
|
||||
@@ -62,10 +64,14 @@ async function view(doc) {
|
||||
}
|
||||
}
|
||||
|
||||
async function previewBranchOf(doc) {
|
||||
return doc.previewBranch || (await getRepoInfo(doc.repoFullName).catch(() => null))?.defaultBranch || 'main'
|
||||
}
|
||||
|
||||
// Neubau anstossen (wie beim Bearbeiten/Reaktivieren eines Projekts)
|
||||
async function triggerRebuild(doc) {
|
||||
const repo = doc.repoFullName
|
||||
const branch = doc.previewBranch || (await getRepoInfo(repo).catch(() => null))?.defaultBranch || 'main'
|
||||
const branch = await previewBranchOf(doc)
|
||||
const found = await fetchPreviewConfig(repo, branch).catch(() => null)
|
||||
const cfg = {
|
||||
enabled: true,
|
||||
@@ -93,7 +99,11 @@ const wrap = (fn) => async (req, res) => {
|
||||
}
|
||||
|
||||
router.get('/:id/preview', wrap(async (req, res) => {
|
||||
res.json(await view(await loadProject(req.params.id)))
|
||||
const doc = await loadProject(req.params.id)
|
||||
const devAvailable = doc.repoFullName
|
||||
? await repoHasDevScript(doc.repoFullName, await previewBranchOf(doc)).catch(() => null)
|
||||
: null
|
||||
res.json({ ...(await view(doc)), devAvailable })
|
||||
}))
|
||||
|
||||
router.patch('/:id/preview', wrap(async (req, res) => {
|
||||
@@ -110,6 +120,10 @@ router.patch('/:id/preview', wrap(async (req, res) => {
|
||||
}
|
||||
return res.json(await view(await getDocument(col(), doc.$id)))
|
||||
}
|
||||
if (mode === 'dev' && doc.repoFullName) {
|
||||
const has = await repoHasDevScript(doc.repoFullName, await previewBranchOf(doc)).catch(() => null)
|
||||
if (has === false) throw fail(400, NO_DEV)
|
||||
}
|
||||
const updated = await updateDocument(col(), doc.$id, { previewMode: mode })
|
||||
await triggerRebuild(updated)
|
||||
res.json(await view(await getDocument(col(), doc.$id)))
|
||||
|
||||
@@ -540,6 +540,7 @@ export async function syncPreviewTlsOnStartup({
|
||||
// ---- Preview-Runner (PREVIEW_RUNNER=on) ----
|
||||
|
||||
// Zeiten des Hintergrund-Verfolgers (fuer Tests ueberschreibbar)
|
||||
const NO_DEV_SCRIPT_ERROR = 'Kein dev-Skript in package.json'
|
||||
export const runnerTiming = { pollMs: 2000, maxMs: 60 * 60 * 1000, unreachableMs: 5 * 60 * 1000 }
|
||||
// Neuester Lauf je Repo: aeltere Verfolger schreiben nichts mehr (R14)
|
||||
const latestRun = new Map()
|
||||
@@ -679,7 +680,9 @@ async function followRun({ repoFullName, project, token, runId, subdomain, job,
|
||||
} else {
|
||||
await patchProject(repoFullName, project, {
|
||||
previewState: 'failed',
|
||||
previewError: maskLog(failure || run?.error || 'Preview-Build fehlgeschlagen', env),
|
||||
previewError: run?.error === NO_DEV_SCRIPT_ERROR && !failure
|
||||
? 'Dev-Modus hier nicht möglich – statische Version ist online'
|
||||
: maskLog(failure || run?.error || 'Preview-Build fehlgeschlagen', env),
|
||||
})
|
||||
}
|
||||
if (!current()) return
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Prueft, ob ein Repo-Branch ein dev-Skript in package.json hat (Dev-Modus nur dann sinnvoll).
|
||||
import { giteaFetch, splitRepo } from './giteaClient.js'
|
||||
|
||||
export const cacheTtlMs = 60 * 1000
|
||||
const cache = new Map()
|
||||
|
||||
export function clearDevScriptCache() { cache.clear() }
|
||||
|
||||
/** true = dev-Skript vorhanden, false = kein package.json oder kein dev-Skript, null = unbekannt (Gitea-Fehler). */
|
||||
export async function repoHasDevScript(repoFullName, branch) {
|
||||
const key = `${repoFullName}@${branch}`
|
||||
const hit = cache.get(key)
|
||||
if (hit && Date.now() - hit.at < cacheTtlMs) return hit.value
|
||||
const value = await lookup(repoFullName, branch)
|
||||
cache.set(key, { at: Date.now(), value })
|
||||
return value
|
||||
}
|
||||
|
||||
async function lookup(repoFullName, branch) {
|
||||
const [owner, repo] = splitRepo(repoFullName)
|
||||
if (!owner || !repo) return null
|
||||
let data
|
||||
try {
|
||||
data = await giteaFetch(`/repos/${owner}/${repo}/contents/package.json?ref=${encodeURIComponent(branch)}`)
|
||||
} catch (err) {
|
||||
return err?.status === 404 ? false : null
|
||||
}
|
||||
try {
|
||||
const pkg = JSON.parse(Buffer.from(data?.content || '', 'base64').toString('utf8'))
|
||||
const dev = pkg?.scripts?.dev
|
||||
return typeof dev === 'string' && dev.trim() !== ''
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user