29 lines
1.6 KiB
JavaScript
29 lines
1.6 KiB
JavaScript
import { randomUUID } from 'node:crypto';
|
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
import { git } from './lib.mjs';
|
|
|
|
export const lockRef = 'refs/heads/automation/release-lock';
|
|
|
|
export async function acquireLock({ runGit = git, wait = sleep, attempts = 480, ref = lockRef } = {}) {
|
|
const lockSha = runGit(['-c', 'user.name=FEDEO Release', '-c', 'user.email=release@fedeo.de',
|
|
'commit-tree', 'HEAD^{tree}', '-p', 'HEAD', '-m', `chore(release): lock ${randomUUID()}`]);
|
|
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
const existing = runGit(['ls-remote', 'origin', ref]);
|
|
if (!existing) {
|
|
try {
|
|
// An empty lease means the ref MUST NOT exist, even if another runner just created it.
|
|
runGit(['push', `--force-with-lease=${ref}:`, 'origin', `${lockSha}:${ref}`]);
|
|
return () => runGit(['push', `--force-with-lease=${ref}:${lockSha}`, 'origin', `:${ref}`]);
|
|
} catch (error) {
|
|
if (/403|forbidden|permission denied|authentication failed/i.test(String(error.stderr || error.message))) {
|
|
throw new Error('Die main-Release-Sperre benötigt Git-Schreibrechte. RELEASE_TOKEN (Secret oder Variable) oder den bisherigen vars.CI_TOKEN mit write:repository und Zugriff auf automation/release-lock konfigurieren.');
|
|
}
|
|
if (!runGit(['ls-remote', 'origin', ref])) throw error;
|
|
}
|
|
}
|
|
if (attempt % 4 === 0) console.log('Ein anderer Release läuft; warte auf die Git-Sperre.');
|
|
await wait(15_000);
|
|
}
|
|
throw new Error(`Release-Sperre ${ref} bleibt belegt. Siehe docs/releases.md zur Wiederaufnahme.`);
|
|
}
|