Asset Pipeline Hooks
Die Asset-Pipeline laeuft nach dem Build-Schritt und vor dem Upload in den GitHub Release. Plugins koennen jede Stufe über sechs Hooks abfangen, die die interne Struktur der Pipeline spiegeln.
Pipeline-Stufen
Abschnitt betitelt „Pipeline-Stufen“releaseAssets config → Glob-Matching → ResolvedAsset[] → [resolveAssets] : Asset-Liste filtern, ergaenzen oder ersetzen → [transformAsset] : jedes Asset signieren, strippen oder aufteilen (1 → N) → [compressAsset] : die Standard-Komprimierung tar.gz / zip ersetzen → [nameAsset] : die Name-Vorlage mit dynamischer Logik überschreiben → sha256 hash → [generateChecksums] : Prüfsummen-Dateien an die Asset-Liste anhängen → GitHub-Release-Upload (integriert) → [uploadAssets] : an zusätzliche Ziele hochladen (S3, R2, CDN usw.) → ReleaseContext zusammengebaut → [afterRelease] : finale Asset-Liste konsumieren (brew, notify usw.)Hooks-Schnittstelle
Abschnitt betitelt „Hooks-Schnittstelle“interface AssetPipelineHooks { resolveAssets?( resolved: ResolvedAsset[], ctx: PubmContext, ): Promise<ResolvedAsset[]> | ResolvedAsset[];
transformAsset?( asset: ResolvedAsset, ctx: PubmContext, ): Promise<TransformedAsset | TransformedAsset[]> | TransformedAsset | TransformedAsset[];
compressAsset?( asset: TransformedAsset, ctx: PubmContext, ): Promise<CompressedAsset> | CompressedAsset;
nameAsset?( asset: CompressedAsset, ctx: PubmContext, ): string;
generateChecksums?( assets: PreparedAsset[], ctx: PubmContext, ): Promise<PreparedAsset[]> | PreparedAsset[];
uploadAssets?( assets: PreparedAsset[], ctx: PubmContext, ): Promise<UploadedAsset[]> | UploadedAsset[];}Alle Hooks werden zu PluginHooks hinzugefuegt und über das normale plugins-Array in pubm.config.ts registriert.
Hook-Referenz
Abschnitt betitelt „Hook-Referenz“resolveAssets
Abschnitt betitelt „resolveAssets“Wird einmal mit der vollständigen Liste der per Glob gefundenen Assets aufgerufen. Verwende diesen Hook, um Assets zu filtern, programmgesteuert gefundene Dateien hinzuzufuegen oder Metadaten anzuhängen.
Input: ResolvedAsset[] - Assets aus dem Glob-Matching mit geparsten Plattforminformationen
Output: ResolvedAsset[] - die neue Asset-Liste (ersetzt die vorherige Liste)
const filterPlugin: PubmPlugin = { name: "filter-assets", hooks: { resolveAssets(resolved, ctx) { // Nur Assets für unterstützte Plattformen aufnehmen return resolved.filter( (a) => (a.platform.os === "darwin" || a.platform.os === "linux") && a.platform.arch === "arm64", ); }, },};transformAsset
Abschnitt betitelt „transformAsset“Wird vor der Komprimierung einmal pro Asset aufgerufen. Verwende diesen Hook, um Binaries zu signieren, strip auszufuehren, Nebendateien in ein Archiv aufzunehmen oder ein Eingabe-Asset in mehrere Ausgaben aufzuteilen.
Input: ResolvedAsset - ein Asset
Output: TransformedAsset | TransformedAsset[] - ein oder mehrere transformierte Assets
TransformedAsset erweitert ResolvedAsset um das optionale Feld extraFiles?: string[]. Dateien aus extraFiles werden während der Komprimierung zusammen mit der Hauptdatei ins Archiv gepackt.
const codeSignPlugin: PubmPlugin = { name: "code-sign", hooks: { async transformAsset(asset, ctx) { if (asset.platform.os === "darwin") { await exec("codesign", [ "--sign", process.env.SIGNING_IDENTITY, "--options", "runtime", asset.filePath, ]); } return asset; }, },};Ein Asset in mehrere Ausgaben aufteilen
Abschnitt betitelt „Ein Asset in mehrere Ausgaben aufteilen“Gib ein Array zurück, um aus einem Eingang mehrere Assets zu erzeugen. Jedes Element durchlaeuft den Rest der Pipeline unabhängig.
hooks: { async transformAsset(asset, ctx) { if (asset.platform.os === "windows") { // Sowohl ein normales Binary als auch ein Debug-Build erzeugen return [ asset, { ...asset, filePath: asset.filePath.replace(".exe", "-debug.exe") }, ]; } return asset; },},compressAsset
Abschnitt betitelt „compressAsset“Ersetzt die eingebaute Komprimierungslogik vollständig. Wenn gesetzt, ist der Hook dafür verantwortlich, ein CompressedAsset mit dem richtigen filePath und compressFormat zu erzeugen.
Input: TransformedAsset
Output: CompressedAsset
Verwende das, wenn du ein Format brauchst, das pubm nicht nativ unterstützt, oder wenn du zusätzliche Dateien in das Archiv packen willst.
const customArchivePlugin: PubmPlugin = { name: "deb-package", hooks: { async compressAsset(asset, ctx) { if (asset.platform.os === "linux") { const debPath = await buildDebPackage(asset.filePath, ctx.version); return { ...asset, filePath: debPath, originalPath: asset.filePath, compressFormat: false, }; } // Für andere Plattformen auf den Standard zurückfallen return defaultCompress(asset); }, },};nameAsset
Abschnitt betitelt „nameAsset“Gibt den finalen Upload-Dateinamen zurück, ohne Erweiterung. Die Erweiterung wird aus compressFormat angehaengt. Verwende diesen Hook, wenn das Name-Vorlagensystem nicht ausdrucksstark genug ist.
Input: CompressedAsset
Output: string - der Dateiname ohne Erweiterung
const dateStampPlugin: PubmPlugin = { name: "date-stamp", hooks: { nameAsset(asset, ctx) { const date = new Date().toISOString().slice(0, 10).replace(/-/g, ""); return `${ctx.packageName}-${ctx.version}-${date}-${asset.platform.raw}`; }, },};generateChecksums
Abschnitt betitelt „generateChecksums“Wird mit der vollständigen Liste vorbereiteter Assets aufgerufen. Verwende diesen Hook, um eine Prüfsummen-Manifestdatei anzuhaengen.
Input: PreparedAsset[] - alle Assets inklusive ihrer sha256-Werte
Output: PreparedAsset[] - urspruengliche Assets plus zusätzliche Prüfsummen-Dateien
import { writeFileSync } from "node:fs";import { join } from "node:path";
const checksumsPlugin: PubmPlugin = { name: "checksums", hooks: { async generateChecksums(assets, ctx) { const lines = assets .map((a) => `${a.sha256} ${a.name}`) .join("\n");
const checksumPath = join(ctx.runtime.tempDir, "SHA256SUMS.txt"); writeFileSync(checksumPath, lines + "\n");
const sha256 = await computeSha256(checksumPath);
return [ ...assets, { filePath: checksumPath, originalPath: checksumPath, name: "SHA256SUMS.txt", sha256, platform: { raw: "" }, compressFormat: false, config: { path: "", compress: false, name: "SHA256SUMS.txt" }, }, ]; }, },};uploadAssets
Abschnitt betitelt „uploadAssets“Wird nach dem Upload in den GitHub Release mit derselben PreparedAsset[]-Liste aufgerufen. Verwende diesen Hook, um Artefakte an weitere Ziele zu spiegeln. Die Ergebnisse jedes Plugins werden gesammelt und zusammengefuehrt - alle Plugins erhalten dieselbe Eingabeliste.
Input: PreparedAsset[]
Output: UploadedAsset[] - hochgeladene Assets mit den Feldern url und target
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";import { readFileSync } from "node:fs";
const s3Plugin: PubmPlugin = { name: "s3-mirror", hooks: { async uploadAssets(assets, ctx) { const s3 = new S3Client({ region: "us-east-1" }); const bucket = process.env.RELEASE_BUCKET;
return Promise.all( assets.map(async (asset) => { const key = `releases/${ctx.version}/${asset.name}`; await s3.send( new PutObjectCommand({ Bucket: bucket, Key: key, Body: readFileSync(asset.filePath), }), ); return { ...asset, url: `https://${bucket}.s3.amazonaws.com/${key}`, target: "s3", }; }), ); }, },};Multi-Plugin-Komposition
Abschnitt betitelt „Multi-Plugin-Komposition“Wenn mehrere Plugins denselben Hook registrieren, werden sie in Registrierungsreihenfolge zusammengesetzt:
| Hook | Zusammensetzungsregel |
|---|---|
resolveAssets | Kette - die Ausgabe von Plugin N ist der Input von Plugin N+1 |
transformAsset | Kette - die Ausgabe von Plugin N ist der Input von Plugin N+1 |
compressAsset | Kette - die Ausgabe von Plugin N ist der Input von Plugin N+1 |
nameAsset | Letzter gewinnt - jedes Plugin erhält dieselben (asset, ctx)-Argumente; der Rueckgabewert des zuletzt registrierten Plugins wird verwendet |
generateChecksums | Kette - die Ausgabe von Plugin N ist der Input von Plugin N+1 |
uploadAssets | Additiv - jedes Plugin erhält die urspruengliche PreparedAsset[]-Liste unabhängig; alle Ergebnisse werden zusammengefuehrt |
Jeder nicht abgefangene Fehler in einer Hook-Kette bricht die Pipeline ab und leitet an den onError-Hook weiter.
Vollstaendiges Beispiel: Code-Signing + Prüfsummen + S3
Abschnitt betitelt „Vollstaendiges Beispiel: Code-Signing + Prüfsummen + S3“import { defineConfig } from "@pubm/core";
export default defineConfig({ releaseAssets: ["platforms/*/bin/mytool"],
plugins: [ // macOS-Binaries signieren { name: "code-sign", hooks: { async transformAsset(asset, ctx) { if (asset.platform.os === "darwin") { await exec("codesign", ["--sign", process.env.SIGNING_IDENTITY, asset.filePath]); } return asset; }, }, },
// SHA256SUMS.txt anhängen checksumsPlugin,
// Nach S3 spiegeln s3Plugin, ],});Verwandte Doku
Abschnitt betitelt „Verwandte Doku“- Release Assets - deklarative Konfigurationsreferenz
- Platform Detection - OS- und Architektur-Tabellen
- Plugins API Reference - vollständige Plugin-Schnittstelle