Add rebuild endpoint — docker compose up --build without git pull

This commit is contained in:
jtricerolph 2026-07-14 13:22:57 +00:00
parent c72ebdf79a
commit db4bb4deb8

View file

@ -193,13 +193,12 @@ async function refreshStatus(repo) {
return entry return entry
} }
async function deploy(target, repoName) { async function runRemote(target, repoName, cmd, label) {
if (!/^\/opt\/[a-z0-9-]+$/.test(target.path)) { if (!/^\/opt\/[a-z0-9-]+$/.test(target.path)) {
app.log.error(`Rejecting suspicious path for deploy: ${target.path}`) app.log.error(`Rejecting suspicious path for ${label}: ${target.path}`)
return return
} }
const remoteCmd = `cd ${target.path} && git pull && docker compose up -d --build` const entry = { repo: repoName, host: target.host, started: new Date().toISOString(), status: 'running', type: label }
const entry = { repo: repoName, host: target.host, started: new Date().toISOString(), status: 'running' }
deployLog.unshift(entry) deployLog.unshift(entry)
if (deployLog.length > 50) deployLog.pop() if (deployLog.length > 50) deployLog.pop()
@ -209,20 +208,28 @@ async function deploy(target, repoName) {
'-o', 'StrictHostKeyChecking=no', '-o', 'StrictHostKeyChecking=no',
'-o', 'UserKnownHostsFile=/dev/null', '-o', 'UserKnownHostsFile=/dev/null',
`root@${target.host}`, `root@${target.host}`,
'sh', '-c', remoteCmd, 'sh', '-c', cmd,
], { timeout: 300_000 }) ], { timeout: 300_000 })
entry.status = 'success' entry.status = 'success'
entry.output = stdout.slice(-500) entry.output = stdout.slice(-500)
app.log.info(`Deploy ${repoName} → success`) app.log.info(`${label} ${repoName} → success`)
delete statusCache[repoName] delete statusCache[repoName]
} catch (err) { } catch (err) {
entry.status = 'failed' entry.status = 'failed'
entry.error = err.message.slice(-500) entry.error = err.message.slice(-500)
app.log.error(`Deploy ${repoName} → failed`) app.log.error(`${label} ${repoName} → failed`)
} }
entry.finished = new Date().toISOString() entry.finished = new Date().toISOString()
} }
async function deploy(target, repoName) {
return runRemote(target, repoName, `cd ${target.path} && git pull && docker compose up -d --build`, 'deploy')
}
async function rebuild(target, repoName) {
return runRemote(target, repoName, `cd ${target.path} && docker compose up -d --build`, 'rebuild')
}
// ── Routes ──────────────────────────────────────────────────────────────────── // ── Routes ────────────────────────────────────────────────────────────────────
app.get('/health', async () => ({ status: 'healthy' })) app.get('/health', async () => ({ status: 'healthy' }))
@ -284,6 +291,18 @@ app.post('/deploy/:repo', async (request, reply) => {
return reply.status(202).send({ ok: true, deploying: repo }) return reply.status(202).send({ ok: true, deploying: repo })
}) })
app.post('/rebuild/:repo', async (request, reply) => {
const { repo } = request.params
const target = getDeployTarget(repo)
if (!target) return reply.status(404).send({ error: 'Unknown repo' })
const running = deployLog.find(d => d.repo === repo && d.status === 'running')
if (running) return reply.status(409).send({ error: 'Deploy already in progress' })
rebuild(target, repo).catch(() => {})
return reply.status(202).send({ ok: true, rebuilding: repo })
})
app.post('/exec', async (request, reply) => { app.post('/exec', async (request, reply) => {
const { host, command } = request.body || {} const { host, command } = request.body || {}
if (!host || !command || typeof command !== 'string' || command.length > 2000) if (!host || !command || typeof command !== 'string' || command.length > 2000)