Files
TimeTracker/src/citrus_time_tracker/youtrack_client.py
2026-03-10 05:42:27 +03:00

81 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import httpx
import os
import logging
from pathlib import Path
logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger("YouTrackClient")
class YouTrackClient:
def __init__(self):
self.base_url = os.getenv("YOUTRACK_URL")
self.token = os.getenv("YOUTRACK_TOKEN")
self.ca_bundle = os.getenv("YOUTRACK_CA_BUNDLE")
if not self.base_url or not self.token:
self.enabled = False
logger.info("YouTrack: .env не настроен — синхронизация отключена")
return
# Определяем verify параметр для httpx
if self.ca_bundle:
ca_path = Path(self.ca_bundle)
if ca_path.exists():
self.verify = str(ca_path.resolve())
logger.info(f"YouTrack: использую CA bundle: {self.verify}")
else:
logger.error(f"YouTrack: CA bundle не найден: {ca_path}")
self.verify = True # fallback на системные
else:
self.verify = True # стандартное поведение
self.enabled = True
self.headers = {
"Authorization": f"Bearer {self.token}",
"Content-Type": "application/json",
"Accept": "application/json"
}
self.base_url = self.base_url.rstrip('/')
def _get_client(self) -> httpx.Client:
"""Создаёт HTTP-клиент с правильной настройкой SSL"""
return httpx.Client(verify=self.verify, timeout=15)
def issue_exists(self, issue_id: str) -> bool:
if not self.enabled:
return False
try:
with self._get_client() as client:
url = f"{self.base_url}/api/issues/{issue_id}"
resp = client.get(url, headers=self.headers)
exists = resp.status_code == 200
if not exists:
logger.warning(f"YouTrack: задача {issue_id} не найдена (HTTP {resp.status_code})")
return exists
except Exception as e:
logger.error(f"YouTrack: ошибка при проверке задачи {issue_id}: {e}")
return False
def add_work_item(self, issue_id: str, minutes: float) -> bool:
if not self.enabled:
return False
if minutes <= 0:
return True
payload = {"duration": {"minutes": round(minutes)}}
try:
with self._get_client() as client:
url = f"{self.base_url}/api/issues/{issue_id}/timeTracking/workItems"
resp = client.post(url, headers=self.headers, json=payload)
if resp.status_code in (200, 201):
logger.info(f"YouTrack: +{round(minutes)} мин к {issue_id}")
return True
else:
logger.error(f"YouTrack: ошибка отправки времени ({issue_id}): {resp.status_code} {resp.text}")
return False
except Exception as e:
logger.error(f"YouTrack: сетевая ошибка при отправке времени ({issue_id}): {e}")
return False