Andrew Hanna

Andrew Hanna

2GP CI/CD: Unlocked- und Managed-Package-Builds automatisieren

2GP CI/CD: Unlocked- und Managed-Package-Builds automatisieren

Kurze Antwort: Eine 2GP CI/CD-Pipeline erzeugt bei jedem Merge eine Paketversion, installiert diese Version in eine frische Scratch Org, lässt die Tests dagegen laufen und promotet nur, was besteht. Die Pipeline selbst sind fünf Befehle. Was 2GP-Builds Monate später wirklich bricht, ist nicht die Pipeline, sondern die Ancestry- und Namespace-Entscheidungen aus Woche eins.

Was macht eine 2GP CI/CD-Pipeline eigentlich?

Fünf Stufen, in dieser Reihenfolge:

  1. Quellcode validieren. Statische Analyse und Linting am Pull Request, bevor etwas gebaut wird.
  2. Paketversion bauen. Eine Beta-Version, erzeugt aus dem Quellcode und nicht aus einer Org.
  3. Sauber installieren. Eine frische Scratch Org beweist, dass sich das Paket installieren lässt, und das ist eine andere Aussage als "der Code deployt".
  4. Gegen das installierte Paket testen. Code mit Namespace verhält sich nach dem Paketieren anders, Tests laufen also nach der Installation.
  5. Promoten, was besteht. Die Promotion ist das Tor und der einzige Schritt, der schwer auslösbar sein sollte.

Der entscheidende Unterschied: Metadaten zu deployen beweist, dass sie in einer Org kompilieren, die Ihnen gehört. Eine Paketversion zu installieren beweist, dass sie in einer Org funktioniert, die Ihnen nicht gehört.

Was unterscheidet Unlocked und Managed 2GP?

  • Unlocked Packages sind für den eigenen oder den Org-Bestand eines Kunden. Kein Namespace nötig, keine Ancestry, keine Security Review. Versionen sind billig und ersetzbar.
  • Managed 2GP ist für die Distribution: registrierter Namespace, Schutz des geistigen Eigentums, Ancestry, Upgradepfade für Subscriber und AppExchange Security Review.

Die Form der Pipeline ist identisch. Die Folgen einer falschen Promotion nicht: eine bereute Unlocked-Version ersetzt man, eine promotete Managed-Version ist dauerhaft öffentliche API.

Wie bauen Sie die Pipeline Schritt für Schritt?

  1. Dev Hub nicht-interaktiv authentifizieren. Ein JWT-Bearer-Flow mit Zertifikat im Secret Store Ihrer CI. Der Dev Hub muss die Org sein, der der Namespace gehört, sonst scheitert die Versionserstellung sofort.
  2. Version erzeugen: sf package version create --package MyPackage --code-coverage --installation-key-bypass --wait 60. Die entstehende 04t-Id als Pipeline-Output sichern.
  3. Scratch Org starten: sf org create scratch --definition-file config/project-scratch-def.json --duration-days 1 --wait 10.
  4. Installieren und testen: sf package install --package 04tXXXX --wait 20, danach sf apex run test --test-level RunLocalTests --code-coverage --wait 30.
  5. Promoten, nur auf dem Release-Branch: sf package version promote --package [email protected].

Alles vor Schritt 5 läuft bei jedem Pull Request. Schritt 5 läuft auf genau einem Branch, hinter einer menschlichen Freigabe.

Wie bekommen Sie Ancestry und Namespace richtig hin?

Ancestry

