Tooling (Welle B): ruff-Linting einführen, Pre-commit-Hook härten
- ruff.toml: Config (E/F/W, E501 bewusst ignoriert wegen langer deutscher Daten-/Log-Strings; alembic/versions ausgeschlossen) - requirements-dev.txt mit ruff==0.15.18 - .githooks/pre-commit: ruff-Linting vor den Tests; fragiles 'grep -q OK' durch echte Exit-Code-Prüfung ersetzt; Testaufruf auf 'unittest discover' vereinheitlicht - Lints behoben: ungenutzte Imports (datetime, Optional, request u.a.), f-strings ohne Platzhalter, ungenutzte Test-Variable; bewusster alembic-Verfügbarkeits-Check mit noqa markiert Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9c3d58b04f
commit
814b3f45cb
10 changed files with 55 additions and 32 deletions
|
|
@ -1,46 +1,47 @@
|
|||
#!/bin/bash
|
||||
# Pre-commit hook für Typewriter Trainer
|
||||
# Führt automatisch Tests aus vor jedem Commit
|
||||
# Führt Linting (ruff) und Tests vor jedem Commit aus.
|
||||
#
|
||||
# Installation:
|
||||
# cp .githooks/pre-commit .git/hooks/pre-commit
|
||||
# chmod +x .git/hooks/pre-commit
|
||||
|
||||
echo "🧪 Running tests before commit..."
|
||||
set -u
|
||||
|
||||
echo "🔎 Running pre-commit checks..."
|
||||
echo ""
|
||||
|
||||
# Farben für Output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
NC='\033[0m'
|
||||
|
||||
# Unit Tests ausführen (schnell)
|
||||
echo "📋 Running Unit Tests..."
|
||||
if python -m unittest tests.test_lesson_service tests.test_statistics_service tests.test_settings_service -v 2>&1 | grep -q "OK"; then
|
||||
echo -e "${GREEN}✅ Unit Tests passed${NC}"
|
||||
# 1. Linting mit ruff (falls installiert)
|
||||
if python -m ruff --version >/dev/null 2>&1; then
|
||||
echo "🧹 Running ruff..."
|
||||
if ! python -m ruff check .; then
|
||||
echo -e "${RED}❌ Linting failed${NC}"
|
||||
echo "Bitte 'python -m ruff check .' beheben (ggf. '--fix')."
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ Linting passed${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Unit Tests failed${NC}"
|
||||
echo ""
|
||||
echo "Please fix the tests before committing."
|
||||
exit 1
|
||||
echo -e "${YELLOW}⚠️ ruff nicht installiert – Linting übersprungen${NC}"
|
||||
echo " Installation: pip install -r requirements-dev.txt"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# Integration Tests ausführen
|
||||
echo "🔗 Running Integration Tests..."
|
||||
if python -m unittest tests.test_integration_progress tests.test_integration_statistics -v 2>&1 | grep -q "OK"; then
|
||||
echo -e "${GREEN}✅ Integration Tests passed${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ Integration Tests failed${NC}"
|
||||
echo ""
|
||||
echo "Please fix the tests before committing."
|
||||
# 2. Tests (Exit-Code-basiert, kein grep)
|
||||
echo "🧪 Running tests..."
|
||||
if ! python -m unittest discover -s tests -p "test_*.py"; then
|
||||
echo -e "${RED}❌ Tests failed${NC}"
|
||||
echo "Bitte die Tests vor dem Commit beheben."
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✅ Tests passed${NC}"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}✅ All tests passed! Proceeding with commit...${NC}"
|
||||
echo -e "${GREEN}✅ All checks passed! Proceeding with commit...${NC}"
|
||||
echo ""
|
||||
|
||||
exit 0
|
||||
|
|
|
|||
2
app.py
2
app.py
|
|
@ -90,7 +90,7 @@ if __name__ == '__main__':
|
|||
logger.info("Tipptrainer gestartet")
|
||||
logger.info(f"Version: {VERSION}")
|
||||
logger.info(f"Lektionen geladen: {len(helpers.lessons)}")
|
||||
logger.info(f"Debug-Info verfügbar unter: http://127.0.0.1:5000/debug")
|
||||
logger.info("Debug-Info verfügbar unter: http://127.0.0.1:5000/debug")
|
||||
logger.info("=" * 50)
|
||||
|
||||
app.run(debug=True, host='0.0.0.0', port=5000)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from flask_sqlalchemy import SQLAlchemy
|
||||
from datetime import datetime
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
||||
|
|
|
|||
4
requirements-dev.txt
Normal file
4
requirements-dev.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Entwicklungs-Abhängigkeiten (nicht für den Produktivbetrieb nötig)
|
||||
-r requirements.txt
|
||||
|
||||
ruff==0.15.18
|
||||
|
|
@ -8,7 +8,7 @@ import json
|
|||
import logging
|
||||
import threading
|
||||
import time
|
||||
from flask import Blueprint, request, jsonify, current_app
|
||||
from flask import Blueprint, jsonify, current_app
|
||||
from services import helpers
|
||||
from services.helpers import (
|
||||
repair_json,
|
||||
|
|
|
|||
19
ruff.toml
Normal file
19
ruff.toml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Ruff-Konfiguration – https://docs.astral.sh/ruff/
|
||||
target-version = "py311"
|
||||
line-length = 120
|
||||
|
||||
# Generierte / externe Verzeichnisse nicht prüfen
|
||||
extend-exclude = ["venv", "alembic/versions"]
|
||||
|
||||
[lint]
|
||||
select = ["E", "F", "W"]
|
||||
# Zeilenlänge nicht erzwingen: das Projekt enthält lange deutsche
|
||||
# Daten-Strings (Lektionstexte) und Log-Meldungen, bei denen E501 nur
|
||||
# Rauschen erzeugt. Logikfehler (E/F/W) bleiben aktiv.
|
||||
ignore = ["E501"]
|
||||
|
||||
[lint.per-file-ignores]
|
||||
# Tests setzen FLASK_TESTING bewusst VOR dem App-Import (E402)
|
||||
"tests/*" = ["E402"]
|
||||
# app.py registriert Blueprints bewusst nach App-/CSRF-Setup (E402)
|
||||
"app.py" = ["E402"]
|
||||
|
|
@ -74,7 +74,7 @@ def get_or_create_secret_key() -> str:
|
|||
|
||||
# Setze Dateiberechtigungen auf 0o600 (nur User kann lesen/schreiben)
|
||||
os.chmod(env_path, 0o600)
|
||||
logger.info(f"Neuer Secret Key generiert und in .env gespeichert (Berechtigungen: 0o600)")
|
||||
logger.info("Neuer Secret Key generiert und in .env gespeichert (Berechtigungen: 0o600)")
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Speichern der .env Datei: {e}")
|
||||
logger.warning("Verwende temporären Secret Key für diese Session")
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Handles all progress and lesson progress related business logic
|
|||
"""
|
||||
|
||||
import logging
|
||||
from typing import Dict, Any, Optional
|
||||
from typing import Dict, Any
|
||||
from models import db, Progress, LessonProgress
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ def main():
|
|||
|
||||
# Prüfe ob Alembic installiert ist
|
||||
try:
|
||||
import alembic
|
||||
import alembic # noqa: F401 # nur Verfügbarkeits-Check
|
||||
logger.info("✓ Alembic ist installiert")
|
||||
except ImportError:
|
||||
logger.error("✗ Alembic nicht gefunden!")
|
||||
|
|
@ -36,7 +36,7 @@ def main():
|
|||
# Prüfe ob instance/ Verzeichnis existiert
|
||||
instance_dir = os.path.join(os.path.dirname(__file__), 'instance')
|
||||
if not os.path.exists(instance_dir):
|
||||
logger.info(f"Erstelle instance/ Verzeichnis...")
|
||||
logger.info("Erstelle instance/ Verzeichnis...")
|
||||
os.makedirs(instance_dir)
|
||||
logger.info("✓ Verzeichnis erstellt")
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import unittest
|
|||
import os
|
||||
os.environ['FLASK_TESTING'] = 'true' # Set before importing app
|
||||
|
||||
from datetime import datetime, timedelta, date
|
||||
from datetime import timedelta, date
|
||||
from app import app, db
|
||||
from models import LessonStatistic, DailyPractice
|
||||
from services.statistics_service import StatisticsService
|
||||
|
|
@ -281,7 +281,7 @@ class TestStatisticsServiceIntegration(unittest.TestCase):
|
|||
)
|
||||
|
||||
# Speichere in DB
|
||||
saved_stat = StatisticsService.save_lesson_statistics(
|
||||
StatisticsService.save_lesson_statistics(
|
||||
lesson_index=5,
|
||||
chars_per_minute=stats['typing_speed'],
|
||||
error_rate=stats['error_rate'],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue