104 lines
3.1 KiB
Python
104 lines
3.1 KiB
Python
import logging
|
|
from collections import deque
|
|
from multiprocessing import Process, Lock
|
|
from pathlib import Path
|
|
from typing import Annotated
|
|
|
|
from injectable import injectable, Autowired, autowired
|
|
|
|
from app.config import get_settings
|
|
from app.model.webhook import WoodpeckerEvent
|
|
from app.services import Passwords, GitService, DockerService
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class WoodpeckerRunner(Process):
|
|
def __init__(self, git: GitService, docker: DockerService, passwords: Passwords,
|
|
success_callback=None, error_callback=None):
|
|
super().__init__(daemon=True)
|
|
self._git = git
|
|
self._docker = docker
|
|
self._passwords = passwords
|
|
self._success_callback = success_callback
|
|
self._error_callback = error_callback
|
|
self._event: WoodpeckerEvent | None = None
|
|
|
|
def process_event(self, event: WoodpeckerEvent):
|
|
self._event = event
|
|
self.start()
|
|
|
|
def run(self):
|
|
try:
|
|
service = self.get_service(self._event.files)
|
|
if service is None:
|
|
logger.info("No service found.")
|
|
return self._success_callback()
|
|
service_path = f"{get_settings().git.path}/compose/{service}/docker-compose.yml"
|
|
self._git.checkout(self._event.commit)
|
|
for file in self._event.files:
|
|
if file.__contains__('.mo.'):
|
|
pass
|
|
self._docker.reload(Path(service_path))
|
|
|
|
return self._success_callback()
|
|
except Exception as e:
|
|
return self._error_callback(e)
|
|
|
|
def get_service(self, files: list[str]) -> str | None:
|
|
supported_files = []
|
|
for f in files:
|
|
f_parts = f.split("/")
|
|
if f_parts[0] in ["compose", "files"]:
|
|
supported_files.append(f[1])
|
|
match len(set(supported_files)):
|
|
case 0:
|
|
return None
|
|
case 1:
|
|
return supported_files[0]
|
|
case _:
|
|
raise Exception("Multiple services are not supported.")
|
|
|
|
|
|
@injectable(singleton=True)
|
|
class Woodpecker:
|
|
@autowired
|
|
def __init__(self, passwords: Annotated[Passwords, Autowired]):
|
|
self._passwords = passwords
|
|
self._git = GitService()
|
|
self._docker = DockerService()
|
|
self._runner: WoodpeckerRunner | None = None
|
|
self._pending = deque()
|
|
self._lock = Lock()
|
|
logger.info("Woodpecker initialized.")
|
|
|
|
def on_ci_event(self, event: WoodpeckerEvent):
|
|
logger.info(f"Received event: {event}")
|
|
with self._lock:
|
|
if len(self._pending) > 0 or self._runner is not None:
|
|
self._pending.append(event)
|
|
return
|
|
self._start_runner(event)
|
|
|
|
def _start_runner(self, event: WoodpeckerEvent):
|
|
with self._lock:
|
|
self._runner = WoodpeckerRunner(self._git, self._docker, self._on_runner_completed)
|
|
self._runner.process_event(event)
|
|
|
|
def _on_runner_completed(self):
|
|
logger.info("Runner completed.")
|
|
self._runner.join()
|
|
with self._lock:
|
|
self._runner = None
|
|
if len(self._pending) > 0:
|
|
event = self._pending.popleft()
|
|
self._start_runner(event)
|
|
|
|
def _on_runner_error(self, t: Exception):
|
|
logger.error(f"Runner error: {t}", exc_info=True)
|
|
self._runner.join()
|
|
with self._lock:
|
|
self._runner = None
|
|
if len(self._pending) > 0:
|
|
event = self._pending.popleft()
|
|
self._start_runner(event)
|