Skip to content

Commit d800f4a

Browse files
authored
Move glitchtip qontract api folder (#5437)
* Move glitchtip qontract api folder * Add return type self
1 parent c47a1a1 commit d800f4a

File tree

11 files changed

+166
-136
lines changed

11 files changed

+166
-136
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from qontract_api.glitchtip.glitchtip_client_factory import GlitchtipClientFactory
2+
from qontract_api.glitchtip.glitchtip_workspace_client import GlitchtipWorkspaceClient
3+
from qontract_api.glitchtip.models import (
4+
GlitchtipInstance,
5+
GlitchtipOrganization,
6+
GlitchtipProject,
7+
GlitchtipProjectAlert,
8+
GlitchtipProjectAlertRecipient,
9+
RecipientType,
10+
)
11+
12+
__all__ = [
13+
"GlitchtipClientFactory",
14+
"GlitchtipInstance",
15+
"GlitchtipOrganization",
16+
"GlitchtipProject",
17+
"GlitchtipProjectAlert",
18+
"GlitchtipProjectAlertRecipient",
19+
"GlitchtipWorkspaceClient",
20+
"RecipientType",
21+
]

qontract_api/qontract_api/integrations/glitchtip_project_alerts/glitchtip_client_factory.py renamed to qontract_api/qontract_api/glitchtip/glitchtip_client_factory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from qontract_api.cache import CacheBackend
66
from qontract_api.config import Settings
7-
from qontract_api.integrations.glitchtip_project_alerts.glitchtip_workspace_client import (
7+
from qontract_api.glitchtip.glitchtip_workspace_client import (
88
GlitchtipWorkspaceClient,
99
)
1010

qontract_api/qontract_api/integrations/glitchtip_project_alerts/glitchtip_workspace_client.py renamed to qontract_api/qontract_api/glitchtip/glitchtip_workspace_client.py

File renamed without changes.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
"""Pydantic domain models for Glitchtip."""
2+
3+
import re
4+
from enum import StrEnum
5+
from typing import Any, Self
6+
7+
from pydantic import BaseModel, Field, model_validator
8+
9+
from qontract_api.models import Secret
10+
11+
12+
def _slugify(value: str) -> str:
13+
"""Convert value into a slug.
14+
15+
Adapted from https://docs.djangoproject.com/en/4.1/_modules/django/utils/text/#slugify
16+
"""
17+
value = re.sub(r"[^\w\s-]", "", value.lower())
18+
return re.sub(r"[-\s]+", "-", value).strip("-_")
19+
20+
21+
class RecipientType(StrEnum):
22+
"""Type of alert recipient."""
23+
24+
EMAIL = "email"
25+
WEBHOOK = "webhook"
26+
27+
28+
class GlitchtipProjectAlertRecipient(BaseModel, frozen=True):
29+
"""Desired state for a single project alert recipient."""
30+
31+
recipient_type: RecipientType = Field(
32+
..., description="Recipient type: 'email' or 'webhook'"
33+
)
34+
url: str = Field(default="", description="Webhook URL (empty for email recipients)")
35+
36+
@model_validator(mode="after")
37+
def validate_url(self) -> Self:
38+
if self.recipient_type == RecipientType.WEBHOOK and not self.url:
39+
raise ValueError("url must be set for webhook recipients")
40+
if self.recipient_type == RecipientType.EMAIL and self.url:
41+
raise ValueError("url must be empty for email recipients")
42+
return self
43+
44+
45+
class GlitchtipProjectAlert(BaseModel, frozen=True):
46+
"""Desired state for a single project alert."""
47+
48+
name: str = Field(
49+
..., description="Alert name (unique identifier within a project)"
50+
)
51+
timespan_minutes: int = Field(
52+
..., description="Time window in minutes for alert evaluation"
53+
)
54+
quantity: int = Field(..., description="Number of events to trigger the alert")
55+
recipients: list[GlitchtipProjectAlertRecipient] = Field(
56+
default=[], description="List of alert recipients"
57+
)
58+
59+
60+
class GlitchtipProject(BaseModel, frozen=True):
61+
"""Desired state for a single Glitchtip project's alerts."""
62+
63+
name: str = Field(..., description="Project name")
64+
slug: str = Field(
65+
default="",
66+
description="Project slug (URL-friendly identifier). Defaults to slugified name if not provided.",
67+
)
68+
alerts: list[GlitchtipProjectAlert] = Field(
69+
default=[], description="Desired alerts for this project"
70+
)
71+
72+
@model_validator(mode="before")
73+
@classmethod
74+
def set_slug_from_name(cls, values: Any) -> Any:
75+
if isinstance(values, dict) and not values.get("slug"):
76+
values["slug"] = _slugify(values["name"])
77+
return values
78+
79+
80+
class GlitchtipOrganization(BaseModel, frozen=True):
81+
"""Desired state for a single Glitchtip organization's projects."""
82+
83+
name: str = Field(..., description="Organization name")
84+
projects: list[GlitchtipProject] = Field(
85+
default=[], description="Projects within this organization"
86+
)
87+
88+
89+
class GlitchtipInstance(BaseModel, frozen=True):
90+
"""Glitchtip instance configuration."""
91+
92+
name: str = Field(..., description="Instance name (unique identifier)")
93+
console_url: str = Field(..., description="Glitchtip instance base URL")
94+
token: Secret = Field(..., description="Secret reference for the API token")
95+
read_timeout: int = Field(default=30, description="HTTP read timeout in seconds")
96+
max_retries: int = Field(default=3, description="Max HTTP retries")
97+
organizations: list[GlitchtipOrganization] = Field(
98+
default=[], description="Desired organizations with project alerts"
99+
)

qontract_api/qontract_api/integrations/glitchtip_project_alerts/models.py

Lines changed: 19 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,11 @@
11
"""Pydantic models for Glitchtip project alerts reconciliation API."""
22

3-
import re
4-
from enum import StrEnum
5-
from typing import Annotated, Any, Literal
3+
from typing import Annotated, Literal
64

7-
from pydantic import BaseModel, Field, model_validator
5+
from pydantic import BaseModel, Field
86

9-
from qontract_api.models import Secret, TaskResult, TaskStatus
10-
11-
12-
def _slugify(value: str) -> str:
13-
"""Convert value into a slug.
14-
15-
Adapted from https://docs.djangoproject.com/en/4.1/_modules/django/utils/text/#slugify
16-
"""
17-
value = re.sub(r"[^\w\s-]", "", value.lower())
18-
return re.sub(r"[-\s]+", "-", value).strip("-_")
19-
20-
21-
class RecipientType(StrEnum):
22-
"""Type of alert recipient."""
23-
24-
EMAIL = "email"
25-
WEBHOOK = "webhook"
26-
27-
28-
class GlitchtipProjectAlertRecipient(BaseModel, frozen=True):
29-
"""Desired state for a single project alert recipient."""
30-
31-
recipient_type: RecipientType = Field(
32-
..., description="Recipient type: 'email' or 'webhook'"
33-
)
34-
url: str = Field(default="", description="Webhook URL (empty for email recipients)")
35-
36-
@model_validator(mode="after")
37-
def validate_url(self) -> "GlitchtipProjectAlertRecipient":
38-
if self.recipient_type == RecipientType.WEBHOOK and not self.url:
39-
raise ValueError("url must be set for webhook recipients")
40-
if self.recipient_type == RecipientType.EMAIL and self.url:
41-
raise ValueError("url must be empty for email recipients")
42-
return self
43-
44-
45-
class GlitchtipProjectAlert(BaseModel, frozen=True):
46-
"""Desired state for a single project alert."""
47-
48-
name: str = Field(
49-
..., description="Alert name (unique identifier within a project)"
50-
)
51-
timespan_minutes: int = Field(
52-
..., description="Time window in minutes for alert evaluation"
53-
)
54-
quantity: int = Field(..., description="Number of events to trigger the alert")
55-
recipients: list[GlitchtipProjectAlertRecipient] = Field(
56-
default=[], description="List of alert recipients"
57-
)
58-
59-
60-
class GlitchtipProject(BaseModel, frozen=True):
61-
"""Desired state for a single Glitchtip project's alerts."""
62-
63-
name: str = Field(..., description="Project name")
64-
slug: str = Field(
65-
default="",
66-
description="Project slug (URL-friendly identifier). Defaults to slugified name if not provided.",
67-
)
68-
alerts: list[GlitchtipProjectAlert] = Field(
69-
default=[], description="Desired alerts for this project"
70-
)
71-
72-
@model_validator(mode="before")
73-
@classmethod
74-
def set_slug_from_name(cls, values: Any) -> Any:
75-
if isinstance(values, dict) and not values.get("slug"):
76-
values["slug"] = _slugify(values["name"])
77-
return values
78-
79-
80-
class GlitchtipOrganization(BaseModel, frozen=True):
81-
"""Desired state for a single Glitchtip organization's projects."""
82-
83-
name: str = Field(..., description="Organization name")
84-
projects: list[GlitchtipProject] = Field(
85-
default=[], description="Projects within this organization"
86-
)
87-
88-
89-
class GlitchtipInstance(BaseModel, frozen=True):
90-
"""Glitchtip instance configuration."""
91-
92-
name: str = Field(..., description="Instance name (unique identifier)")
93-
console_url: str = Field(..., description="Glitchtip instance base URL")
94-
token: Secret = Field(..., description="Secret reference for the API token")
95-
read_timeout: int = Field(default=30, description="HTTP read timeout in seconds")
96-
max_retries: int = Field(default=3, description="Max HTTP retries")
97-
organizations: list[GlitchtipOrganization] = Field(
98-
default=[], description="Desired organizations with project alerts"
99-
)
100-
101-
102-
class GlitchtipProjectAlertsReconcileRequest(BaseModel, frozen=True):
103-
"""Request model for Glitchtip project alerts reconciliation.
104-
105-
POST requests always queue a background task (async execution).
106-
"""
107-
108-
instances: list[GlitchtipInstance] = Field(
109-
..., description="List of Glitchtip instances to reconcile"
110-
)
111-
dry_run: bool = Field(
112-
default=True,
113-
description="If True, only calculate actions without executing. Default: True (safety first!)",
114-
)
7+
from qontract_api.glitchtip.models import GlitchtipInstance
8+
from qontract_api.models import TaskResult, TaskStatus
1159

11610

11711
# Type-safe action models
@@ -170,6 +64,21 @@ class GlitchtipProjectAlertsTaskResult(TaskResult, frozen=True):
17064
)
17165

17266

67+
class GlitchtipProjectAlertsReconcileRequest(BaseModel, frozen=True):
68+
"""Request model for Glitchtip project alerts reconciliation.
69+
70+
POST requests always queue a background task (async execution).
71+
"""
72+
73+
instances: list[GlitchtipInstance] = Field(
74+
..., description="List of Glitchtip instances to reconcile"
75+
)
76+
dry_run: bool = Field(
77+
default=True,
78+
description="If True, only calculate actions without executing. Default: True (safety first!)",
79+
)
80+
81+
17382
class GlitchtipProjectAlertsTaskResponse(BaseModel, frozen=True):
17483
"""Response model for POST /reconcile endpoint.
17584

qontract_api/qontract_api/integrations/glitchtip_project_alerts/service.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,16 @@
1010
)
1111

1212
from qontract_api.config import Settings
13-
from qontract_api.integrations.glitchtip_project_alerts.glitchtip_client_factory import (
14-
GlitchtipClientFactory,
15-
)
16-
from qontract_api.integrations.glitchtip_project_alerts.glitchtip_workspace_client import (
17-
GlitchtipWorkspaceClient,
13+
from qontract_api.glitchtip import GlitchtipClientFactory, GlitchtipWorkspaceClient
14+
from qontract_api.glitchtip.models import (
15+
GlitchtipInstance,
16+
GlitchtipOrganization,
17+
GlitchtipProjectAlert,
1818
)
1919
from qontract_api.integrations.glitchtip_project_alerts.models import (
2020
GlitchtipAlertActionCreate,
2121
GlitchtipAlertActionDelete,
2222
GlitchtipAlertActionUpdate,
23-
GlitchtipInstance,
24-
GlitchtipOrganization,
25-
GlitchtipProjectAlert,
2623
GlitchtipProjectAlertsTaskResult,
2724
)
2825
from qontract_api.logger import get_logger

qontract_api/qontract_api/integrations/glitchtip_project_alerts/tasks.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@
1212
from qontract_api.cache.factory import get_cache
1313
from qontract_api.config import settings
1414
from qontract_api.event_manager import get_event_manager
15-
from qontract_api.integrations.glitchtip_project_alerts.glitchtip_client_factory import (
16-
GlitchtipClientFactory,
17-
)
15+
from qontract_api.glitchtip import GlitchtipClientFactory
16+
from qontract_api.glitchtip.models import GlitchtipInstance
1817
from qontract_api.integrations.glitchtip_project_alerts.models import (
19-
GlitchtipInstance,
2018
GlitchtipProjectAlertsTaskResult,
2119
)
2220
from qontract_api.integrations.glitchtip_project_alerts.service import (

qontract_api/tests/integrations/test_glitchtip_project_alerts_models.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@
33
import pytest
44
from pydantic import ValidationError
55

6-
from qontract_api.integrations.glitchtip_project_alerts.models import (
7-
GlitchtipAlertActionCreate,
8-
GlitchtipAlertActionDelete,
9-
GlitchtipAlertActionUpdate,
6+
from qontract_api.glitchtip.models import (
107
GlitchtipInstance,
118
GlitchtipOrganization,
129
GlitchtipProject,
1310
GlitchtipProjectAlert,
1411
GlitchtipProjectAlertRecipient,
12+
)
13+
from qontract_api.integrations.glitchtip_project_alerts.models import (
14+
GlitchtipAlertActionCreate,
15+
GlitchtipAlertActionDelete,
16+
GlitchtipAlertActionUpdate,
1517
GlitchtipProjectAlertsReconcileRequest,
1618
GlitchtipProjectAlertsTaskResponse,
1719
GlitchtipProjectAlertsTaskResult,

qontract_api/tests/integrations/test_glitchtip_project_alerts_router.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88

99
from qontract_api.auth import create_access_token
1010
from qontract_api.constants import REQUEST_ID_HEADER
11-
from qontract_api.integrations.glitchtip_project_alerts.models import (
11+
from qontract_api.glitchtip.models import (
1212
GlitchtipInstance,
1313
GlitchtipOrganization,
14+
)
15+
from qontract_api.integrations.glitchtip_project_alerts.models import (
1416
GlitchtipProjectAlertsReconcileRequest,
1517
GlitchtipProjectAlertsTaskResult,
1618
)

qontract_api/tests/integrations/test_glitchtip_project_alerts_service.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
from qontract_utils.glitchtip_api.models import Organization, Project, ProjectAlert
77

88
from qontract_api.config import Settings
9-
from qontract_api.integrations.glitchtip_project_alerts.glitchtip_workspace_client import (
10-
GlitchtipWorkspaceClient,
9+
from qontract_api.glitchtip import GlitchtipWorkspaceClient
10+
from qontract_api.glitchtip.models import (
11+
GlitchtipInstance,
12+
GlitchtipOrganization,
13+
GlitchtipProject,
14+
GlitchtipProjectAlert,
1115
)
1216
from qontract_api.integrations.glitchtip_project_alerts.models import (
1317
GlitchtipAlertActionCreate,
1418
GlitchtipAlertActionDelete,
1519
GlitchtipAlertActionUpdate,
16-
GlitchtipInstance,
17-
GlitchtipOrganization,
18-
GlitchtipProject,
19-
GlitchtipProjectAlert,
2020
)
2121
from qontract_api.integrations.glitchtip_project_alerts.service import (
2222
GlitchtipProjectAlertsService,

0 commit comments

Comments
 (0)