Spaß mit Gitlab, Tags und Releases

Eine Entwicklungsrichtlinie 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 eingefroren 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. Andernfalls 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 
 7   PRIVATE-TOKEN:$GITLAB_API_TOKEN -L $TAGS_URL_BASE/$VERSION\""
 8- "if [[ `$CHECK_TAG_EXISTS_COMMAND` ]]; then exit 1; fi"
 9
10after_script:
11- "curl -f --header \"PRIVATE-TOKEN: $GITLAB_API_TOKEN\" --request POST
12   \"$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.