Crear un plugin
El sistema de plugins de SourceAnt le permite ampliar la plataforma con integraciones personalizadas, proveedores de autenticación, backends LLM y más.
Resumen
Los plugins son clases de Python que heredan de BasePlugin. Cada plugin declara su tipo, metadatos y hooks de ciclo de vida. El gestor de plugins maneja automáticamente el descubrimiento, la resolución de dependencias y la gestión del ciclo de vida.
Tipos de plugins
Cada plugin debe declarar uno de los siguientes tipos mediante el PluginType enum:
- INTEGRATION. Integraciones de servicios externos (GitHub, GitLab, etc.)
- AUTHENTICATION. Proveedores de autenticación (OAuth, SAML, etc.)
- LLM. Backends de modelos de lenguaje
- WEBHOOK. Manejadores de webhooks
- NOTIFICATION. Canales de notificación (Slack, Email, etc.)
- UTILITY. Utilidades auxiliares
Inicio rápido
Cree un nuevo directorio bajo src/plugins/ con un plugin.py archivo:
src/plugins/
my_plugin/
plugin.py
__init__.py Aquí hay un plugin mínimo:
from src.core.plugins import BasePlugin, PluginMetadata, PluginType
class MyPlugin(BasePlugin):
@property
def metadata(self) -> PluginMetadata:
return PluginMetadata(
name="my_plugin",
version="1.0.0",
description="A custom plugin",
author="Your Name",
plugin_type=PluginType.UTILITY,
)
async def _initialize(self) -> None:
# One-time setup: register routes, connect to services
pass
async def _start(self) -> None:
# Called after all plugins are initialized
pass
async def _stop(self) -> None:
# Graceful shutdown
pass
async def _cleanup(self) -> None:
# Final cleanup before unload
pass Metadatos del plugin
La PluginMetadata La dataclass define la identidad y configuración de su plugin:
| Campo | Tipo | Descripción |
|---|---|---|
name | str | Identificador único del plugin |
version | str | Versión semántica (por ejemplo, "1.0.0") |
description | str | Descripción breve |
author | str | Autor del plugin |
plugin_type | PluginType | Uno de los valores del enum de tipo de plugin |
dependencies | List[str] | Nombres de los plugins de los que depende (predeterminado: []) |
config_schema | Dict | Esquema JSON para la validación de la configuración (predeterminado: None) |
enabled | bool | Si el plugin está activo (predeterminado: True) |
priority | int | Prioridad de carga, menor = antes (predeterminado: 100) |
Hooks del ciclo de vida
Los plugins siguen un ciclo de vida estricto gestionado por el PluginManager:
- Descubrimiento. El gestor escanea los directorios de plugins en busca de
plugin.pyo__init__.py - Carga. Las clases de plugin se importan y se instancian
- Registro. Los metadatos se validan y el plugin se registra
- Inicialización.
_initialize()se llama en orden de dependencias - Arranque.
_start()se llama después de que todos los plugins se hayan inicializado - Apagado.
_stop()se llama en orden inverso de dependencias - Limpieza.
_cleanup()se ejecuta antes de que el plugin se descargue
Sobrescribir _initialize, _start, _stop, y _cleanup en su plugin. Los métodos de la clase base (initialize, start, etc.) gestionan el seguimiento del estado y llaman a sus implementaciones.
Sistema de eventos
Los plugins interactúan con SourceAnt mediante puntos de enganche y suscripciones a eventos.
Puntos de enganche
Registre callbacks para eventos integrados del ciclo de vida:
from src.core.plugins import event_hooks, HookPriority
# In your _initialize method:
event_hooks.register_hook(
hook_name="before_review_generation",
callback=self._on_before_review,
plugin_name=self.metadata.name,
priority=HookPriority.NORMAL,
) Puntos de enganche disponibles:
- Ciclo de vida de la aplicación.
app_startup,app_shutdown - Webhooks.
before_webhook_processing,after_webhook_processing - Revisiones de código.
before_review_generation,after_review_generation,before_review_posting,after_review_posting - Autenticación.
before_user_authentication,after_user_authentication,before_user_logout,after_user_logout - Repositorios.
before_repository_authorization,after_repository_authorization,before_webhook_setup,after_webhook_setup - Errores.
on_error,on_plugin_error
Suscripciones a eventos
Suscríbase a eventos específicos de dominio para un control más granular:
event_hooks.subscribe_to_events(
plugin_name=self.metadata.name,
callback=self._handle_event,
event_types=[
"pull_request.opened",
"pull_request.synchronize",
],
) Prioridad de hooks
Controle el orden en que se ejecutan los hooks con HookPriority:
| Nivel | Valor | Caso de uso |
|---|---|---|
HIGHEST | 0 | Comprobaciones de seguridad, validación |
HIGH | 25 | Preprocesamiento, enriquecimiento |
NORMAL | 50 | Procesamiento estándar (predeterminado) |
LOW | 75 | Posprocesamiento, registro |
LOWEST | 100 | Limpieza, analítica |
Descubrimiento de plugins
La PluginManager descubre automáticamente los plugins escaneando los directorios registrados. Para que un plugin sea descubierto, debe:
- Estar en un subdirectorio de un directorio de plugins registrado
- Contener un archivo
plugin.pyo__init__.pyarchivo - Exportar una clase que herede de
BasePlugin
Se omiten los directorios que empiezan por guion bajo.
Dependencias
Declare las dependencias en sus metadatos para garantizar el orden de carga correcto:
PluginMetadata(
name="my_plugin",
version="1.0.0",
description="Depends on GitHub OAuth",
author="Your Name",
plugin_type=PluginType.INTEGRATION,
dependencies=["github_oauth"],
) El registro de plugins utiliza la ordenación topológica para resolver el grafo de dependencias. Las dependencias circulares se detectan y provocarán un error en el momento de la carga. El método _initialize de un plugin solo se llama después de que se hayan inicializado todas sus dependencias.
Validación de la configuración
Definir un JSON Schema en config_schema para validar la configuración del plugin en el momento de la carga:
PluginMetadata(
name="my_notifier",
version="1.0.0",
description="Slack notifications",
author="Your Name",
plugin_type=PluginType.NOTIFICATION,
config_schema={
"type": "object",
"properties": {
"webhook_url": {"type": "string"},
"channel": {"type": "string"},
},
"required": ["webhook_url"],
},
) Acceder a los valores de configuración validados en su plugin con self.get_config("webhook_url").