Ancestry betrifft nur Managed 2GP, und genau dort laufen automatisierte Pipelines still aus dem Ruder. Salesforce verlangt, dass der angegebene Vorgänger die höchste promotete Versionsnummer des Pakets ist, und nur zu managed-released promotete Versionen dürfen als Vorgänger gelten (Salesforce Developers). Drei Regeln für Ihre Pipeline:

  • Nutzen Sie das Schlüsselwort. "ancestorVersion": "HIGHEST" in sfdx-project.json setzt den Vorgänger automatisch auf die höchste promotete Version, genau was CI braucht. Alternativen sind ein explizites major.minor.patch oder eine ancestorId.
  • Promoten Sie nie einen halb grünen Build. Eine promotete Version wird zum nächsten Vorgänger. Wer Rauschen promotet, vererbt Rauschen an die Linie.
  • Kennen Sie den Preis des Linienbruchs. Mit --skip-ancestor-check lässt sich die lineare Versionierung brechen, aber Pakete aktualisieren nur entlang der Ancestry-Linie: Subscriber auf einer aufgegebenen Version verlieren ihren Upgradepfad.

Patch-Versionen haben eine eigene Regel: Ein Patch kann nicht direkter Vorgänger einer Nicht-Patch-Version sein.

Namespace

  • Verknüpfen Sie den Namespace mit dem Dev Hub, an dem sich Ihre CI anmeldet. Diese eine Abweichung ist der häufigste Fehlschlag beim ersten Lauf.
  • 2GP erlaubt mehrere Pakete in einem Namespace. Trennen Sie nach Package Directory in sfdx-project.json und deklarieren Sie Abhängigkeiten zwischen Paketen explizit, mit Versionen.
  • Sie kommen von 1GP? Salesforce hat Package Migrations mit Summer '25 allgemein verfügbar gemacht: Konvertierung eines 1GP-Pakets nach 2GP mit sf package convert samt Migration installierter Subscriber.

Wie bleibt eine 2GP-Pipeline schnell?

  • Poolen Sie Ihre Scratch Orgs. Meist ist die Org-Erstellung langsamer als der Paketbau. Vorgewärmte Orgs nehmen sie aus dem kritischen Pfad.
  • Testumfang je Stufe. Relevante Tests am Pull Request, RunLocalTests vor der Promotion.
  • Version cachen. Hat sich die Quelle nicht geändert, bauen Sie das Paket nicht neu.

All das lässt sich aus Salesforce CLI plus GitHub Actions, Azure Pipelines oder CumulusCI zusammensetzen. Serpent liefert dieselbe Pipeline ohne YAML: native 1GP-, 2GP- und Managed-Package-Workflows, Auflösung paketübergreifender Abhängigkeiten und Versionsverwaltung über Subscriber-Orgs in jedem Plan, mit vorgewärmtem Scratch-Org-Pooling in Scale. Weitere Build- und Release-Guides finden Sie in den SF Guides.

FAQ

Lässt sich die 2GP-Paketerstellung vollständig automatisieren?

Ja. Versionserstellung, Installation, Tests und Promotion sind CLI-Befehle, der ganze Zyklus läuft unbeaufsichtigt. Lassen Sie die Promotion trotzdem hinter einer menschlichen Freigabe.

Was ist Package Ancestry in 2GP?

Die deklarierte Abstammung zwischen Managed-Paketversionen. Sie definiert den Upgradepfad der Subscriber, denn Pakete aktualisieren nur entlang dieser Linie.

Brauchen Unlocked Packages einen Namespace?

Nein. Sie kommen ohne aus, deshalb passen sie zu internen Org-Beständen. Managed 2GP verlangt einen registrierten, mit dem Dev Hub verknüpften Namespace.

Warum scheitert meine Versionserstellung an der Ancestry?

Meist weil der genannte Vorgänger keine promotete, managed-released Version ist, oder weil eine Patch-Version als Vorgänger einer Nicht-Patch-Version gesetzt wurde.

Soll die CI jeden grünen Build promoten?

Nein. Promotion ist praktisch unumkehrbar und setzt den nächsten Vorgänger, gehört also auf einen Release-Branch hinter eine Freigabe, nicht in jeden Merge.

Ähnliche Artikel

Neugierig auf schnelleres Shipping, bevor Sie einsteigen? Sprechen wir

Unverbindlich.