Compare commits
No commits in common. "develop" and "master" have entirely different histories.
10 changed files with 9 additions and 92 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -14,6 +14,6 @@ uv.lock
|
||||||
**/*.kdbx*
|
**/*.kdbx*
|
||||||
.compose_repository
|
.compose_repository
|
||||||
|
|
||||||
deployment/
|
__pycache__/
|
||||||
**/dist/
|
**/dist/
|
||||||
**/*.log
|
**/*.log
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ from starlette.responses import JSONResponse, Response
|
||||||
|
|
||||||
from karl.api.models import Request
|
from karl.api.models import Request
|
||||||
from karl.core.injects import AutowireSupport
|
from karl.core.injects import AutowireSupport
|
||||||
from karl.model.webhook import WoodpeckerEvent, ReloadEvent
|
from karl.core.woodpecker import Woodpecker
|
||||||
|
from karl.model.webhook import WoodpeckerEvent
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -20,6 +21,7 @@ async def root():
|
||||||
|
|
||||||
@cbv(router)
|
@cbv(router)
|
||||||
class APIv1:
|
class APIv1:
|
||||||
|
woodpecker: Woodpecker = Depends(AutowireSupport.woodpecker)
|
||||||
bus: EventBus = Depends(AutowireSupport.bus)
|
bus: EventBus = Depends(AutowireSupport.bus)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
@ -37,10 +39,3 @@ class APIv1:
|
||||||
async def ci(self, request: Request):
|
async def ci(self, request: Request):
|
||||||
await self.bus.dispatch(mapper.map(request))
|
await self.bus.dispatch(mapper.map(request))
|
||||||
return Response(status_code=201)
|
return Response(status_code=201)
|
||||||
|
|
||||||
@router.get("/reload", summary="Manual service reload")
|
|
||||||
async def reload(self, service: str = None) -> Response:
|
|
||||||
if service is None:
|
|
||||||
return Response(status_code=400)
|
|
||||||
await self.bus.dispatch(ReloadEvent(service=service))
|
|
||||||
return Response(status_code=201)
|
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,4 @@ class Settings(BaseSettings):
|
||||||
|
|
||||||
@lru_cache
|
@lru_cache
|
||||||
def get_settings() -> Settings:
|
def get_settings() -> Settings:
|
||||||
paths = ['deployment/config.yaml', 'config/config.yaml']
|
return Settings.from_yaml()
|
||||||
for path in paths:
|
|
||||||
if Path(path).exists():
|
|
||||||
return Settings.from_yaml(path)
|
|
||||||
raise Exception("Config file not found")
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
from bubus import EventBus
|
from bubus import EventBus
|
||||||
from injectable import inject
|
from injectable import inject
|
||||||
|
|
||||||
from karl.core.reload import ReloadService
|
|
||||||
from karl.core.woodpecker import Woodpecker
|
from karl.core.woodpecker import Woodpecker
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -11,10 +10,6 @@ class AutowireSupport:
|
||||||
def woodpecker():
|
def woodpecker():
|
||||||
return inject(Woodpecker)
|
return inject(Woodpecker)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def reload():
|
|
||||||
return inject(ReloadService)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def bus():
|
def bus():
|
||||||
return inject(EventBus)
|
return inject(EventBus)
|
||||||
|
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
import logging
|
|
||||||
from datetime import datetime
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Annotated
|
|
||||||
|
|
||||||
from bubus import EventBus
|
|
||||||
from injectable import injectable, autowired, Autowired
|
|
||||||
|
|
||||||
from karl import get_settings
|
|
||||||
from model.webhook import ReloadEvent, WoodpeckerEvent
|
|
||||||
from services import GitService
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
@injectable(singleton=True)
|
|
||||||
class ReloadService:
|
|
||||||
|
|
||||||
@autowired
|
|
||||||
def __init__(self, bus: Annotated[EventBus, Autowired]):
|
|
||||||
self._bus = bus
|
|
||||||
self._git = GitService()
|
|
||||||
bus.on(ReloadEvent, self.on_reload)
|
|
||||||
self.root_path = get_settings().git.path
|
|
||||||
logger.info("ReloadService initialized.")
|
|
||||||
|
|
||||||
async def on_reload(self, event: ReloadEvent):
|
|
||||||
try:
|
|
||||||
logger.info(f"Received ReloadEvent: {event.service}")
|
|
||||||
head = self._git.get_head()
|
|
||||||
file_path = Path(self.root_path) / f"files/{event.service}"
|
|
||||||
if not file_path.exists():
|
|
||||||
raise Exception(f"Service {event.service} not found: {file_path.absolute()} does not exist.")
|
|
||||||
logger.debug(f"Found service files at {file_path}: {', '.join([str(f) for f in list(file_path.iterdir())])}")
|
|
||||||
mos = list(file_path.glob('*.mo.*'))
|
|
||||||
logger.debug(f"Found {len(mos)} .mo files")
|
|
||||||
we = WoodpeckerEvent(
|
|
||||||
_id=-1,
|
|
||||||
commit=head.sha,
|
|
||||||
ref=head.branch,
|
|
||||||
message=f"Manual reload of {event.service}",
|
|
||||||
started=int(datetime.now().timestamp()),
|
|
||||||
files=[f"compose/{event.service}/docker-compose.yml"] + [str(pp).replace(str(self.root_path), '') for pp in mos]
|
|
||||||
)
|
|
||||||
logger.debug(f"Sending <WoodpeckerEvent commit={we.commit} ref={we.ref} message={we.message} started={we.started} files={we.files}")
|
|
||||||
await self._bus.dispatch(we)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Reload error: {e}", exc_info=True)
|
|
||||||
|
|
@ -3,7 +3,6 @@ import logging
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from injectable import load_injection_container
|
from injectable import load_injection_container
|
||||||
|
|
||||||
from core.injects import AutowireSupport
|
|
||||||
from karl.config import get_settings
|
from karl.config import get_settings
|
||||||
from karl.util.logging import HandlerFactory
|
from karl.util.logging import HandlerFactory
|
||||||
|
|
||||||
|
|
@ -16,7 +15,7 @@ class KarlApplication:
|
||||||
_app = FastAPI(title="Karl", version="0.1.0")
|
_app = FastAPI(title="Karl", version="0.1.0")
|
||||||
self._set_middlewares(_app)
|
self._set_middlewares(_app)
|
||||||
self._set_routes(_app)
|
self._set_routes(_app)
|
||||||
self._init_services(_app)
|
self._set_events(_app)
|
||||||
|
|
||||||
self._app = _app
|
self._app = _app
|
||||||
|
|
||||||
|
|
@ -56,9 +55,8 @@ class KarlApplication:
|
||||||
app.include_router(api_v1_router, prefix="/api/v1", tags=["v1"])
|
app.include_router(api_v1_router, prefix="/api/v1", tags=["v1"])
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _init_services(self, app: FastAPI):
|
def _set_events(self, app: FastAPI):
|
||||||
AutowireSupport.reload()
|
pass
|
||||||
AutowireSupport.woodpecker()
|
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
from dataclasses import dataclass
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Head:
|
|
||||||
sha: str
|
|
||||||
branch: str
|
|
||||||
|
|
@ -10,6 +10,3 @@ class WoodpeckerEvent(BaseEvent):
|
||||||
message: str
|
message: str
|
||||||
started: int
|
started: int
|
||||||
files: List[str]
|
files: List[str]
|
||||||
|
|
||||||
class ReloadEvent(BaseEvent):
|
|
||||||
service: str
|
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,4 @@ class DockerService:
|
||||||
os.chdir(compose_path.parent)
|
os.chdir(compose_path.parent)
|
||||||
self._client.compose.ps()
|
self._client.compose.ps()
|
||||||
self._client.compose.down(remove_orphans=True)
|
self._client.compose.down(remove_orphans=True)
|
||||||
self._client.compose.up(detach=True)
|
self._client.compose.up()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ from git import Repo, Remote
|
||||||
from injectable import injectable
|
from injectable import injectable
|
||||||
|
|
||||||
from karl.config import GitConfig, get_settings
|
from karl.config import GitConfig, get_settings
|
||||||
from model.vcs import Head
|
|
||||||
|
|
||||||
|
|
||||||
@injectable(singleton=True)
|
@injectable(singleton=True)
|
||||||
|
|
@ -28,11 +27,3 @@ class GitService:
|
||||||
def checkout(self, sha: str):
|
def checkout(self, sha: str):
|
||||||
self._origin.fetch()
|
self._origin.fetch()
|
||||||
self._repo.git.checkout(sha)
|
self._repo.git.checkout(sha)
|
||||||
|
|
||||||
def get_head(self) -> Head:
|
|
||||||
if self._repo.head.is_detached:
|
|
||||||
return Head(self._repo.head.object.hexsha, "detached")
|
|
||||||
return Head(
|
|
||||||
self._repo.active_branch.commit.hexsha,
|
|
||||||
self._repo.active_branch.name
|
|
||||||
)
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue