removed some faulty tests
This commit is contained in:
+5
-11
@@ -227,15 +227,9 @@ Der Initialisierungsbildschirm bleibt nach erfolgreichem Laden sichtbar. Erst ei
|
|||||||
|
|
||||||
Gemeinsame Entwürfe und Wichtelcodes: [Gruppenbearbeitung.md](Gruppenbearbeitung.md).
|
Gemeinsame Entwürfe und Wichtelcodes: [Gruppenbearbeitung.md](Gruppenbearbeitung.md).
|
||||||
|
|
||||||
## Deployment-Freigabe
|
## Workflow und Deployment
|
||||||
|
|
||||||
Automatische Deployments benötigen ein erfolgreiches SonarQube Quality Gate.
|
Der Workflow liegt unter `.gitea/workflows/build-and-deploy.yaml`. Seine
|
||||||
Der Analysejob erzeugt danach eine Freigabe für den geprüften Commit, den
|
Quality-Gate-Konfiguration und Job-Abhängigkeiten werden vom Projektinhaber
|
||||||
Workflow-Lauf und dessen aktuellen Versuch. Ohne passende Freigabe darf das
|
gepflegt. Beim Prüfen eines Laufs sind Testergebnis, SonarQube-Ergebnis und
|
||||||
Deployment nicht fortfahren. Das SSH-Skript übernimmt ausschließlich diesen
|
Deployment-Status jeweils einzeln zu beachten.
|
||||||
Commit und prüft ihn vor dem Neustart des App-Dienstes. So kann ein inzwischen
|
|
||||||
weiter fortgeschrittener Branch nicht unbemerkt als ungeprüfter Stand starten.
|
|
||||||
|
|
||||||
Der ausdrücklich manuell ausgewählte Workflow-Aufruf `job=deploy` bleibt als
|
|
||||||
bestehender Override verfügbar. Er benötigt eine bewusste Auswahl und ersetzt
|
|
||||||
keine neue Analyse. Ein gewöhnlicher Push kann diesen Override nicht verwenden.
|
|
||||||
|
|||||||
+9
-17
@@ -179,21 +179,13 @@ Rechte fremder Urheber und bestehende Lizenzen bleiben davon unberührt.
|
|||||||
Vor Änderungen an Gruppenrechten und Code-Eingabe zusätzlich
|
Vor Änderungen an Gruppenrechten und Code-Eingabe zusätzlich
|
||||||
`docs/agents/GRUPPENBEARBEITUNG.md` lesen und bei Übergaben ausdrücklich nennen.
|
`docs/agents/GRUPPENBEARBEITUNG.md` lesen und bei Übergaben ausdrücklich nennen.
|
||||||
|
|
||||||
## Deployment-Freigabe nach dem Quality Gate
|
## Zuständigkeit für Quality Gate und Workflow
|
||||||
|
|
||||||
Am 18. Oktober 2026 ist Lauf 1828 für Commit 0e4cdfb trotz fehlgeschlagenem
|
Nutzervorgabe vom 18. Oktober 2026: Der Nutzer bearbeitet das Quality Gate und
|
||||||
Quality Gate bis zum erfolgreichen Deployment gelaufen. Die vorhandene
|
seine Workflow-Abhängigkeiten selbst. Diese Konfiguration und Abhängigkeiten
|
||||||
jobweite `if`-Bedingung allein hat das Deployment nicht verhindert.
|
nicht eigenständig ändern oder debuggen. Beim Monitoring ihre Ergebnisse
|
||||||
|
melden; weitere Änderungen daran benötigen einen ausdrücklichen Auftrag.
|
||||||
- Automatische Deployments benötigen ein erst nach erfolgreichem Gate erzeugtes
|
Die zuvor vorgeschlagene zusätzliche Freigabeartefakt-Kette wurde nicht
|
||||||
Freigabeartefakt für genau Commit, Workflow-Lauf und Laufversuch.
|
übernommen. Dazu gehörende Tests und Dokumentationsanforderungen gelten nicht.
|
||||||
- Im Deployment-Schritt muss die Freigabe geprüft werden; im SSH-Skript müssen
|
Test- und Quellcodekorrekturen innerhalb des beauftragten App-Umfangs bleiben
|
||||||
eine fehlende Freigabe und ein abweichender Commit vor Änderungen abgewiesen
|
möglich; dabei keine Workflow-Änderungen voraussetzen.
|
||||||
werden. Nur den freigegebenen Commit übernehmen und vor dem Neustart prüfen.
|
|
||||||
- Der bestehende ausdrückliche manuelle Aufruf `job=deploy` bleibt ein bewusster
|
|
||||||
Override. Ein Push darf diese Ausnahme nicht aktivieren.
|
|
||||||
- Verhaltenstests in `test/deployment-workflow.test.js` ausführen. Sie führen die
|
|
||||||
tatsächlichen Shell-Blöcke mit isolierten Dateien und simulierten externen
|
|
||||||
Befehlen aus; keine echten SSH-Verbindungen oder Neustarts im Test.
|
|
||||||
- Die neue Freigabekette muss nach dem nächsten Check-in im echten Workflow
|
|
||||||
bestätigt werden. Lokale Shell-Tests ersetzen keine erfolgreiche Pipeline.
|
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
import assert from 'node:assert/strict';
|
|
||||||
import fs from 'node:fs';
|
|
||||||
import os from 'node:os';
|
|
||||||
import path from 'node:path';
|
|
||||||
import { spawnSync } from 'node:child_process';
|
|
||||||
import test from 'node:test';
|
|
||||||
|
|
||||||
const workflow = fs.readFileSync(new URL('../.gitea/workflows/build-and-deploy.yaml', import.meta.url), 'utf8');
|
|
||||||
const commit = 'a'.repeat(40);
|
|
||||||
function script(name, attribute = 'run') {
|
|
||||||
const lines = workflow.split('\n');
|
|
||||||
const start = lines.findIndex(line => line.trim() === `- name: ${name}`);
|
|
||||||
assert.notEqual(start, -1);
|
|
||||||
const offset = lines.findIndex((line, index) => index > start && line.trim() === `${attribute}: |-`);
|
|
||||||
assert.notEqual(offset, -1);
|
|
||||||
const indent = lines[offset].search(/\S/) + 2;
|
|
||||||
const result = [];
|
|
||||||
for (const line of lines.slice(offset + 1)) {
|
|
||||||
if (line.trim() && line.search(/\S/) < indent) break;
|
|
||||||
result.push(line.slice(indent));
|
|
||||||
}
|
|
||||||
return result.join('\n');
|
|
||||||
}
|
|
||||||
function fixture(t) {
|
|
||||||
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'wegwichtel-deploy-'));
|
|
||||||
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
|
|
||||||
const output = path.join(directory, 'output');
|
|
||||||
const env = { ...process.env, EXPECTED_COMMIT: commit, WORKFLOW_RUN: '1828', WORKFLOW_ATTEMPT: '1',
|
|
||||||
RUN_EVENT: 'push', SELECTED_JOB: '', GITHUB_OUTPUT: output };
|
|
||||||
function run(source, extra = {}) { return spawnSync('sh', ['-s'], { input: source, cwd: directory, env: { ...env, ...extra }, encoding: 'utf8' }); }
|
|
||||||
function proof(value = `${commit}:1828:1`) {
|
|
||||||
fs.mkdirSync(path.join(directory, 'deployment-approval'), { recursive: true });
|
|
||||||
fs.writeFileSync(path.join(directory, 'deployment-approval', 'quality-gate-passed.txt'), value);
|
|
||||||
}
|
|
||||||
return { directory, output, env, run, proof };
|
|
||||||
}
|
|
||||||
|
|
||||||
test('a deployment approval is written only after the Quality Gate step succeeded', t => {
|
|
||||||
const h = fixture(t), source = script('Write deployment approval');
|
|
||||||
for (const outcome of ['', 'failure', 'skipped', 'cancelled']) {
|
|
||||||
assert.notEqual(h.run(source, { GATE_OUTCOME: outcome }).status, 0);
|
|
||||||
assert.equal(fs.existsSync(path.join(h.directory, 'quality-gate-passed.txt')), false);
|
|
||||||
}
|
|
||||||
assert.equal(h.run(source, { GATE_OUTCOME: 'success' }).status, 0);
|
|
||||||
assert.equal(fs.readFileSync(path.join(h.directory, 'quality-gate-passed.txt'), 'utf8'), `${commit}:1828:1\n`);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('push deployments reject missing, mismatching and previous-attempt approval artifacts', t => {
|
|
||||||
const h = fixture(t), source = script('Verify deployment approval');
|
|
||||||
assert.notEqual(h.run(source).status, 0);
|
|
||||||
for (const proof of ['wrong', `${'b'.repeat(40)}:1828:1`, `${commit}:1827:1`, `${commit}:1828:0`]) {
|
|
||||||
h.proof(proof); assert.notEqual(h.run(source).status, 0);
|
|
||||||
assert.equal(fs.existsSync(h.output), false);
|
|
||||||
}
|
|
||||||
h.proof(); assert.equal(h.run(source).status, 0);
|
|
||||||
assert.equal(fs.readFileSync(h.output, 'utf8'), `commit=${commit}\n`);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('only an explicit manual deploy can use the existing manual override', t => {
|
|
||||||
const h = fixture(t), source = script('Verify deployment approval');
|
|
||||||
assert.notEqual(h.run(source, { RUN_EVENT: 'push', SELECTED_JOB: 'deploy' }).status, 0);
|
|
||||||
assert.notEqual(h.run(source, { RUN_EVENT: 'workflow_dispatch', SELECTED_JOB: 'all' }).status, 0);
|
|
||||||
assert.equal(h.run(source, { RUN_EVENT: 'workflow_dispatch', SELECTED_JOB: 'deploy' }).status, 0);
|
|
||||||
assert.equal(fs.readFileSync(h.output, 'utf8'), `commit=${commit}\n`);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('the remote script refuses missing approval before git access and restarts only the approved commit', t => {
|
|
||||||
const h = fixture(t), source = script('Deploy Wegwichtel', 'script');
|
|
||||||
const log = path.join(h.directory, 'calls');
|
|
||||||
const stubs = String.raw`
|
|
||||||
cd() { return 0; }
|
|
||||||
git() {
|
|
||||||
printf 'git %s\n' "$*" >> "$TASK_LOG"
|
|
||||||
if [ "$1" = merge ] && [ "$MERGE_FAILS" = yes ]; then return 1; fi
|
|
||||||
if [ "$1" = rev-parse ]; then printf '%s\n' "$ACTUAL_COMMIT"; fi
|
|
||||||
}
|
|
||||||
systemctl() { printf 'systemctl %s\n' "$*" >> "$TASK_LOG"; }
|
|
||||||
`;
|
|
||||||
const invoke = (approval, actual = commit, mergeFails = 'no') => h.run(stubs + source, {
|
|
||||||
DEPLOY_APPROVED_COMMIT: approval, ACTUAL_COMMIT: actual, TASK_LOG: log, MERGE_FAILS: mergeFails
|
|
||||||
});
|
|
||||||
assert.notEqual(invoke('').status, 0); assert.equal(fs.existsSync(log), false);
|
|
||||||
assert.notEqual(invoke('b'.repeat(40)).status, 0); assert.equal(fs.existsSync(log), false);
|
|
||||||
assert.notEqual(invoke(commit, 'b'.repeat(40)).status, 0);
|
|
||||||
assert.doesNotMatch(fs.readFileSync(log, 'utf8'), /systemctl/);
|
|
||||||
fs.rmSync(log);
|
|
||||||
assert.notEqual(invoke(commit, commit, 'yes').status, 0);
|
|
||||||
assert.doesNotMatch(fs.readFileSync(log, 'utf8'), /systemctl/);
|
|
||||||
fs.rmSync(log);
|
|
||||||
assert.equal(invoke(commit).status, 0);
|
|
||||||
const calls = fs.readFileSync(log, 'utf8');
|
|
||||||
assert.match(calls, new RegExp(`git merge --ff-only ${commit}`));
|
|
||||||
assert.match(calls, /systemctl --user restart wegwichtel.service/);
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user