CI demo: metrics + Gitea Actions

This commit is contained in:
2026-11-12 13:55:02 +08:00
commit 6637fb8ff4
17 changed files with 564 additions and 0 deletions

1
app/__init__.py Normal file
View File

@@ -0,0 +1 @@
"""Пакет приложения ci-demo (Gitea edition)."""

35
app/discounts.py Normal file
View File

@@ -0,0 +1,35 @@
"""Скидки демо-проекта ci-demo (СТРПО, неделя 9, Gitea edition)."""
from abc import ABC, abstractmethod
class Discount(ABC):
@abstractmethod
def apply(self, total: float) -> float:
"""Вернуть сумму с учётом скидки."""
class NoDiscount(Discount):
def apply(self, total: float) -> float:
return total
class VIPDiscount(Discount):
def apply(self, total: float) -> float:
return total * 0.9
class EmployeeDiscount(Discount):
def apply(self, total: float) -> float:
return total * 0.7
DISCOUNTS: dict[str, type[Discount]] = {
"regular": NoDiscount,
"vip": VIPDiscount,
"employee": EmployeeDiscount,
}
def discount_for(customer_type: str) -> Discount:
"""Выбрать стратегию скидки по типу клиента."""
return DISCOUNTS.get(customer_type, NoDiscount)()

41
app/legacy_report.py Normal file
View File

@@ -0,0 +1,41 @@
"""Учебный модуль с высокой сложностью для метрического гейта CI.
V(G) функции classify_order — ранг C (11–20). Поэтому:
xenon --max-absolute C app/ # зелёный
xenon --max-absolute B app/ # красный — гейт не пропускает
Мораль: порог в CI делает рост сложности видимым и блокирующим.
"""
def classify_order(order, cfg):
"""Классифицировать заказ по десятку правил — намеренно сложно."""
if order is None:
return "missing"
if "total" not in order:
return "no_total"
total = order["total"]
if total < 0:
return "negative"
if total == 0:
return "empty"
if total > 100000:
return "huge"
if cfg.get("maintenance"):
return "maintenance"
if cfg.get("blocked"):
return "blocked"
if cfg.get("regions") and order.get("region") not in cfg["regions"]:
return "region"
if order.get("coupon") and not cfg.get("coupons", False):
return "coupon"
if total > cfg.get("limit", 10000):
return "limit"
if order.get("fraud") and order.get("manual_review"):
return "fraud_review"
elif order.get("fraud"):
return "fraud"
if order.get("vip") and total > 5000:
return "vip_review"
return "ok"

21
app/service.py Normal file
View File

@@ -0,0 +1,21 @@
"""Сервис заказов демо-проекта ci-demo (СТРПО, неделя 9, Gitea edition)."""
from dataclasses import dataclass
from .discounts import Discount
@dataclass
class Order:
items: dict[str, float]
@property
def total(self) -> float:
return sum(self.items.values())
class OrderService:
def __init__(self, discount: Discount) -> None:
self.discount = discount
def total(self, order: Order) -> float:
return round(self.discount.apply(order.total), 2)