Prozessbibliothek als eigenes Repository auslagern (#9)
- ADR 0004 ersetzt ADR 0003: Die Prozessmodelle liegen im Repository AG_Prozesse/Prozessbibliothek, geklont nach Prozessbibliothek/ (neuer Eintrag in workspace.toml, .gitignore). prozesse/ ist entfernt; das Ablageformat (Ordner je Prozess, drei Dateien, Status) bleibt. - pruefe_prozesse.py prüft den Klon (Ort über setup_workspace.repos_root), lässt Punkt-Ordner wie .git aus und erlaubt in der Wurzel nur die Repo-Dateien. Fehlt der Klon, gibt es einen Hinweis statt eines Befunds; pytest warnt dann. - einlesen.py sucht den Bestand in der Bibliothek und nennt Treffer als Prozessbibliothek/<name>/, auch wenn der Klon woanders liegt. - Regeln aus prozesse/README.md nach docs/leitfaden/08_prozessbibliothek.md, inklusive Ablauf bei Konverteränderungen (zwei Pull Requests). - Verweise in AGENTS.md, README, Skills, Leitfäden, Vorlagen, Fallstricken und STATUS nachgezogen. - Tests: python -m pytest -q -> 88 bestanden, 1 xfail (#8), 1 Warnung (Bibliothek noch nicht geklont). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+24
-7
@@ -22,18 +22,18 @@ FESTE_ZEIT = datetime(2026, 9, 23, 14, 5, 12, tzinfo=timezone(timedelta(hours=2)
|
||||
|
||||
@pytest.fixture
|
||||
def ws(tmp_path, monkeypatch):
|
||||
"""Leerer Workspace mit input/, prozesse/ und entwuerfe/ an Stelle des echten."""
|
||||
for name in ("input", "prozesse", "entwuerfe"):
|
||||
"""Leerer Workspace mit input/, entwuerfe/ und geklonter Prozessbibliothek an Stelle des echten."""
|
||||
for name in ("input", "Prozessbibliothek", "entwuerfe"):
|
||||
(tmp_path / name).mkdir()
|
||||
monkeypatch.setattr(einlesen, "ROOT", tmp_path)
|
||||
monkeypatch.setattr(einlesen, "EINGANG", tmp_path / "input")
|
||||
monkeypatch.setattr(einlesen, "PROZESSE", tmp_path / "prozesse")
|
||||
monkeypatch.setattr(einlesen, "BIBLIOTHEK", tmp_path / "Prozessbibliothek")
|
||||
monkeypatch.setattr(einlesen, "ENTWUERFE", tmp_path / "entwuerfe")
|
||||
return tmp_path
|
||||
|
||||
|
||||
def lege_prozess_an(ws, name, text):
|
||||
ordner = ws / "prozesse" / name
|
||||
ordner = ws / "Prozessbibliothek" / name
|
||||
ordner.mkdir()
|
||||
(ordner / f"{name}.md").write_text(text, encoding="utf-8")
|
||||
(ordner / "README.md").write_text(f"# {name}\n\n| | |\n|---|---|\n| Status | Entwurf |\n", encoding="utf-8")
|
||||
@@ -92,11 +92,11 @@ def test_neue_md_mit_titel_namensvorschlag_und_art(ws):
|
||||
|
||||
|
||||
def test_gleichnamiger_prozess_wird_als_kandidat_mit_1_gemeldet(ws):
|
||||
"""Prüft, dass ein vorhandener Prozess mit gleichem Ordnernamen als Kandidat mit Ähnlichkeit 1 erscheint."""
|
||||
"""Prüft, dass ein Prozess der Bibliothek mit gleichem Ordnernamen als Kandidat mit Ähnlichkeit 1 erscheint."""
|
||||
lege_prozess_an(ws, "antrag-pruefen", ARBEITSSCHRITTE)
|
||||
(ws / "input" / "neu.md").write_text(ARBEITSSCHRITTE.replace("erfassen", "prüfen"), encoding="utf-8")
|
||||
kandidaten = eintrag(einlesen.pruefe_eingang(), "neu.md")["kandidaten"]
|
||||
assert kandidaten[0]["pfad"] == "prozesse/antrag-pruefen/"
|
||||
assert kandidaten[0]["pfad"] == "Prozessbibliothek/antrag-pruefen/"
|
||||
assert kandidaten[0]["aehnlichkeit"] == 1.0
|
||||
|
||||
|
||||
@@ -117,6 +117,23 @@ def test_gitea_entwuerfe_zaehlen_nicht_zum_bestand(ws):
|
||||
assert einlesen.pruefe_eingang()["bestand"] == []
|
||||
|
||||
|
||||
def test_punktordner_der_bibliothek_zaehlen_nicht_zum_bestand(ws):
|
||||
"""Prüft, dass .git und andere Punkt-Ordner im Bibliotheks-Klon nicht als Prozess gelten."""
|
||||
(ws / "Prozessbibliothek" / ".git").mkdir()
|
||||
assert einlesen.pruefe_eingang()["bestand"] == []
|
||||
|
||||
|
||||
def test_bibliothek_ausserhalb_des_workspace_wird_mit_ihrem_namen_genannt(ws, tmp_path_factory, monkeypatch):
|
||||
"""Prüft, dass ein Prozess auch dann als 'Prozessbibliothek/<name>/' erscheint, wenn der Klon woanders liegt."""
|
||||
anderswo = tmp_path_factory.mktemp("klone") / "Prozessbibliothek"
|
||||
anderswo.mkdir()
|
||||
monkeypatch.setattr(einlesen, "BIBLIOTHEK", anderswo)
|
||||
ordner = anderswo / "antrag-pruefen"
|
||||
ordner.mkdir()
|
||||
(ordner / "antrag-pruefen.md").write_text(ARBEITSSCHRITTE, encoding="utf-8")
|
||||
assert [e["pfad"] for e in einlesen.pruefe_eingang()["bestand"]] == ["Prozessbibliothek/antrag-pruefen/"]
|
||||
|
||||
|
||||
def test_vermerk_steht_oben_mit_zeitstempel_und_markiert_als_eingelesen(ws):
|
||||
"""Prüft, dass der Vermerk als erste Zeile mit Zeitstempel geschrieben wird und die Datei danach als eingelesen gilt."""
|
||||
datei = ws / "input" / "antrag.md"
|
||||
@@ -156,7 +173,7 @@ def test_zweiter_vermerk_kommt_obenauf_der_erste_bleibt(ws):
|
||||
datei = ws / "input" / "antrag.md"
|
||||
datei.write_text(ARBEITSSCHRITTE, encoding="utf-8")
|
||||
einlesen.setze_vermerk(datei, "neu", "entwuerfe/antrag-pruefen.md", jetzt=FESTE_ZEIT)
|
||||
einlesen.setze_vermerk(datei, "aktualisiert", "prozesse/antrag-pruefen/", jetzt=FESTE_ZEIT + timedelta(days=1))
|
||||
einlesen.setze_vermerk(datei, "aktualisiert", "Prozessbibliothek/antrag-pruefen/", jetzt=FESTE_ZEIT + timedelta(days=1))
|
||||
zeilen = datei.read_text(encoding="utf-8").splitlines()
|
||||
assert "2026-09-24" in zeilen[0] and "aktualisiert" in zeilen[0]
|
||||
assert "2026-09-23" in zeilen[1] and "| neu |" in zeilen[1]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Tests für scripts/pruefe_prozesse.py und für den Bestand unter prozesse/ – reines Python/pytest."""
|
||||
"""Tests für scripts/pruefe_prozesse.py und für den Bestand der Prozessbibliothek – reines Python/pytest."""
|
||||
import sys
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
@@ -32,11 +33,47 @@ def lege_prozess_an(wurzel, name="test-prozess", status="Entwurf"):
|
||||
return ordner
|
||||
|
||||
|
||||
def test_bestand_unter_prozesse_und_beispiele_ist_konsistent():
|
||||
"""Prüft, dass alle Prozessordner und Skill-Beispiele im Repository ohne Befund sind."""
|
||||
def test_bestand_der_bibliothek_und_beispiele_ist_konsistent():
|
||||
"""Prüft, dass alle Prozessordner der geklonten Prozessbibliothek und die Skill-Beispiele ohne Befund sind."""
|
||||
if not pp.BIBLIOTHEK.is_dir():
|
||||
warnings.warn(f"Prozessbibliothek nicht geklont ({pp.BIBLIOTHEK}) – nur die Skill-Beispiele geprüft. "
|
||||
"Klonen mit: python scripts/setup_workspace.py")
|
||||
assert pp.pruefe_alles() == []
|
||||
|
||||
|
||||
def test_bibliothek_liegt_als_klon_neben_projektwissen():
|
||||
"""Prüft, dass die Prozessbibliothek unter dem Klon-Ordner aus workspace.toml/workspace.local.toml gesucht wird."""
|
||||
import setup_workspace
|
||||
assert pp.BIBLIOTHEK == setup_workspace.repos_root() / "Prozessbibliothek"
|
||||
|
||||
|
||||
def test_prozessordner_ohne_punktordner(tmp_path):
|
||||
"""Prüft, dass .git und andere Punkt-Ordner im Bibliotheks-Klon nicht als Prozess gelten."""
|
||||
lege_prozess_an(tmp_path)
|
||||
(tmp_path / ".git").mkdir()
|
||||
(tmp_path / ".gitea").mkdir()
|
||||
assert [o.name for o in pp.prozessordner(tmp_path)] == ["test-prozess"]
|
||||
|
||||
|
||||
def test_fremde_datei_in_der_bibliothekswurzel_wird_gemeldet(tmp_path):
|
||||
"""Prüft, dass in der Wurzel der Bibliothek nur die Repo-Dateien erlaubt sind und alles andere gemeldet wird."""
|
||||
lege_prozess_an(tmp_path)
|
||||
for erlaubt in ("README.md", "AGENTS.md", "CLAUDE.md", ".gitattributes", ".gitignore"):
|
||||
(tmp_path / erlaubt).write_text("", encoding="utf-8")
|
||||
(tmp_path / "antrag.bpmn").write_text("", encoding="utf-8")
|
||||
befunde = pp.pruefe_bibliothek(tmp_path)
|
||||
assert len(befunde) == 1 and "antrag.bpmn" in befunde[0]
|
||||
|
||||
|
||||
def test_fehlende_bibliothek_ist_kein_befund_aber_ein_hinweis(tmp_path):
|
||||
"""Prüft, dass eine nicht geklonte Bibliothek keinen Befund, aber einen Hinweis auf setup_workspace.py ergibt."""
|
||||
fehlt = tmp_path / "Prozessbibliothek"
|
||||
assert pp.pruefe_bibliothek(fehlt) == []
|
||||
assert "setup_workspace.py" in pp.hinweis_bibliothek(fehlt)
|
||||
fehlt.mkdir()
|
||||
assert pp.hinweis_bibliothek(fehlt) == ""
|
||||
|
||||
|
||||
def test_es_gibt_mindestens_ein_beispiel():
|
||||
"""Prüft, dass der Abgleich .md/.bpmn wenigstens an den Skill-Beispielen tatsächlich greift."""
|
||||
assert pp.beispiele(), "keine Beispiele in .agents/skills/sn-bpmn/beispiele/"
|
||||
|
||||
Reference in New Issue
Block a user