Skip to content

Commit

Permalink
WIP3
Browse files Browse the repository at this point in the history
  • Loading branch information
fajpunk committed Jul 10, 2024
1 parent 0ddd80f commit 62283d3
Show file tree
Hide file tree
Showing 25 changed files with 145 additions and 159 deletions.
52 changes: 7 additions & 45 deletions src/mobu/config/github.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,26 @@
"""Config for GitHub application integrations."""

from enum import StrEnum
from textwrap import dedent
from typing import Literal

from pydantic import BaseModel, Field, field_validator
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings

from ..models.user import User


class GafaelfawrScope(StrEnum):
"""Gafaelfawr scopes."""
"""Available Gafaelfawr scopes."""

exec_notebook = "exec:notebook"
exec_portal = "exec:portal"
read_image = "read:image"
read_tap = "read:tap"


class Toggleable(BaseSettings):
"""Type to enable toggling of sections of config."""

enabled: bool = Field(
False,
title="Whether the GitHub CI app is enabled",
description=(
"If set to false, the GitHub CI app will be disabled and the"
" routes to receive webhooks from it will return 404 errors"
),
)


class Disabled(Toggleable):
"""Type indicating that functionality is disabled."""

enabled: Literal[False] = False


class GitHubCiAppEnabled(Toggleable):
class GitHubCiAppConfig(BaseSettings):
"""Configuration for GitHub CI app functionality if it is enabled."""

enabled: Literal[True] = True

