Helm-Chart-Publish als geteilten Baustein aufnehmen

Der Workflow kommt aus jlab-cluster/helm-charts, wo er 26 duenne Huellen
bedient. Er laedt ein gepacktes Chart in eine klassische, indexbasierte
Helm-Registry: ein einzelnes HTTP-POST, kein OCI-helm-push.

Zwei Dinge sind beim Umzug anders als in der Vorlage.

Der Eigentuemer ist eine Pflichteingabe registry-owner vom Typ string, ohne
Vorgabe. Bisher wurde er aus github.repository_owner abgeleitet; als Eingabe
wird er im aufrufenden Repository ausgewertet, wo der Wert gemessen ist. Das
folgt der Hausregel, dass ein Eigentuemer-Segment nie geraten wird, und haengt
den Baustein an keine Kontext-Semantik. type: string wie alle Eingaben hier,
siehe #4.

OP_CONNECT_HOST kommt aus einer Variablen des aufrufenden Repositories statt
fest verdrahtet aus dem Baustein — ein geteilter Baustein traegt nicht die
Infrastruktur-Adresse eines einzelnen Mandanten. Ein erster Schritt prueft die
Variable und benennt sie beim Abbruch, statt zwei Schritte spaeter an einer
leeren Adresse zu scheitern.

Alles andere ist unveraendert uebernommen, samt der Kommentare, die es
begruenden: curl --config - statt --user, --fail-with-body, der gebaute
Dateiname mit test -f, die :?-Waechter je Tresor-Feld, die Leerzeichen-Pruefung
an den Zugangsdaten, das Maskieren des Hosts und die drei Formwaechter an
charts-url.

Der workflow_dispatch-Block ist entfallen: Ein Dispatch hier liefe gegen dieses
Repository, in dem kein Chart liegt. Die Huellen des Aufrufers tragen ihn.

ci/helm-dependencies.sh bleibt ein Skript des aufrufenden Repositories; der
Checkout holt dessen Baum, also laeuft es weiter aus dessen Kopie.

Part of jlab-cluster/helm-charts#66
This commit is contained in:
jklein committed 2026-10-01 22:39:17 +00:00
1 parent b82d0a2155
commit 7d0c1b9c22
2 files changed
+380

No files matched your search

