Coverage for src / qdrant_loader / webhooks / single_event_handler.py: 79%
29 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-06-11 09:38 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-06-11 09:38 +0000
1"""Single-event webhook handler for WS-5 (Jira)."""
3from __future__ import annotations
5from typing import Any
7from qdrant_loader.utils.logging import LoggingConfig
8from qdrant_loader.webhooks.queue_backend import (
9 SINGLE_DELETE,
10 SINGLE_UPSERT,
11 ChangeEvent,
12)
14logger = LoggingConfig.get_logger(__name__)
17async def parse_webhook_event(
18 source_type: str,
19 source: str,
20 payload: Any,
21) -> ChangeEvent | None:
22 """Parse webhook payload into a ChangeEvent for Jira single-event processing."""
23 if source_type != "jira":
24 return None
26 if not isinstance(payload, dict):
27 logger.warning("Jira payload is not a dict", payload_type=type(payload))
28 return None
30 try:
31 issue = payload.get("issue", {})
32 issue_key = issue.get("key")
33 webhook_event = payload.get("webhookEvent", "unknown")
35 if not issue_key:
36 logger.warning("No issue.key in Jira webhook payload")
37 return None
39 operation = _map_jira_event_to_operation(webhook_event)
40 if operation is None:
41 logger.debug(
42 "Unsupported Jira webhook event type",
43 event_type=webhook_event,
44 )
45 return None
47 return ChangeEvent(
48 source=source,
49 source_type=source_type,
50 project_id=None,
51 entity_id=issue_key,
52 payload=payload,
53 operation=operation,
54 )
55 except Exception as exc:
56 logger.exception("Failed to parse Jira webhook event", exc_info=exc)
57 return None
60def _map_jira_event_to_operation(jira_event: str) -> str | None:
61 """Map Jira webhook event type to WS-5 operation."""
62 mapping = {
63 "jira:issue_created": SINGLE_UPSERT,
64 "jira:issue_updated": SINGLE_UPSERT,
65 "jira:issue_deleted": SINGLE_DELETE,
66 }
67 return mapping.get(jira_event)