SourceAnt

Ein Plugin erstellen

Das Plugin-System von SourceAnt ermöglicht es Ihnen, die Plattform mit benutzerdefinierten Integrationen, Authentifizierungsanbietern, LLM-Backends und mehr zu erweitern.

Übersicht

Plugins sind Python-Klassen, die von BasePlugin. erben. Jedes Plugin deklariert seinen Typ, Metadaten und Lifecycle-Hooks. Der Plugin-Manager übernimmt automatisch Discovery, Abhängigkeitsauflösung und Lifecycle-Verwaltung.

Plugin-Typen

Jedes Plugin muss einen der folgenden Typen über das PluginType Enum deklarieren:

  • INTEGRATION. Integrationen externer Dienste (GitHub, GitLab usw.)
  • AUTHENTICATION. Authentifizierungsanbieter (OAuth, SAML usw.)
  • LLM. Sprachmodell-Backends
  • WEBHOOK. Webhook-Handler
  • NOTIFICATION. Benachrichtigungskanäle (Slack, E-Mail usw.)
  • UTILITY. Hilfsprogramme

Schnellstart

Erstellen Sie ein neues Verzeichnis unter src/plugins/ mit einer plugin.py Datei:

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

Hier ist ein minimales Plugin:

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

Plugin-Metadaten

Der PluginMetadata dataclass definiert die Identität und Konfiguration Ihres Plugins:

Feld Typ Beschreibung
namestrEindeutiger Plugin-Bezeichner
versionstrSemantische Version (z. B. "1.0.0")
descriptionstrKurze Beschreibung
authorstrPlugin-Autor
plugin_typePluginTypeEiner der Enum-Werte des Plugin-Typs
dependenciesList[str]Namen der Plugins, von denen dieses abhängt (Standard: [])
config_schemaDictJSON Schema für die Konfigurationsvalidierung (Standard: None)
enabledboolOb das Plugin aktiv ist (Standard: True)
priorityintLadepriorität, niedriger = früher (Standard: 100)

Lifecycle-Hooks

Plugins folgen einem strikten Lifecycle, der von der PluginManager:

  1. Discovery. Der Manager durchsucht Plugin-Verzeichnisse nach plugin.py oder __init__.py
  2. Loading. Plugin-Klassen werden importiert und instanziiert
  3. Registration. Metadaten werden validiert und das Plugin wird registriert
  4. Initialization. _initialize() wird in Abhängigkeitsreihenfolge aufgerufen
  5. Startup. _start() wird aufgerufen, nachdem alle Plugins initialisiert wurden
  6. Shutdown. _stop() wird in umgekehrter Abhängigkeitsreihenfolge aufgerufen
  7. Cleanup. _cleanup() wird ausgeführt, bevor das Plugin entladen wird

Überschreiben _initialize, _start, _stop, und _cleanup in Ihrem Plugin. Die Methoden der Basisklasse (initialize, start, usw.) übernehmen die Zustandsverfolgung und rufen Ihre Implementierungen auf.

Ereignissystem

Plugins interagieren mit SourceAnt über Hook-Punkte und Ereignis-Abonnements.

Hook-Punkte

Registrieren Sie Callbacks für integrierte Lifecycle-Ereignisse:

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

Verfügbare Hook-Punkte:

  • App-Lifecycle. app_startup, app_shutdown
  • Webhooks. before_webhook_processing, after_webhook_processing
  • Code-Reviews. before_review_generation, after_review_generation, before_review_posting, after_review_posting
  • Authentifizierung. before_user_authentication, after_user_authentication, before_user_logout, after_user_logout
  • Repositories. before_repository_authorization, after_repository_authorization, before_webhook_setup, after_webhook_setup
  • Fehler. on_error, on_plugin_error

Ereignis-Abonnements

Abonnieren Sie domänenspezifische Ereignisse für eine granularere Steuerung:

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

Hook-Priorität

Steuern Sie die Ausführungsreihenfolge von Hooks mit HookPriority:

Ebene Wert Anwendungsfall
HIGHEST0Sicherheitsprüfungen, Validierung
HIGH25Vorverarbeitung, Anreicherung
NORMAL50Standardverarbeitung (Standard)
LOW75Nachverarbeitung, Protokollierung
LOWEST100Bereinigung, Analytik

Plugin-Discovery

Der PluginManager entdeckt Plugins automatisch durch Scannen registrierter Verzeichnisse. Damit ein Plugin entdeckt wird, muss es:

  1. sich in einem Unterverzeichnis eines registrierten Plugin-Verzeichnisses befinden
  2. entweder eine plugin.py oder __init__.py Datei
  3. Exportieren Sie eine Klasse, die erbt von BasePlugin

Verzeichnisse, die mit einem Unterstrich beginnen, werden übersprungen.

Abhängigkeiten

Deklarieren Sie Abhängigkeiten in Ihren Metadaten, um eine korrekte Ladereihenfolge sicherzustellen:

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

Die Plugin-Registry verwendet topologische Sortierung, um den Abhängigkeitsgraphen aufzulösen. Zirkuläre Abhängigkeiten werden erkannt und führen beim Laden zu einem Fehler. Die _initialize Methode eines Plugins wird erst aufgerufen, nachdem alle seine Abhängigkeiten initialisiert wurden.

Konfigurationsvalidierung

Definieren Sie ein JSON Schema in config_schema um die Plugin-Konfiguration beim Laden zu validieren:

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

Greifen Sie in Ihrem Plugin mit auf validierte Konfigurationswerte zu self.get_config("webhook_url").