+131
View File
@@ -148,6 +148,121 @@ Die eigentlichen Zugänge für Checkout und Registry liegen in 1Password
(`GitHub-Actions/jlab-git-checkout-token`, `GitHub-Actions/jlab-registry-access`)
und müssen in Gitea nicht hinterlegt werden.
### `.gitea/workflows/publish-helm-chart.yml`
Packt ein Helm-Chart und lädt es in eine **klassische, indexbasierte**
Helm-Registry. Das ist kein OCI-`helm push`: Es gibt keine Registry-Sitzung,
sondern ein einzelnes HTTP-`POST` des gepackten `.tgz`, je Anfrage
authentifiziert. Läuft auf `ubuntu-latest`.
Die Ziel-URL wird zusammengesetzt, nicht gespeichert:
```
<charts-url>/<registry-owner>/helm/api/charts
```
`<charts-url>` ist die Basis bis `/api/packages` und liegt in 1Password
(`GitHub-Actions/jlab-registry-access`, Feld `charts-url`), `<registry-owner>`
ist die Pflichteingabe. Damit steht im aufrufenden Repository kein Wert, der auf
die Registry zeigt — nicht einmal ein Pfadsegment —, und ein zweiter Eigentümer
auf derselben Instanz braucht keine zweite Einstellung.
#### Eingaben
| Eingabe | Pflicht | Vorgabe | Bedeutung |
| ---------------- | ------- | ------- | --------- |
| `chart-name` | ja | — | Name des Charts, zugleich der Name seines Verzeichnisses unterhalb von `chart-location` |
| `registry-owner` | ja | — | Eigentümer-Segment der Ziel-URL, also der `<owner>` in `<basis>/<owner>/helm/api/charts` |
| `chart-location` | nein | `.` | Verzeichnis, in dem das Chart-Verzeichnis liegt |
Dass `registry-owner` Pflicht ist und keine Vorgabe hat, folgt derselben
Hausregel wie `image-owner` oben: Ein Eigentümer-Segment wird nie geraten.
Aufrufer übergeben `${{ github.repository_owner }}`; der Wert wird damit im
**aufrufenden** Repository ausgewertet, wo er gemessen ist (`jlab-cluster`, Lauf
282 von `validate-charts.yml`). Dass der Kontext auch in einem von fremd
aufgerufenen Workflow der des Aufrufers bleibt, ist dokumentiert, auf dieser
Gitea-Fassung aber nicht gemessen — und ein Chart, das unter dem falschen
Eigentümer veröffentlicht wird, ist nichts, wofür man sich auf eine
Kontext-Semantik verlassen müsste. Als Eingabe hängt der Baustein an keiner.
Alle Eingaben sind `type: string`, auch dort, wo künftig ein Schalter
hinzukommt: Boolesche `workflow_call`-Eingaben werden auf dieser Gitea-Version
nicht durchgereicht — bei grünem Lauf. Siehe
[Issue #4](https://git.jk-dev.de/workflow-util/pipelines/issues/4) und die
Begründung im Abschnitt zu `push` oben.
#### Ausgaben
| Ausgabe | Bedeutung |
| --------------- | --------- |
| `chart-version` | Die veröffentlichte Chart-Version, gelesen aus `version:` in `Chart.yaml` |
#### Aufrufbeispiel
```yaml
jobs:
publish-outline:
name: Publish Outline Helm Chart
uses: workflow-util/pipelines/.gitea/workflows/publish-helm-chart.yml@v3
with:
chart-name: 'outline'
registry-owner: ${{ github.repository_owner }}
secrets: inherit
```
`secrets: inherit` ist notwendig — der Workflow braucht `OP_CONNECT_TOKEN` aus
dem aufrufenden Repository.
Der Baustein löst sich nicht selbst aus. Wann veröffentlicht wird, entscheidet
die Hülle im aufrufenden Repository über ihr eigenes `on:` — üblicherweise ein
`push` auf `main`, eingeschränkt auf das Chart-Verzeichnis, dazu ein
`workflow_dispatch` für den Fall, dass von Hand nachgeschoben werden muss.
#### Form des Tresor-Felds `charts-url`
Das Feld enthält **nur** die Basis:
```
https://<host>/api/packages # so
https://<host>/api/packages/<owner>/helm/api/charts # nicht so
```
Drei Wächter weisen eine andere Form namentlich zurück: wenn der Wert auf
`/api/charts` endet, wenn er das Segment `/helm` enthält, und wenn er nicht auf
`/api/packages` endet. Der Grund ist die Lesbarkeit des Fehlers — 1Password
maskiert die URL im Protokoll, ein 404 gegen eine maskierte Adresse wäre nicht zu
deuten. Der Eigentümer wird aus demselben Grund geprüft: Ein leerer Wert ergäbe
`<basis>//helm/api/charts`, also wieder einen nackten 404.
#### Voraussetzungen im aufrufenden Repository
| Name | Art | Zweck |
| ------------------------- | ----------------- | ----- |
| `OP_CONNECT_HOST` | Variable | Adresse des 1Password-Connect-Servers im Cluster, etwa `https://op-connect.example.com` |
| `OP_CONNECT_TOKEN` | Secret | Zugang zu diesem Connect-Server, kommt über `secrets: inherit` |
| `ci/helm-dependencies.sh` | Datei im Repository | Ausführbares Skript, das die deklarierten Abhängigkeiten eines Charts nach `charts/` holt |
`OP_CONNECT_HOST` ist bewusst eine Variable des aufrufenden Repositories und
kein fest verdrahteter Wert: Ein geteilter Baustein trägt nicht die
Infrastruktur-Adresse eines einzelnen Mandanten. Der Preis dafür ist eine
Voraussetzung, die man vergessen kann, und eine nicht gesetzte Variable kommt als
leere Zeichenkette an. Deshalb prüft der erste Schritt sie und benennt beim
Abbruch die Einstellung samt Ort — statt zwei Schritte später an einer leeren
Adresse zu scheitern.
`ci/helm-dependencies.sh` ist ein Skript des **aufrufenden** Repositories, und
das bleibt nach dem Umzug hierher so: Der Checkout holt das Repository, zu dem
der Lauf gehört — das des Aufrufers —, also ist `${{ github.workspace }}` dessen
Arbeitsverzeichnis. Der Aufruf steht vor `helm package`, weil `helm package` mit
`found in Chart.yaml, but missing in charts/ directory` abbricht, solange eine
deklarierte Abhängigkeit nicht geholt ist. Für ein Chart ohne `dependencies:`
tut das Skript nichts, vorhanden und ausführbar muss es trotzdem sein; fehlt es,
sagt der Lauf genau das.
Der Registry-Zugang selbst liegt in 1Password
(`GitHub-Actions/jlab-registry-access`: `username`, `password`, `charts-url`) und
muss in Gitea nicht hinterlegt werden.
## Auf einen Tag zeigen, nicht auf `@main`
Aufrufe bitte immer an einen Tag binden:
@@ -169,3 +284,19 @@ bestehende Aufrufe, wird der Major-Anteil erhöht.
Aufrufe, die den Wert als YAML-Boolean übergeben. `v1` bleibt unverändert
stehen; wer umstellt, wechselt auf `@v2` und schreibt `push: 'true'` bzw.
`push: 'false'`.
### Die Nummer bezeichnet den Zustand des Repositories
Tags gelten hier **repository-weit**, nicht je Datei. `v3` ist der Stand, ab dem
es `publish-helm-chart.yml` gibt; unter `v1` und `v2` existiert die Datei nicht,
ein Aufruf auf `@v2` findet sie also nicht.
Das hat eine Folge, die man kennen muss, weil sie sonst als Fehler gelesen wird:
Wer künftig `docker-build-push.yml` ändert, erhöht auf `v4` — und ein Aufruf von
`publish-helm-chart.yml@v3` bleibt gültig und richtig, obwohl sich an dieser
Datei nichts geändert hat. Die Nummer ist keine Dateiversion. Umgekehrt zwingt
eine brechende Änderung an einem Baustein die Aufrufer der anderen zu nichts:
Sie bleiben auf ihrem Tag stehen, bis sie bewusst nachziehen.
`v3` selbst ist additiv. Der neue Baustein ändert an `docker-build-push.yml`
nichts, bestehende Aufrufer auf `@v2` bleiben unberührt.