Ein eigenes Plugin schreiben
semrel-Plugins sind eigenständige Executables — jede Sprache, die Umgebungsvariablen lesen, JSON nach stdout schreiben und mit einem sinnvollen Code beenden kann, kann den Plugin-Vertrag umsetzen.
Diese Anleitung führt dich durch den Bau eines minimalen Provider Plugins in Go.
Plugin-Vertrag
Abschnitt betitelt „Plugin-Vertrag“Jedes semrel-Plugin kommuniziert über zwei Kanäle:
| Kanal | Richtung | Zweck |
|---|---|---|
| Umgebungsvariablen | → Plugin | Release-Kontext + Plugin-Konfiguration |
| stdout (JSON) | Plugin → | Ergebnisse (nur Analyzer) |
| stderr | Plugin → | Logs, Warnungen, plugin_schema_version=N |
| Exit-Code | Plugin → | 0 = Erfolg, ungleich null = Release abbrechen |
Umgebungsvariablen
Abschnitt betitelt „Umgebungsvariablen“semrel setzt vor der Ausführung jedes Plugins die folgenden Variablen:
| Variable | Beschreibung |
|---|---|
SEMREL_VERSION | semrel-CLI-Version |
SEMREL_TAG_NAME | Vollständiger Tag-Name (v1.2.3) |
SEMREL_CURRENT_VERSION | Aktuelle Projektversion |
SEMREL_NEXT_VERSION | Berechnete nächste Version |
SEMREL_BUMP | Bump-Stufe: major, minor, patch oder none |
SEMREL_BRANCH | Aktueller git-Branch |
SEMREL_TAG_PREFIX | Konfiguriertes Tag-Präfix |
SEMREL_CHANGELOG | Erzeugter Changelog-Inhalt |
SEMREL_DRY_RUN | true bei Ausführung mit --dry-run |
SEMREL_COMMITS | JSON-Array der rohen Commit-Messages im aktuellen Release-Fenster |
SEMREL_CONTRIBUTORS | JSON-Array der Contributor-Metadaten für das aktuelle Release-Fenster, nach Commit-Anzahl absteigend sortiert |
Plugin-spezifische args: aus .semrel.yaml werden als SEMREL_PLUGIN_<KEY>=<value> bereitgestellt (Schlüssel in Großbuchstaben).
SEMREL_CONTRIBUTORS enthält Objekte im Format {"name":"Jane Doe","email":"jane@example.com","commits":3,"firstContribution":true}. Die Variable ist nur für Plugins verfügbar, die nach der Analyse des Release-Commit-Bereichs laufen (z. B. Generator-, Pre-Tag-, Provider-, Hook-, Publisher- und Updater-Plugins).
Schema-Versionierung
Abschnitt betitelt „Schema-Versionierung“Jedes Plugin sollte beim Start seine Schema-Version ausgeben:
echo "plugin_schema_version=1" >&2So weiß semrel, welche Version des Env-Var-Vertrags das Plugin erwartet, und kann künftig Kompatibilitätsprüfungen durchführen.
Projektstruktur
Abschnitt betitelt „Projektstruktur“Erstelle dein Modul
Terminal-Fenster mkdir semrel-plugin-my-providercd semrel-plugin-my-providergo mod init github.com/yourorg/semrel-plugin-my-providerFüge Abhängigkeiten hinzu
Terminal-Fenster go get github.com/SemRels/semrel-plugin-sdk # optional: helpers for env-var readingImplementiere das Plugin
Erstelle
cmd/plugin/main.go:package mainimport ("fmt""os")func main() {if err := run(os.Environ(), os.Stdout, os.Stderr); err != nil {fmt.Fprintln(os.Stderr, "error:", err)os.Exit(1)}}func run(env []string, stdout, stderr *os.File) error {// Announce schema version.fmt.Fprintln(stderr, "plugin_schema_version=1")// Read context from environment.nextVersion := os.Getenv("SEMREL_NEXT_VERSION")dryRun := os.Getenv("SEMREL_DRY_RUN") == "true"token := os.Getenv("SEMREL_PLUGIN_TOKEN") // from args: token: ${{ secrets.MY_TOKEN }}if token == "" {return fmt.Errorf("SEMREL_PLUGIN_TOKEN is required")}if dryRun {fmt.Fprintf(stderr, "[dry-run] would publish release %s\n", nextVersion)return nil}// TODO: call your platform API here.fmt.Fprintf(stderr, "published release %s\n", nextVersion)return nil}Baue die Binärdatei
semrel sucht nach einer Binärdatei namens
semrel-plugin-<name>in~/.semrel/plugins/oder in$PATH.Terminal-Fenster go build -o semrel-plugin-my-provider ./cmd/pluginmkdir -p ~/.semrel/pluginscp semrel-plugin-my-provider ~/.semrel/plugins/Binde es in
.semrel.yamleinplugins:- uses: my-provider # resolves to semrel-plugin-my-providerargs:token: ${{ env.MY_TOKEN }}Teste es
Terminal-Fenster semrel release --dry-run
Unit-Tests schreiben
Abschnitt betitelt „Unit-Tests schreiben“Der einfachste Testansatz ist, run() direkt mit Mock-Werten für die Umgebung aufzurufen:
package main_test
import ( "bytes" "testing"
"github.com/stretchr/testify/require")
func TestRunDryRun(t *testing.T) { env := map[string]string{ "SEMREL_NEXT_VERSION": "1.2.0", "SEMREL_DRY_RUN": "true", "SEMREL_PLUGIN_TOKEN": "test-token", }
var stdout, stderr bytes.Buffer err := run(env, &stdout, &stderr) require.NoError(t, err) require.Contains(t, stderr.String(), "plugin_schema_version=1") require.Contains(t, stderr.String(), "[dry-run] would publish release 1.2.0")}Dein Plugin veröffentlichen
Abschnitt betitelt „Dein Plugin veröffentlichen“1. Ein Release taggen
Abschnitt betitelt „1. Ein Release taggen“semrel selbst ist dafür das empfohlene Tool:
semrel release2. In die Registry einreichen
Abschnitt betitelt „2. In die Registry einreichen“Reiche dein Plugin ein, damit es in der offiziellen semrel-Plugin-Registry gelistet wird:
gh api POST https://registry.semrel.io/api/v1/plugins/submit \ --field name=my-provider \ --field description="My custom provider plugin" \ --field repository=https://github.com/yourorg/semrel-plugin-my-provider \ --field category=provider \ --field license=MITOder besuche registry.semrel.io und klicke auf Submit Plugin.
3. Ein JSON Schema hinzufügen
Abschnitt betitelt „3. Ein JSON Schema hinzufügen“Erstelle schema/v1.json in deinem Repository, um die SEMREL_PLUGIN_*-Variablen zu dokumentieren, die dein Plugin akzeptiert:
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://registry.semrel.io/schemas/plugins/my-provider/v1.json", "title": "my-provider plugin schema", "type": "object", "properties": { "SEMREL_PLUGIN_TOKEN": { "type": "string", "description": "API token for the target platform." } }, "required": ["SEMREL_PLUGIN_TOKEN"]}Dieses Schema wird von der Registry unter /schemas/plugins/my-provider/v1.json ausgeliefert und aktiviert Editor-Autovervollständigung für die .semrel.yaml-Dateien deiner Nutzer.
Referenz der Plugin-Typen
Abschnitt betitelt „Referenz der Plugin-Typen“| Typ | Ausgabe | Exit bei Fehler | Zweck |
|---|---|---|---|
| Analyzer | JSON nach stdout | Ja | Bestimmt aus Commits die nächste Version |
| Generator | Nichts (Side Effects) | Ja | Erzeugt Release-Artefakte (Changelog usw.) |
| Provider | Nichts (Side Effects) | Ja | Veröffentlicht das Release auf einer Plattform |
| Condition | Nichts | Ja (ungleich null) | Gate — bricht das Release ab, wenn Bedingungen nicht erfüllt sind |
| Hook | Nichts (Side Effects) | Optional | Lifecycle-Callbacks (vor/nach Release) |
| Updater | Nichts (Side Effects) | Ja | Aktualisiert Versions-Strings in Projektdateien |
| Packager | Nichts (Side Effects) | Ja | Baut verteilbare Release-Artefakte |
| Publisher | Nichts (Side Effects) | Ja | Lädt Artefakte in Registries oder HTTP-Endpunkte hoch |