id: int = Field(
...,
title="Github CI app id",
Expand Down Expand Up @@ -127,13 +107,11 @@ def check_bot_user(cls, v: list[User]) -> list[User]:
return v


class GitHubRefreshAppEnabled(Toggleable):
class GitHubRefreshAppConfig(BaseSettings):
"""Configuration for GitHub refresh app functionality."""

enabled: Literal[True] = True

webhook_secret: str = Field(
None,
...,
title="Github refresh app webhook secret",
description=(
"Generated when the GitHub app was set up. You can find this"
Expand All @@ -150,19 +128,3 @@ class GitHubRefreshAppEnabled(Toggleable):
" this list will get a 403 response."
),
)


class GitHubCiAppConfig(BaseModel):
"""Config for the GitHub CI app integration."""

app: Disabled | GitHubCiAppEnabled = Field(
Disabled(), title="GitHub CI app config"
)


class GitHubRefreshAppConfig(BaseModel):
"""Config for the GitHub refresh app integration."""

app: Disabled | GitHubRefreshAppEnabled = Field(
Disabled(), title="GitHub refresh app config"
)
67 changes: 28 additions & 39 deletions src/mobu/dependencies/github.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,49 @@
"""Dependencies GitHub CI app functionality."""

from pathlib import Path
from typing import Annotated

import yaml
from fastapi import Depends

from ..config.github import (
GafaelfawrScope,
GitHubCiAppConfig,
GitHubCiAppEnabled,
GitHubRefreshAppEnabled,
GitHubRefreshAppConfig,
)
from ..models.user import User
from ..services.github_ci.ci_manager import CiManager
from .context import ContextDependency


class GitHubCiAppConfigDependency:
"""Holds the config for GitHub CI app integration, loaded from a file."""
"""Config for GitHub CI app integration, loaded from a file."""

def __init__(self) -> None:
self.config: GitHubCiAppConfig

def __call__(self) -> GitHubConfig:
def __call__(self) -> GitHubCiAppConfig:
return self.config

def initialize(self, path: Path | None = None) -> None:
if path is None:
self.config = GitHubCiAppConfig().config
else:
self.config = GitHubCiAppConfig.model_validate(
config=yaml.safe_load(path.read_text())
)


def github_ci_app_config_dependency(
github_config: Annotated[GitHubConfig, Depends(GitHubConfigDependency)],
) -> GitHubCiAppEnabled:
"""Config for an enabled GitHub CI app integration."""
match github_config.ci_app:
case GitHubCiAppEnabled():
return github_config.ci_app
case _:
raise RuntimeError("GitHub CI app functionality is not enabled.")


def github_refresh_app_config_dependency(
github_config: Annotated[GitHubConfig, Depends(GitHubConfigDependency)],
) -> GitHubRefreshAppEnabled:
"""Config for an enabled GitHub refresh app integration."""
match github_config.refresh_app:
case GitHubRefreshAppEnabled():
return github_config.refresh_app
case _:
raise RuntimeError(
"GitHub Refresh app functionality is not enabled."
)
def initialize(self, path: Path) -> None:
self.config = GitHubCiAppConfig.model_validate(
yaml.safe_load(path.read_text())
)


class GitHubRefreshAppConfigDependency:
"""Config for GitHub refresh app integration, loaded from a
file.
"""

def __init__(self) -> None:
self.config: GitHubRefreshAppConfig

def __call__(self) -> GitHubRefreshAppConfig:
return self.config

def initialize(self, path: Path) -> None:
self.config = GitHubRefreshAppConfig.model_validate(
yaml.safe_load(path.read_text())
)


class CiManagerDependency:
Expand All @@ -67,7 +55,7 @@ class CiManagerDependency:
"""

def __init__(self) -> None:
self._ci_manager: CiManager | None
self._ci_manager: CiManager | None = None

@property
def ci_manager(self) -> CiManager:
Expand All @@ -84,11 +72,13 @@ def initialize(
users: list[User],
github_app_id: int,
github_private_key: str,
scopes: list[GafaelfawrScope],
) -> None:
self._ci_manager = CiManager(
users=users,
github_app_id=github_app_id,
github_private_key=github_private_key,
scopes=scopes,
http_client=base_context.process_context.http_client,
gafaelfawr_storage=base_context.process_context.gafaelfawr,
logger=base_context.process_context.logger,
Expand Down Expand Up @@ -116,7 +106,6 @@ def __call__(self) -> CiManager | None:
return None


github_config_dependency = GitHubConfigDependency()
github_refresh_app_config_dependency = GitHubRefreshAppConfigDependency()
github_ci_app_config_dependency = GitHubCiAppConfigDependency()
ci_manager_dependency = CiManagerDependency()
Expand Down
2 changes: 1 addition & 1 deletion src/mobu/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from safir.slack.webhook import SlackWebhookClient
from structlog.stdlib import BoundLogger

from .config.app_config import config
from .config.base_config import config
from .models.solitary import SolitaryConfig
from .services.manager import FlockManager
from .services.solitary import Solitary
Expand Down
2 changes: 1 addition & 1 deletion src/mobu/handlers/external.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from safir.models import ErrorModel
from safir.slack.webhook import SlackRouteErrorHandler

from ..config.app_config import config
from ..config.base_config import config
from ..dependencies.context import RequestContext, context_dependency
from ..dependencies.github import maybe_ci_manager_dependency
from ..models.flock import FlockConfig, FlockData, FlockSummary
Expand Down
4 changes: 2 additions & 2 deletions src/mobu/handlers/github_ci_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from safir.github.webhooks import GitHubCheckRunEventModel
from safir.slack.webhook import SlackRouteErrorHandler

from ..config.github import GitHubCiAppEnabled
from ..config.github import GitHubCiAppConfig
from ..constants import GITHUB_WEBHOOK_WAIT_SECONDS
from ..dependencies.context import RequestContext, anonymous_context_dependency
from ..dependencies.github import (
Expand Down Expand Up @@ -38,7 +38,7 @@
async def post_webhook(
context: Annotated[RequestContext, Depends(anonymous_context_dependency)],
ci_app_config: Annotated[
GitHubCiAppEnabled, Depends(github_ci_app_config_dependency)
GitHubCiAppConfig, Depends(github_ci_app_config_dependency)
],
ci_manager: Annotated[CiManager, Depends(ci_manager_dependency)],
) -> None:
Expand Down
4 changes: 2 additions & 2 deletions src/mobu/handlers/github_refresh_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from safir.github.webhooks import GitHubPushEventModel
from safir.slack.webhook import SlackRouteErrorHandler

from ..config.github import GitHubRefreshAppEnabled
from ..config.github import GitHubRefreshAppConfig
from ..constants import GITHUB_WEBHOOK_WAIT_SECONDS
from ..dependencies.context import RequestContext, anonymous_context_dependency
from ..dependencies.github import github_refresh_app_config_dependency
Expand All @@ -33,7 +33,7 @@
async def post_webhook(
context: Annotated[RequestContext, Depends(anonymous_context_dependency)],
refresh_app_config: Annotated[
GitHubRefreshAppEnabled,
GitHubRefreshAppConfig,
Depends(github_refresh_app_config_dependency),
],
) -> None:
Expand Down
2 changes: 1 addition & 1 deletion src/mobu/handlers/internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from safir.metadata import Metadata, get_metadata
from safir.slack.webhook import SlackRouteErrorHandler

from ..config.app_config import config
from ..config.base_config import config

internal_router = APIRouter(route_class=SlackRouteErrorHandler)
"""FastAPI router for all internal handlers."""
Expand Down
31 changes: 19 additions & 12 deletions src/mobu/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@
from safir.middleware.x_forwarded import XForwardedMiddleware
from safir.slack.webhook import SlackRouteErrorHandler

from mobu.config.github import GitHubCiAppEnabled

from .asyncio import schedule_periodic
from .config.app_config import config
from .dependencies.context import ContextDependency, context_dependency
from .config.base_config import config
from .dependencies.context import context_dependency
from .dependencies.github import (
ci_manager_dependency,
github_config_dependency,
github_ci_app_config_dependency,
github_refresh_app_config_dependency,
)
from .handlers.external import external_router
from .handlers.github_ci_app import api_router as github_ci_app_router
Expand All @@ -44,7 +43,7 @@


@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[ContextDependency]:
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
"""Set up and tear down the the base application."""
if not config.environment_url:
raise RuntimeError("MOBU_ENVIRONMENT_URL was not set")
Expand All @@ -57,19 +56,27 @@ async def lifespan(app: FastAPI) -> AsyncIterator[ContextDependency]:
status_interval = timedelta(days=1)
app.state.periodic_status = schedule_periodic(post_status, status_interval)

github_config_dependency.initialize(config.github_config_path)
ci_app_config = github_config_dependency.config.ci_app
if config.github_refresh_app_config_path:
github_refresh_app_config_dependency.initialize(
config.github_refresh_app_config_path
)

if config.github_ci_app_config_path:
github_ci_app_config_dependency.initialize(
config.github_ci_app_config_path
)
ci_app_config = github_ci_app_config_dependency.config

if isinstance(ci_app_config, GitHubCiAppEnabled):
ci_manager_dependency.initialize(
base_context=context_dependency,
github_app_id=ci_app_config.id,
github_private_key=ci_app_config.private_key,
scopes=ci_app_config.scopes,
users=ci_app_config.users,
)
await ci_manager_dependency.ci_manager.start()

yield context_dependency
yield

await ci_manager_dependency.aclose()
await context_dependency.aclose()
Expand Down Expand Up @@ -97,12 +104,12 @@ async def lifespan(app: FastAPI) -> AsyncIterator[ContextDependency]:
app.include_router(internal_router)
app.include_router(external_router, prefix=config.path_prefix)

if github_config_dependency.config.ci_app.enabled:
if config.github_ci_app_config_path:
app.include_router(
github_ci_app_router, prefix=f"{config.path_prefix}/github/ci"
)

if github_config_dependency.config.refresh_app.enabled:
if config.github_refresh_app_config_path:
app.include_router(
github_refresh_app_router,
prefix=f"{config.path_prefix}/github/refresh",
Expand Down
2 changes: 1 addition & 1 deletion src/mobu/services/business/nublado.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from safir.slack.blockkit import SlackException
from structlog.stdlib import BoundLogger

from ...config.app_config import config
from ...config.base_config import config
from ...exceptions import JupyterSpawnError, JupyterTimeoutError
from ...models.business.nublado import (
NubladoBusinessData,
Expand Down
2 changes: 1 addition & 1 deletion src/mobu/services/business/tap.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from httpx import AsyncClient
from structlog.stdlib import BoundLogger

from ...config.app_config import config
from ...config.base_config import config
from ...exceptions import CodeExecutionError, TAPClientError
from ...models.business.tap import TAPBusinessData, TAPBusinessOptions
from ...models.user import AuthenticatedUser
Expand Down
Loading

0 comments on commit 62283d3

Please sign in to comment.