import { test, before, after } from 'node:test' import assert from 'node:assert/strict' import { execFileSync } from 'node:child_process' import fs from 'node:fs/promises' import os from 'node:os' import path from 'node:path' // 2026-09-30 (Kirschner Gebäudeservice): Projektänderung und Gitea-Webhook deployten dasselbe // Repo gleichzeitig, beide git clone liefen ins selbe Arbeitsverzeichnis und brachen ab. let tmp let previewDeploy const cwd = process.cwd() before(async () => { tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'preview-lock-')) const repo = path.join(tmp, 'gitea', 'WEBklar', 'kunde.git') const src = path.join(tmp, 'src') await fs.mkdir(src, { recursive: true }) // Genug Inhalt, dass ein Klon Zeit braucht und sich zwei Klone überschneiden for (let i = 0; i < 300; i += 1) await fs.writeFile(path.join(src, `seite-${i}.html`), `

${i}

`.repeat(200)) await fs.writeFile(path.join(src, 'index.html'), 'Kunde') const git = (args, dir) => execFileSync('git', args, { cwd: dir, stdio: 'ignore' }) git(['init', '-q', '-b', 'main'], src) git(['-c', 'user.name=t', '-c', 'user.email=t@t', 'add', '.'], src) git(['-c', 'user.name=t', '-c', 'user.email=t@t', 'commit', '-q', '-m', 'init'], src) git(['clone', '-q', '--bare', src, repo], tmp) await fs.mkdir(path.join(tmp, 'work')) process.chdir(path.join(tmp, 'work')) // previewWorkDir() liegt unter process.cwd() Object.assign(process.env, { APPWRITE_ENDPOINT: 'http://127.0.0.1:9/v1', APPWRITE_API_KEY: 'test-key', GITEA_BASE_URL: `file://${path.join(tmp, 'gitea')}`, GITEA_API_TOKEN: '', PREVIEW_DEPLOY_ROOT: path.join(tmp, 'previews'), TRAEFIK_DYNAMIC_DIR: '', }) previewDeploy = await import('../server/services/previewDeploy.js') }) after(async () => { process.chdir(cwd) await fs.rm(tmp, { recursive: true, force: true }) }) test('gleichzeitige Deploys desselben Repos laufen nacheinander und gelingen beide', async () => { const cfg = { subdomain: 'kunde', type: 'static' } const results = await Promise.allSettled([ previewDeploy.runDeploy('WEBklar/kunde', 'main', cfg), previewDeploy.runDeploy('WEBklar/kunde', 'main', cfg), previewDeploy.runDeploy('WEBklar/kunde', 'main', cfg), ]) for (const r of results) assert.equal(r.status, 'fulfilled', r.reason?.message) assert.match(await fs.readFile(path.join(tmp, 'previews', 'kunde', 'index.html'), 'utf8'), /Kunde/) assert.equal((await fs.readdir(path.join(tmp, 'previews', 'kunde'))).filter((f) => f.startsWith('seite-')).length, 300) })