Spaß mit Gitlab, Tags und Releases

Eine Entwicklunsrichtlinie in meiner Firma verlangt, dass man nach dem offiziellen Release einer Komponente unter deren Version keinen weiteren Check-in mehr machen darf.

Und ich durfte das umsetzen … und zwar mit Gitlab CI-YAMLs, GIT Tags und Shellscripts unter [Linux].
Was für ein Spaß … W-T-F …


Da uns GIT keine stabile Versionierung nach dem MAJOR.MINOR.PATCH Schema bereitstellt, mussten wir tricksen. In den .gitlab-ci.yml Dateien wo die Build-Jobs definiert sind, wird eine “globale” Versions-Variable geführt, die bei Änderungen inkrementell hochgezählt werden muss.

Während der aktiven Entwicklung ist das eigentlich egal, doch wenn ein Feature fertig gestellt und getestet ist, soll eine eigene Release-Stage dafür sorgen, dass das Ergebnis in ein Release-Repository hochgeladen wird, woraus dann die produktiven Installationen generiert werden.

Mit dem “Release” soll die Software-Version eingefrohren werden und es darf mit eben dieser “Version” keinen weiteren Check-In mehr geben.

Das Konzept sieht vor, dass beim Release in GIT ein Tag angelegt wird, das der Version gleicht. Parallel darf kein Build-Job Code mit einer Version bauen, für die es schon ein solches Release-Tag gibt.

Aber wie setzt man das “billig” um? Denn dort wo ich dieses Schema einsetzen sollte, sind komplexe Scriptabhängigkeiten eher störend.

Meine Lösung sieht daher wie folgt aus:

Im Gitlab-CI Job wird per before-script vor der Ausführung der Build-Stage das gute alte Tool curl aufgerufen, um den GitLab Server zu fragen, ob ein Tag mit der aktuellen Version schon existiert. Fall ja (curl Exitcode == 0) ist das ein Fehler und wir brechen ab. Anderfalls darf der Build durchlaufen.

Beim Durchlauf der Release-Stage kommt ebenso wieder curl zum Einsatz, welches die aktuelle Version per REST POST den aktuellen Commit mit einem GIT-Tag verknüpft.

Das sieht dann etwa so aus:

 1variables:
 2- GITLAB_API_TOKEN: "my-secret-access-token"
 3- VERSION: "1.2.3"
 4- TAGS_URL_BASE: "$CI_API_V4_URL/projects/$CI_PROJECT_ID/repository/tags"
 5before_script: 
 6- "export CHECK_TAG_EXISTS_COMMAND=\"curl -f --header PRIVATE-TOKEN:$GITLAB_API_TOKEN -L $TAGS_URL_BASE/$VERSION\""
 7- "if [[ `$CHECK_TAG_EXISTS_COMMAND` ]]; then exit 1; fi"
 8
 9after_script:
10- "curl -f --header \"PRIVATE-TOKEN: $GITLAB_API_TOKEN\" --request POST \"$TAGS_URL_BASE?tag_name=$VERSION&ref=$CI_COMMIT_SHA&message=$VERSION\""

Fazit

Ach wie tief bin ich gesunken …
Wenn mich als Entwickler etwas überhaupt nicht interessiert, dann sind das solche organisatorischen Quick-and-Dirty Ekelskriptereien … aber was soll man machen.

Es ist ein schlechter Trost, dass ich sagen kann:

Egal wo ich bisher gearbeitet habe, die anderen haben noch schlechtere Workarounds fabriziert.

Aber genau das ist das Problem von “Scripting”. Jeder macht irgendetwas irgendwie. Möglichst schnell und scheinbar einfach … und dann hat man Gigabytes an Ansammlungen von solchen Codes, die keiner mehr richtig nachvollziehen kann.

However, zumindest weiß ich wieder ein bisschen mehr über Gitlab-YAMLs Bescheid.


Wenn sich eine triviale Erkenntnis mit Dummheit in der Interpretation paart, dann gibt es in der Regel Kollateralschäden in der Anwendung.
frei zitiert nach A. Van der Bellen
... also dann paaren wir mal eine komplexe Erkenntnis mit Klugheit in der Interpretation!