Pipeline-Stufe 1 automatisiert: requirements, pre-commit-Hook, ruff
Nach Web-Recherche zum 2026er-Python-Standard umgesetzt, aber gefiltert: von
uv/Ruff/pyproject/CI passt hier nur, was zu einer Einzelmaschine mit
GUI-gebundenem MT5 und Live-Geld passt.
(1) requirements.txt (Laufzeit) + requirements-dev.txt (Werkzeuge/Messung),
Versionen gepinnt. Bis dahin gab es GAR KEINE Liste — nach einem
Maschinenausfall waere die Rekonstruktion Raten gewesen. Per AST ueber
core/, server.py, tools/ ermittelt statt geraten.
(2) tools/pre_commit.py faehrt vor jedem Commit check_nfalle + pytest (~5 s).
Einrichten: python tools/pre_commit.py --install. Notausgang
'git commit --no-verify' ist Absicht.
Bewusst OHNE das pre-commit-Framework: dessen Nutzen ist
Werkzeug-Versionierung ueber mehrere Maschinen. Hier gibt es eine, und es
wuerde eine ZWEITE ruff-Version in einer isolierten Umgebung installieren —
genau die Divergenz 'Pruefumgebung != Laufumgebung', die heute schon einmal
zugeschlagen hat.
(3) Ruff statt pyflakes (--select F821), ganzer Scan in 2,1 s. KEIN
ruff format — das wuerde 161 Dateien umformatieren, darunter alle
Backtests, und die Migrations-Regel verletzen.
⚠ VIERTER Fall der Klasse 'Erfolg melden, wo nichts geprueft wurde', und nur
durch den Test aufgefallen: --select F821,E999 laesst ruff 0.16 komplett
abbrechen (E999 wurde entfernt, Exit 2); die Meldung geht nach stderr, und weil
ich den Rueckgabecode nicht pruefte, meldete die Stufe 'keine undefinierten
Namen' — ohne irgendetwas geprueft zu haben. Ein absichtlich eingebauter
F821-Fehler kam glatt durch den Hook. Behoben: nur F821, und Exit 2 loest jetzt
den pyflakes-Rueckfall aus.
Beide Richtungen verifiziert: mit Fehler stoppt der Hook den Commit, ohne ist
er gruen. Der Test-Commit wurde zurueckgenommen (war nur lokal, ahead 1).
Nicht umgesetzt: Gitea Actions (Runner auf derselben Maschine wie der Live-Bot,
kein Mehrwert bei 5 s Pruefzeit), Container/Blue-Green (MT5 braucht eine
Desktop-Sitzung, EINE Broker-Verbindung), mypy/ty (kaum Annotationen).
Struktureller Fund: core/engine.py importiert backtest_breakout_squeeze — ein
Backtest ist Teil des LIVE-Abhaengigkeitsgraphen.
This commit is contained in:
@@ -402,6 +402,46 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche:
|
|||||||
⚠ **Lehre:** die naheliegende Antwort („numpy") war die falsche. Ein Profil
|
⚠ **Lehre:** die naheliegende Antwort („numpy") war die falsche. Ein Profil
|
||||||
kostet zwei Minuten und hätte diese Bremse jederzeit gezeigt — sie lag seit
|
kostet zwei Minuten und hätte diese Bremse jederzeit gezeigt — sie lag seit
|
||||||
Monaten in jedem gegateten Backtest.
|
Monaten in jedem gegateten Backtest.
|
||||||
|
- **⚠⚠ PIPELINE-STUFE 1 IST JETZT AUTOMATISCH — `pre-commit`-Hook (2026-08-07).**
|
||||||
|
Nach einer Web-Recherche zum 2026er-Python-Standard umgesetzt, aber **gefiltert**:
|
||||||
|
von uv/Ruff/pyproject/CI ist hier nur das sinnvoll, was zu einer Einzelmaschine
|
||||||
|
mit GUI-gebundenem MT5 und Live-Geld passt.
|
||||||
|
**(1) Abhängigkeiten festgehalten** — `requirements.txt` (Laufzeit) und
|
||||||
|
`requirements-dev.txt` (Werkzeuge/Messung), **Versionen gepinnt**. ⚠ Bis dahin
|
||||||
|
gab es **gar keine** Liste; nach einem Maschinenausfall wäre die Rekonstruktion
|
||||||
|
Raten gewesen. Ermittelt per AST über `core/`, `server.py`, `tools/` — nicht
|
||||||
|
geraten.
|
||||||
|
**(2) `tools/pre_commit.py`** fährt vor jedem Commit `check_nfalle` + `pytest`
|
||||||
|
(~5 s). Einrichten: `python tools/pre_commit.py --install`. Notausgang
|
||||||
|
`git commit --no-verify` ist Absicht — eine Prüfung, die einen dringenden Fix
|
||||||
|
blockiert, wird sonst deinstalliert.
|
||||||
|
⚠ **Bewusst OHNE das `pre-commit`-Framework**: dessen Nutzen ist Werkzeug-
|
||||||
|
Versionierung über mehrere Maschinen. Hier gibt es eine. Es würde stattdessen
|
||||||
|
eine ZWEITE ruff-Version in einer isolierten Umgebung installieren — genau die
|
||||||
|
Divergenz „Prüfumgebung ≠ Laufumgebung", die heute schon einmal zugeschlagen hat.
|
||||||
|
**(3) Ruff statt pyflakes** (`ruff check --select F821`) — gleiche Befunde,
|
||||||
|
ganzer Scan in 2,1 s. ⚠ **Kein `ruff format`**: das würde 161 Dateien
|
||||||
|
umformatieren, darunter alle Backtests → Migrations-Regel verletzt.
|
||||||
|
⚠⚠ **VIERTER Fall der Fehlerklasse „Erfolg melden, wo nichts geprüft wurde" —
|
||||||
|
und diesmal fiel er nur durch einen Test auf.** `--select F821,E999` lässt ruff
|
||||||
|
0.16 **komplett abbrechen** („Rule E999 was removed", Exit 2); die Meldung geht
|
||||||
|
nach stderr, und weil ich den **Rückgabecode nicht prüfte**, meldete die Stufe
|
||||||
|
„keine undefinierten Namen" — obwohl sie **gar nichts** geprüft hatte. Ein
|
||||||
|
absichtlich eingebauter `F821`-Fehler kam **glatt durch den Hook**. Behoben:
|
||||||
|
nur `F821`, und **Exit 2 = Werkzeugfehler** löst jetzt den pyflakes-Rückfall aus
|
||||||
|
statt als „sauber" zu gelten.
|
||||||
|
✅ **Beide Richtungen verifiziert** (wie beim Deploy-Skript): mit eingebautem
|
||||||
|
Fehler → Hook **stoppt** den Commit; ohne → grün. Der Test-Commit wurde
|
||||||
|
zurückgenommen (war nur lokal).
|
||||||
|
⚠ **Nicht umgesetzt und warum:** *Gitea Actions* — der Runner liefe auf
|
||||||
|
derselben Maschine wie der Live-Bot und konkurrierte um CPU, bei 5 s Prüfzeit
|
||||||
|
ohne Mehrwert gegenüber dem Hook. *Container/Blue-Green* — unmöglich, MT5
|
||||||
|
braucht eine Desktop-Sitzung, und es gibt EINE Broker-Verbindung.
|
||||||
|
*mypy/ty* — kaum Annotationen vorhanden, grosser Aufwand für wenig Ertrag.
|
||||||
|
⚠ **Struktureller Fund dabei:** `core/engine.py:3527` importiert
|
||||||
|
**`backtest_breakout_squeeze`** (ebenso `weekly_review.py`). Ein Backtest ist
|
||||||
|
damit Teil des **Live**-Abhängigkeitsgraphen — „Backtests sind nur Doku" stimmt
|
||||||
|
nicht, ein Fehler dort kann den laufenden Bot treffen.
|
||||||
- **⚠⚠ TEST-SUITE (`pytest`, `tests/`, seit 2026-08-07) — 17 Tests, ~1 s.**
|
- **⚠⚠ TEST-SUITE (`pytest`, `tests/`, seit 2026-08-07) — 17 Tests, ~1 s.**
|
||||||
Im Projekt sind über Monate **dutzende Szenario-Tests** entstanden („mit 10
|
Im Projekt sind über Monate **dutzende Szenario-Tests** entstanden („mit 10
|
||||||
Szenarien getestet", „mit 18 synthetischen Szenarien"), alle als
|
Szenarien getestet", „mit 18 synthetischen Szenarien"), alle als
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# WERKZEUGE fuer Entwicklung, Messung und Pruefung — NICHT fuer den Live-Betrieb.
|
||||||
|
#
|
||||||
|
# ⚠ Bewusst getrennt von `requirements.txt`: der Bot soll sich auf einer frischen
|
||||||
|
# Maschine mit einer moeglichst kleinen Oberflaeche wiederherstellen lassen. scipy
|
||||||
|
# und scikit-learn haben nichts im Handelspfad zu suchen, auch wenn Backtests sie
|
||||||
|
# nutzen.
|
||||||
|
#
|
||||||
|
# Installation: python -m pip install -r requirements-dev.txt
|
||||||
|
|
||||||
|
-r requirements.txt
|
||||||
|
|
||||||
|
# ── Pruefung (laeuft im pre-commit-Hook) ─────────────────────────────────
|
||||||
|
pytest==9.1.1
|
||||||
|
ruff==0.16.1 # ersetzt pyflakes: gleiche Befunde, deutlich schneller
|
||||||
|
pyflakes==3.4.0 # Rueckfall in `tools/check_nfalle.py`, falls ruff fehlt
|
||||||
|
|
||||||
|
# ── Messung / Backtests ──────────────────────────────────────────────────
|
||||||
|
numpy==2.2.6
|
||||||
|
scipy==1.18.0 # `backtest_cost_gate.ci95` (Bootstrap-Konfidenzintervalle)
|
||||||
|
scikit-learn==1.9.0 # bislang ungenutzt; Kandidat fuer P(break)-Nachbau
|
||||||
|
pandas==3.0.2 # bislang ungenutzt
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# LAUFZEIT-Abhaengigkeiten des Bots (server.py + core/).
|
||||||
|
#
|
||||||
|
# ⚠ WOZU: bis 2026-08-07 gab es GAR KEINE Abhaengigkeitsliste. Stirbt die
|
||||||
|
# Maschine, waere die Rekonstruktion Raten gewesen — bei einem System, das
|
||||||
|
# echtes Geld bewegt, die groesste Luecke der Pipeline.
|
||||||
|
#
|
||||||
|
# ⚠ Versionen sind GEPINNT, nicht offen. Ein stiller Minor-Sprung (z. B. bei
|
||||||
|
# `MetaTrader5` oder `fastapi`) kann den laufenden Bot brechen; das faellt dann
|
||||||
|
# nachts auf, nicht beim Update. Bewusst aktualisieren statt zufaellig erben.
|
||||||
|
#
|
||||||
|
# Installation auf einer frischen Maschine:
|
||||||
|
# python -m pip install -r requirements.txt
|
||||||
|
#
|
||||||
|
# ⚠ Erzeugt aus dem LAUFENDEN Stand (pip freeze, gefiltert auf die real
|
||||||
|
# importierten Pakete — ermittelt per AST ueber core/, server.py, tools/).
|
||||||
|
# Nicht handgepflegt raten: bei neuen Importen hier nachtragen.
|
||||||
|
|
||||||
|
# ── Broker-Anbindung (Windows-only, kein Ersatz moeglich) ────────────────
|
||||||
|
MetaTrader5==5.0.5735
|
||||||
|
|
||||||
|
# ── Web-Backend fuer die Mobile-PWA (Port 8000) ──────────────────────────
|
||||||
|
fastapi==0.137.1
|
||||||
|
uvicorn==0.49.0
|
||||||
|
websockets==16.0 # WS-Push /ws
|
||||||
|
# starlette/pydantic kommen als fastapi-Abhaengigkeiten, hier zur Nachvollzieh-
|
||||||
|
# barkeit gepinnt (sonst waehlt pip beim Neuaufbau evtl. andere Versionen)
|
||||||
|
starlette==1.3.1
|
||||||
|
pydantic==2.13.3
|
||||||
|
|
||||||
|
# ── Nachrichten, Kalender, Uebersetzung ──────────────────────────────────
|
||||||
|
requests==2.33.1
|
||||||
|
beautifulsoup4==4.14.3 # importiert als `bs4`
|
||||||
|
feedparser==6.0.12
|
||||||
|
deep-translator==1.11.4
|
||||||
|
|
||||||
|
# ── KI-Copilot (LLM-Provider) ────────────────────────────────────────────
|
||||||
|
# ⚠ Beide Clients sind eingebunden; aktiv ist laut `[agent] provider` nur einer.
|
||||||
|
# Die z.ai-/DeepSeek-/Kimi-Endpunkte laufen ueber den openai-kompatiblen Client.
|
||||||
|
anthropic==0.99.0
|
||||||
|
openai==2.34.0
|
||||||
+64
-21
@@ -19,6 +19,7 @@ Geprueft wird:
|
|||||||
import pathlib
|
import pathlib
|
||||||
import py_compile
|
import py_compile
|
||||||
import re
|
import re
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
@@ -80,31 +81,73 @@ print(f" {npy} Dateien geprueft.")
|
|||||||
SCHWER = ("undefined name", "undefined local", "syntax error")
|
SCHWER = ("undefined name", "undefined local", "syntax error")
|
||||||
print()
|
print()
|
||||||
print("=" * 88)
|
print("=" * 88)
|
||||||
print(" A2) PYFLAKES — undefinierte Namen (was py_compile nicht sieht)")
|
print(" A2) LINTER — undefinierte Namen (was py_compile nicht sieht)")
|
||||||
print("=" * 88)
|
print("=" * 88)
|
||||||
|
# ⚠ RUFF statt pyflakes (2026-08-07, Web-Recherche zum 2026er-Standard): gleiche
|
||||||
|
# Befunde, deutlich schneller, ein Werkzeug statt vieler. Bewusst NUR
|
||||||
|
# `ruff check` mit ENGER Regelauswahl — **kein `ruff format`**: das wuerde 161
|
||||||
|
# Dateien umformatieren, darunter alle Backtests, und damit die Migrations-Regel
|
||||||
|
# verletzen (deren Zahlen sind dokumentiert).
|
||||||
|
# F821 = undefined name ← die Klasse, die hier real weh tut
|
||||||
|
# E999 = syntax error
|
||||||
|
# F811 (redefinition) bleibt DRAUSSEN, s. Begruendung bei SCHWER oben.
|
||||||
|
# pyflakes bleibt als Rueckfall, damit die Pruefung auch ohne ruff laeuft.
|
||||||
|
# ⚠⚠ NUR F821 — `E999` gibt es in ruff 0.16 NICHT MEHR. Wird es trotzdem
|
||||||
|
# selektiert, bricht ruff KOMPLETT ab („Rule E999 was removed") mit Exit 2.
|
||||||
|
# Genau das ist beim ersten Bau passiert, und schlimmer: der Rueckgabecode
|
||||||
|
# wurde nicht geprueft, die Fehlermeldung ging nach stderr — die Stufe meldete
|
||||||
|
# also „keine undefinierten Namen", waehrend sie GAR NICHTS geprueft hat. Ein
|
||||||
|
# absichtlich eingebauter `F821`-Fehler kam glatt durch den Hook.
|
||||||
|
# Syntaxfehler deckt ohnehin Stufe A (`py_compile`) ab.
|
||||||
|
# ⚠ RUFF-EXIT-CODES: 0 = sauber · 1 = Befunde · 2 = Werkzeugfehler.
|
||||||
|
# 2 darf NIEMALS als „sauber" durchgehen.
|
||||||
|
_lint_ok = False
|
||||||
try:
|
try:
|
||||||
import io
|
r = subprocess.run([sys.executable, "-m", "ruff", "check",
|
||||||
|
"--select", "F821", "--no-cache",
|
||||||
from pyflakes.api import checkPath
|
"--output-format", "concise", str(WURZEL)],
|
||||||
from pyflakes.reporter import Reporter
|
capture_output=True, text=True, timeout=180)
|
||||||
|
if r.returncode not in (0, 1):
|
||||||
aus, err = io.StringIO(), io.StringIO()
|
print(f" ⚠ ruff meldet einen WERKZEUGFEHLER (Exit {r.returncode}) — "
|
||||||
rep = Reporter(aus, err)
|
f"Rueckfall auf pyflakes:")
|
||||||
for p in dateien(".py"):
|
for z in (r.stderr or r.stdout).strip().splitlines()[:3]:
|
||||||
checkPath(str(p), rep)
|
print(f" {z}")
|
||||||
zeilen = [z for z in (aus.getvalue() + err.getvalue()).splitlines() if z.strip()]
|
raise RuntimeError("ruff nicht nutzbar")
|
||||||
schwer = [z for z in zeilen if any(s in z for s in SCHWER)]
|
_lint_ok = True
|
||||||
for z in schwer:
|
treffer = [z for z in r.stdout.splitlines()
|
||||||
|
if z.strip() and not z.startswith(("Found", "All checks", "warning:"))]
|
||||||
|
for z in treffer:
|
||||||
kurz = z.replace(str(WURZEL) + "\\", "").replace(str(WURZEL) + "/", "")
|
kurz = z.replace(str(WURZEL) + "\\", "").replace(str(WURZEL) + "/", "")
|
||||||
befunde.append(f"PF {kurz}")
|
befunde.append(f"RUFF {kurz}")
|
||||||
print(f" FEHLER {kurz}")
|
print(f" FEHLER {kurz}")
|
||||||
if not schwer:
|
if not treffer:
|
||||||
print(" keine undefinierten Namen.")
|
print(" keine undefinierten Namen (ruff, F821/E999).")
|
||||||
print(f" ({len(zeilen) - len(schwer)} kosmetische Hinweise unterdrueckt — "
|
except Exception:
|
||||||
f"ungenutzte Importe, f-Strings ohne Platzhalter)")
|
pass
|
||||||
except ImportError:
|
|
||||||
print(" ⚠ pyflakes nicht installiert — Stufe uebersprungen.")
|
if not _lint_ok:
|
||||||
print(" Installation: python -m pip install pyflakes")
|
try:
|
||||||
|
import io
|
||||||
|
|
||||||
|
from pyflakes.api import checkPath
|
||||||
|
from pyflakes.reporter import Reporter
|
||||||
|
|
||||||
|
aus, err = io.StringIO(), io.StringIO()
|
||||||
|
rep = Reporter(aus, err)
|
||||||
|
for p in dateien(".py"):
|
||||||
|
checkPath(str(p), rep)
|
||||||
|
zeilen = [z for z in (aus.getvalue() + err.getvalue()).splitlines()
|
||||||
|
if z.strip()]
|
||||||
|
schwer = [z for z in zeilen if any(s in z for s in SCHWER)]
|
||||||
|
for z in schwer:
|
||||||
|
kurz = z.replace(str(WURZEL) + "\\", "").replace(str(WURZEL) + "/", "")
|
||||||
|
befunde.append(f"PF {kurz}")
|
||||||
|
print(f" FEHLER {kurz}")
|
||||||
|
if not schwer:
|
||||||
|
print(" keine undefinierten Namen (pyflakes-Rueckfall).")
|
||||||
|
except ImportError:
|
||||||
|
print(" ⚠ weder ruff noch pyflakes installiert — Stufe uebersprungen.")
|
||||||
|
print(" Installation: python -m pip install -r requirements-dev.txt")
|
||||||
|
|
||||||
|
|
||||||
# ── B) JavaScript ────────────────────────────────────────────────────────
|
# ── B) JavaScript ────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Pre-Commit-Pruefung: faehrt die Stufe-1-Checks automatisch vor jedem Commit.
|
||||||
|
|
||||||
|
⚠ WOZU. Am 2026-08-07 habe ich `py_compile`, `pytest` und `check_nfalle` rund
|
||||||
|
fuenfzehnmal von Hand gestartet — und trotzdem gingen zwei Fehler durch, weil
|
||||||
|
ich sie im falschen Moment aufrief: die `\\n`-Falle fiel erst beim naechsten
|
||||||
|
Aufruf auf, die beiden `log.`-Fehler in `core/trader.py` lagen MONATE drin
|
||||||
|
(einer seit dem Initial-Commit). Ein Hook vergisst das nicht.
|
||||||
|
|
||||||
|
WAS GEPRUEFT WIRD (~3–4 s):
|
||||||
|
1. `tools/check_nfalle.py` — kompiliert alle .py, ruff (F821/E999),
|
||||||
|
JS-String-Literale, die \\n-Falle in beide Richtungen, .ps1-BOM
|
||||||
|
2. `pytest` — die Szenario-Suite
|
||||||
|
|
||||||
|
⚠ NOTAUSGANG: `git commit --no-verify` ueberspringt den Hook. Das ist Absicht —
|
||||||
|
eine Pruefung, die einen dringenden Fix blockiert, wird sonst dauerhaft
|
||||||
|
deinstalliert. Wer ihn nutzt, sollte die Pruefung danach nachholen.
|
||||||
|
|
||||||
|
⚠ BEWUSST OHNE das `pre-commit`-Framework: dessen Nutzen ist die Verwaltung von
|
||||||
|
Werkzeug-Versionen ueber mehrere Entwickler und Maschinen hinweg. Hier gibt es
|
||||||
|
eine Maschine und einen Entwickler; ein eigenes, versioniertes Skript ist
|
||||||
|
transparenter und braucht keine isolierten Zusatz-Umgebungen (die dann eine
|
||||||
|
ANDERE ruff-Version haetten als die Kommandozeile — genau die Art Divergenz,
|
||||||
|
die dieses Projekt schon oft genug hatte).
|
||||||
|
|
||||||
|
Aufruf:
|
||||||
|
python tools/pre_commit.py # Pruefung von Hand
|
||||||
|
python tools/pre_commit.py --install # als Git-Hook einrichten
|
||||||
|
"""
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
WURZEL = Path(__file__).resolve().parents[1]
|
||||||
|
PY = sys.executable
|
||||||
|
|
||||||
|
|
||||||
|
def lauf(titel: str, argv: list[str]) -> bool:
|
||||||
|
t0 = time.time()
|
||||||
|
r = subprocess.run(argv, cwd=WURZEL, capture_output=True, text=True)
|
||||||
|
dauer = time.time() - t0
|
||||||
|
if r.returncode == 0:
|
||||||
|
print(f" ✅ {titel:<28} {dauer:.1f}s")
|
||||||
|
return True
|
||||||
|
print(f" ❌ {titel:<28} {dauer:.1f}s")
|
||||||
|
# Nur die letzten Zeilen — der Hook soll die Ursache zeigen, nicht fluten.
|
||||||
|
for z in (r.stdout + r.stderr).strip().splitlines()[-25:]:
|
||||||
|
print(f" {z}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def installieren() -> int:
|
||||||
|
hooks = WURZEL / ".git" / "hooks"
|
||||||
|
if not hooks.is_dir():
|
||||||
|
print(" Kein .git/hooks-Verzeichnis gefunden."); return 1
|
||||||
|
ziel = hooks / "pre-commit"
|
||||||
|
# ⚠ Git fuer Windows fuehrt Hooks ueber `sh` aus, nicht ueber cmd — deshalb
|
||||||
|
# ein sh-Shim mit Vorwaertsschraegstrichen.
|
||||||
|
ziel.write_text(
|
||||||
|
"#!/bin/sh\n"
|
||||||
|
"# Erzeugt von tools/pre_commit.py --install\n"
|
||||||
|
f'exec "{Path(PY).as_posix()}" -X utf8 '
|
||||||
|
f'"{(WURZEL / "tools" / "pre_commit.py").as_posix()}"\n',
|
||||||
|
encoding="utf-8", newline="\n")
|
||||||
|
print(f" Hook installiert: {ziel}")
|
||||||
|
print(" Ueberspringen im Notfall: git commit --no-verify")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if "--install" in sys.argv:
|
||||||
|
return installieren()
|
||||||
|
|
||||||
|
print("── Pre-Commit ─────────────────────────────────────")
|
||||||
|
ok = True
|
||||||
|
ok &= lauf("Syntax · Linter · Scanner",
|
||||||
|
[PY, "-X", "utf8", str(WURZEL / "tools" / "check_nfalle.py")])
|
||||||
|
ok &= lauf("Szenario-Tests (pytest)", [PY, "-X", "utf8", "-m", "pytest", "-q"])
|
||||||
|
if ok:
|
||||||
|
print("── alles gruen ────────────────────────────────────")
|
||||||
|
return 0
|
||||||
|
print("── COMMIT GESTOPPT ────────────────────────────────")
|
||||||
|
print(" Beheben — oder bewusst uebergehen: git commit --no-verify")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
Reference in New Issue
Block a user