CI demo: metrics + Gitea Actions
This commit is contained in:
1
app/__init__.py
Normal file
1
app/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Пакет приложения ci-demo (Gitea edition)."""
|
||||
35
app/discounts.py
Normal file
35
app/discounts.py
Normal 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
41
app/legacy_report.py
Normal 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
21
app/service.py
Normal 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)
|
||||
Reference in New Issue
Block a user