Zum Inhalt springen

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.

Jedes semrel-Plugin kommuniziert über zwei Kanäle:

KanalRichtungZweck
Umgebungsvariablen→ PluginRelease-Kontext + Plugin-Konfiguration
stdout (JSON)Plugin →Ergebnisse (nur Analyzer)
stderrPlugin →Logs, Warnungen, plugin_schema_version=N
Exit-CodePlugin →0 = Erfolg, ungleich null = Release abbrechen

semrel setzt vor der Ausführung jedes Plugins die folgenden Variablen:

VariableBeschreibung
SEMREL_VERSIONsemrel-CLI-Version
SEMREL_TAG_NAMEVollständiger Tag-Name (v1.2.3)
SEMREL_CURRENT_VERSIONAktuelle Projektversion
SEMREL_NEXT_VERSIONBerechnete nächste Version
SEMREL_BUMPBump-Stufe: major, minor, patch oder none
SEMREL_BRANCHAktueller git-Branch
SEMREL_TAG_PREFIXKonfiguriertes Tag-Präfix
SEMREL_CHANGELOGErzeugter Changelog-Inhalt
SEMREL_DRY_RUNtrue bei Ausführung mit --dry-run
SEMREL_COMMITSJSON-Array der rohen Commit-Messages im aktuellen Release-Fenster
SEMREL_CONTRIBUTORSJSON-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).

Jedes Plugin sollte beim Start seine Schema-Version ausgeben:

Terminal-Fenster
echo "plugin_schema_version=1" >&2

So weiß semrel, welche Version des Env-Var-Vertrags das Plugin erwartet, und kann künftig Kompatibilitätsprüfungen durchführen.


  1. Erstelle dein Modul

    Terminal-Fenster
    mkdir semrel-plugin-my-provider
    cd semrel-plugin-my-provider
    go mod init github.com/yourorg/semrel-plugin-my-provider
  2. Füge Abhängigkeiten hinzu

    Terminal-Fenster
    go get github.com/SemRels/semrel-plugin-sdk # optional: helpers for env-var reading
  3. Implementiere das Plugin

    Erstelle cmd/plugin/main.go:

    package main
    import (
    "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
    }
  4. 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/plugin
    mkdir -p ~/.semrel/plugins
    cp semrel-plugin-my-provider ~/.semrel/plugins/
  5. Binde es in .semrel.yaml ein

    plugins:
    - uses: my-provider # resolves to semrel-plugin-my-provider
    args:
    token: ${{ env.MY_TOKEN }}
  6. Teste es

    Terminal-Fenster
    semrel release --dry-run

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

semrel selbst ist dafür das empfohlene Tool:

Terminal-Fenster
semrel release

Reiche dein Plugin ein, damit es in der offiziellen semrel-Plugin-Registry gelistet wird:

Terminal-Fenster
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=MIT

Oder besuche registry.semrel.io und klicke auf Submit Plugin.

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.


TypAusgabeExit bei FehlerZweck
AnalyzerJSON nach stdoutJaBestimmt aus Commits die nächste Version
GeneratorNichts (Side Effects)JaErzeugt Release-Artefakte (Changelog usw.)
ProviderNichts (Side Effects)JaVeröffentlicht das Release auf einer Plattform
ConditionNichtsJa (ungleich null)Gate — bricht das Release ab, wenn Bedingungen nicht erfüllt sind
HookNichts (Side Effects)OptionalLifecycle-Callbacks (vor/nach Release)
UpdaterNichts (Side Effects)JaAktualisiert Versions-Strings in Projektdateien
PackagerNichts (Side Effects)JaBaut verteilbare Release-Artefakte
PublisherNichts (Side Effects)JaLädt Artefakte in Registries oder HTTP-Endpunkte hoch