SourceAnt

Créer un plugin

Le système de plugins de SourceAnt vous permet d'étendre la plateforme avec des intégrations personnalisées, des fournisseurs d'authentification, des backends LLM et bien plus encore.

Vue d'ensemble

Les plugins sont des classes Python qui héritent de BasePlugin. Chaque plugin déclare son type, ses métadonnées et ses hooks de cycle de vie. Le gestionnaire de plugins gère automatiquement la découverte, la résolution des dépendances et le cycle de vie.

Types de plugins

Chaque plugin doit déclarer l'un des types suivants via l' PluginType :

  • INTEGRATION. Intégrations de services externes (GitHub, GitLab, etc.)
  • AUTHENTICATION. Fournisseurs d'authentification (OAuth, SAML, etc.)
  • LLM. Backends de modèles de langage
  • WEBHOOK. Gestionnaires de webhooks
  • NOTIFICATION. Canaux de notification (Slack, Email, etc.)
  • UTILITY. Utilitaires

Démarrage rapide

Créez un nouveau répertoire sous src/plugins/ avec un fichier plugin.py :

src/plugins/
  my_plugin/
    plugin.py
    __init__.py

Voici un plugin minimal :

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

Métadonnées du plugin

Le PluginMetadata La dataclass définit l'identité et la configuration de votre plugin :

Champ Type Description
namestrIdentifiant unique du plugin
versionstrVersion sémantique (par ex., "1.0.0")
descriptionstrBrève description
authorstrAuteur du plugin
plugin_typePluginTypeL'une des valeurs de l'énumération des types de plugins
dependenciesList[str]Noms des plugins dont celui-ci dépend (par défaut : [])
config_schemaDictSchéma JSON pour la validation de la configuration (par défaut : None)
enabledboolIndique si le plugin est actif (par défaut : True)
priorityintPriorité de chargement, plus bas = plus tôt (par défaut : 100)

Hooks de cycle de vie

Les plugins suivent un cycle de vie strict géré par le PluginManager:

  1. Découverte. Le gestionnaire analyse les répertoires de plugins à la recherche de plugin.py ou __init__.py
  2. Chargement. Les classes de plugins sont importées et instanciées
  3. Enregistrement. Les métadonnées sont validées et le plugin est enregistré
  4. Initialisation. _initialize() est appelée dans l'ordre des dépendances
  5. Démarrage. _start() est appelée après l'initialisation de tous les plugins
  6. Arrêt. _stop() est appelée dans l'ordre inverse des dépendances
  7. Nettoyage. _cleanup() s'exécute avant le déchargement du plugin

Surcharge _initialize, _start, _stop, et _cleanup dans votre plugin. Les méthodes de la classe de base (initialize, start, etc.) gèrent le suivi de l'état et appellent vos implémentations.

Système d'événements

Les plugins interagissent avec SourceAnt via des points de hook et des abonnements aux événements.

Points de hook

Enregistrez des callbacks pour les événements de cycle de vie intégrés :

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,
)

Points de hook disponibles :

  • Cycle de vie de l'application. app_startup, app_shutdown
  • Webhooks. before_webhook_processing, after_webhook_processing
  • Revues de code. before_review_generation, after_review_generation, before_review_posting, after_review_posting
  • Authentification. before_user_authentication, after_user_authentication, before_user_logout, after_user_logout
  • Dépôts. before_repository_authorization, after_repository_authorization, before_webhook_setup, after_webhook_setup
  • Erreurs. on_error, on_plugin_error

Abonnements aux événements

Abonnez-vous à des événements spécifiques au domaine pour un contrôle plus granulaire :

event_hooks.subscribe_to_events(
    plugin_name=self.metadata.name,
    callback=self._handle_event,
    event_types=[
        "pull_request.opened",
        "pull_request.synchronize",
    ],
)

Priorité des hooks

Contrôlez l'ordre d'exécution des hooks avec HookPriority:

Niveau Valeur Cas d'usage
HIGHEST0Vérifications de sécurité, validation
HIGH25Pré-traitement, enrichissement
NORMAL50Traitement standard (par défaut)
LOW75Post-traitement, journalisation
LOWEST100Nettoyage, analyses

Découverte des plugins

Le PluginManager découvre automatiquement les plugins en analysant les répertoires enregistrés. Pour qu'un plugin soit découvert, il doit :

  1. Se trouver dans un sous-répertoire d'un répertoire de plugins enregistré
  2. Contenir soit un plugin.py ou __init__.py fichier
  3. Exporter une classe qui hérite de BasePlugin

Les répertoires commençant par un underscore sont ignorés.

Dépendances

Déclarez les dépendances dans vos métadonnées pour garantir le bon ordre de chargement :

PluginMetadata(
    name="my_plugin",
    version="1.0.0",
    description="Depends on GitHub OAuth",
    author="Your Name",
    plugin_type=PluginType.INTEGRATION,
    dependencies=["github_oauth"],
)

Le registre de plugins utilise un tri topologique pour résoudre le graphe de dépendances. Les dépendances circulaires sont détectées et entraîneront une erreur au moment du chargement. La méthode _initialize d'un plugin n'est appelée qu'après l'initialisation de toutes ses dépendances.

Validation de la configuration

Définir un schéma JSON dans config_schema pour valider la configuration du plugin au moment du chargement :

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"],
    },
)

Accéder aux valeurs de configuration validées dans votre plugin avec self.get_config("webhook_url").