L’objectif de cet article est d’utiliser certaines fonctionnalités de GitLab CI/CD afin de gérer le versioning automatique d’un projet Git.
Problématique
Les différentes releases d’une application prennent généralement la forme suivante : <NOM DE L'APPLICATION> MAJOR.MINOR.HOTFIX
Exemples
Releases Node.js (Node.js 10.5.0, Node.js 10.4.1, Node.js 10.4.0, etc.)
Releases MariaDB (MariaDB 10.3.8, MariaDB 10.2.16, MariaDB 10.1.34, etc.)
Releases Firefox (Firefox 61.0, Firefox 60.0.2, Firefox 59.0.3, etc.)
Et bien d’autres…
En plus d’être pratique, ce genre de convention permet aux développeurs de savoir s’il s’agit :
- d’une petite correction de bug :
HOTFIX
s’incrémente, - d’un ajout de feature ou d’une correction plus importante :
MINOR
s’incrémente etHOTFIX
est remise à zéro, - ou bien d’une mise à jour importante :
MAJOR
s’incrémente etMINOR
etHOTFIX
sont remises à zéro.
Dans le cadre d’une approche DevOps, l’objectif de cet article est de voir comment utiliser les fonctionnalités de GitLab CI/CD pour semi-automatiser l’incrémentation de ces variables.
Voyons tout d’abord ce dont nous allons avoir besoin pour atteindre cet objectif.
Prérequis
Compte GitLab
Si vous n’avez pas encore de compte GitLab, vous pouvez en créer un en cliquant ici et en suivant les instructions.
Projet Git
Après connexion à votre compte GitLab, il y a deux possibilités :
- Soit vous avez d’ores et déjà un projet Git à versionner, et dans ce cas vous pouvez passer directement à la section suivante ;
- Soit vous n’avez pas encore de projet Git à versionner, et dans ce cas nous allons en créer un rapidement.
.gitlab-ci.yml
Si ce n’est pas encore le cas, veuillez intégrer un fichier nommé .gitlab-ci.yml
à la racine de votre projet. Ce fichier peut être ajouté via l’interface GitLab ou à la main.
Vous trouverez toutes les informations nécessaires à propos de ce fichier sur cette page.
Projet de test
Commençons avec un projet de test assez simple. Pour cela, créons deux fichiers texte (file1.txt
et file2.txt
) avec le contenu suivant :
Hello world!
file2
Maintenant, nous devons remplir notre fichier .gitlab-ci.yml
avec les différentes étapes liées à l’intégration et au déploiement continus. Dans un projet basique, il en existe trois :
- la compilation ;
- le testing ;
- et le packaging.
Avec ces informations, nous pouvons compléter notre fichier .gitlab-ci.yml
avec le contenu suivant :
image: alpine:latest
stages:
- compile
- test
- package
compile:
stage: compile
script: cat file1.txt file2.txt > compiled.txt
artifacts:
paths:
- compiled.txt
expire_in: 20 minutes
test:
stage: test
script: cat compiled.txt | grep -q 'Hello world'
package:
stage: package
script:
- "tar -czf package.gz compiled.txt"
artifacts:
paths:
- ./*.gz
Tout d’abord, nous récupérons une image alpine (distribution Linux ultra-légère), la plus récente, pour pouvoir travailler dessus.
Ensuite, nous listons les différentes étapes grâce au mot-clé stages
.
Et enfin vient la partie un peu plus intéressante :
- La compilation consiste à concaténer le contenu des deux fichiers
file1.txt
etfile2.txt
dans un fichiercompiled.txt
; - Le testing consiste tout simplement à vérifier que l’on retrouve bien la chaîne de caractères
Hello world
à l’intérieur du fichiercompiled.txt
; - Et le packaging (
tar
) consiste alors à récupérer ce fichier et à le compresser pour le mettre ensuite à disposition de l’utilisateur.
Options tar
Les options de la commande tar
sont les suivantes :
- L’option
-c
permet de créer une archive ; - L’option
-z
permet de spécifier que la compression se fait avec gzip ; - L’option
-f
permet de spécifier le nom de fichier de l’archive.
A noter que la liste détaillée des fichiers traités peut être affichée avec l’option -v
(ou -vv
pour une affichage encore plus détaillé).
Notre fichier packagé ici ne comporte aucune information quant à sa version actuelle.
Maintenant que ce projet de test est en place, voyons comment gérer l’auto-incrémentation avec GitLab CI/CD.
Auto-incrémentation
Nous allons ici utiliser une fonctionnalité de GitLab CI/CD et définir des variables secrètes.
Variables secrètes
Tout d’abord, nous allons avoir besoin de définir une variable pour chaque valeur de MAJOR.MINOR.HOTFIX
.
Sur l’interface GitLab de votre projet, dans la barre de navigation située à gauche de l’écran, allez dans Settings > CI/CD > Variables.
Cliquez ensuite sur Expand et créez trois nouvelles variables secrètes de la manière suivante :
Cliquez ensuite sur Save variables.
Nous venons de créer trois numéros de build internes à GitLab qui sont initialisés à la valeur zéro.
Maintenant, nous allons avoir besoin d’une quatrième variable secrète nous permettant de manipuler ces numéros.
Token API GitLab
Nous devons définir une nouvelle variable contenant un token pour l’API GitLab.
Pour cela, cliquez sur votre profil en haut à droite de l’interface GitLab > Settings > Access Tokens.
Créez un nouveau token avec un nom (API_ACCESS_TOKEN par exemple), ne lui donnez pas de date d’expiration pour qu’il reste valide pour une durée infinie, et cochez api dans la section Scopes.
Ensuite cliquez sur Create personal access token et vous verrez un nouveau champ apparaître en haut de la page :
Copiez le token affiché sous Your New Personal Access Token et retournez sur l’interface de création de variables secrètes.
Ensuite, créez une nouvelle variable secrète, protégée (Protected) cette fois-ci, avec comme nom API_ACCESS_TOKEN par exemple et comme valeur le token que vous avez copié précédemment.
Puis cliquez sur Save variables.
Vous vous retrouvez avec ceci (en cliquant sur Reveal values) :
Maintenant que nous avons créé toutes les variables nécessaires au versioning, utilisons-les dans le fichier .gitlab-ci.yml
à l’aide de scripts bash.
Script bash
Créons un dossier versioning/
à la racine du projet qui contiendra tout ce qui concerne le versioning.
À l’intérieur de ce dossier, nous allons créer un fichier texte VERSION_FILE de la forme suivante :
## Uncomment what you want to increment in
## MAJOR.MINOR.HOTFIX (and comment other lines)
#MAJOR
#MINOR
HOTFIX
Comme vous pouvez le deviner grâce au commentaire, ce fichier sera à modifier par l’utilisateur lors d’un push sur la branche principale (master
) afin de gérer l’auto-incrémentation. Dans l’exemple ci-dessus, on s’apprête à incrémenter la variable HOTFIX
.
Maintenant, ajoutons un script bash (auto_increment
) qui va s’occuper de l’incrémentation :
VERSION_FILE=$1
CI_PROJECT_URL=$2
API_ACCESS_TOKEN=$3
CI_PROJECT_ID=$4
VERSION=$(grep "^[^# ]" ${VERSION_FILE})
if [ -z "${VERSION}" ]; then
echo "Error: VERSION is empty"
exit 1
elif [ "${VERSION}" != "MAJOR" ] && [ "${VERSION}" != "MINOR" ] && [ "${VERSION}" != "HOTFIX" ]; then
echo "Error: VERSION is not MAJOR, MINOR or HOTFIX"
exit 2
fi
GITLAB_URL=$(echo ${CI_PROJECT_URL} | awk -F "/" '{print $1 "//" $2$3}')
VAR=$(curl -s -f --header "PRIVATE-TOKEN: ${API_ACCESS_TOKEN}" "${GITLAB_URL}/api/v4/projects/${CI_PROJECT_ID}/variables/${VERSION}" | jq -r '.value' )
VAR=$((VAR+1))
curl -s -f --request PUT --header "PRIVATE-TOKEN: ${API_ACCESS_TOKEN}" "${GITLAB_URL}/api/v4/projects/${CI_PROJECT_ID}/variables/${VERSION}" --form "value=${VAR}"
if [ "${VERSION}" == "MAJOR" ]; then
curl -s -f --request PUT --header "PRIVATE-TOKEN: ${API_ACCESS_TOKEN}" "${GITLAB_URL}/api/v4/projects/${CI_PROJECT_ID}/variables/MINOR" --form "value=0"
curl -s -f --request PUT --header "PRIVATE-TOKEN: ${API_ACCESS_TOKEN}" "${GITLAB_URL}/api/v4/projects/${CI_PROJECT_ID}/variables/HOTFIX" --form "value=0"
fi
if [ "${VERSION}" == "MINOR" ]; then
curl -s -f --request PUT --header "PRIVATE-TOKEN: ${API_ACCESS_TOKEN}" "${GITLAB_URL}/api/v4/projects/${CI_PROJECT_ID}/variables/HOTFIX" --form "value=0"
fi
Ce fichier en apparence complexe ne l’est pas tant que ça. Il inclut plusieurs étapes que l’on va détailler ci-dessous.
Étape 1 : lecture des arguments
Le script auto_increment prend 4 arguments :
VERSION_FILE
qui correspond au fichierversioning/VERSION_FILE
où l’on indique la variable à incrémenter ;CI_PROJECT_URL
qui est une variable interne à GitLab qui correspond à l’adresse HTTP du projet (voir GitLab CI/CD Variables) ;API_ACCESS_TOKEN
qui correspond à la variable secrète que l’on a créée permettant de manipuler l’API de GitLab ;CI_PROJECT_ID
qui est une variable interne à GitLab qui correspond à l’unique identifiant du projet courant que GitLab CI utilise en interne (voir GitLab CI/CD Variables).
Étape 2 : Parsing de la version
Après avoir affecté les arguments à des variables explicites, le fichier récupère la ou les lignes qui ne commencent ni par un espace ni par un # du fichier passé en argument lors de l’exécution du script, et inscrit le résultat dans une variable VERSION
.
Ensuite, on vérifie dans un premier temps que cette variable n’est pas nulle et dans un second temps qu’elle correspond bien à l’une des trois propositions du fichier VERSION_FILE
, qui correspondent au nom des variables secrètes créées dans GitLab. Sinon, on renvoie une erreur explicite.
Étape 3 : Incrémentation
Si la variable est bien reconnue, on récupère sa valeur dans VAR
, on l’incrémente, puis on la met à jour dans GitLab grâce à une requête PUT.
Étape 4 : Décrémentation
Enfin, on gère le fait que si la variable en question est MAJOR
, il faut réinitialiser les valeurs de MINOR
et HOTFIX
à zéro. Et de la même manière, si la variable incrémentée est MINOR
, on réinitialise HOTFIX
à zéro.
Maintenant que ceci est en place, rajoutons une nouvelle étape dans le fichier .gitlab-ci.yml
.
.gitlab-ci.yml : étape supplémentaire
Nous allons ajouter une étape auto_increment
dans le fichier .gitlab-ci.yml
. Pour cela, commencez par modifier les stages :
stages:
- compile
- test
- auto_increment
- package
Ensuite, rajoutez une étape auto_increment
:
auto_increment:
stage: auto_increment
before_script:
- apk add --update curl jq
script:
- "chmod +x versioning/auto_increment"
- "./versioning/auto_increment versioning/VERSION_FILE ${CI_PROJECT_URL} ${API_ACCESS_TOKEN} ${CI_PROJECT_ID}"
Dans ce job, nous récupérons tout d’abord le token d’accès à l’API GitLab. Ensuite, avec le mot-clé before_script
, nous nous assurons de pouvoir utiliser les commandes curl
et jq
.
Le script de ce job va d’abord donner le droit d’exécution sur le script auto_increment
avec la commande chmod +x
, et ensuite lancer ce dernier avec les arguments dont il a besoin (voir Étape 1 : lecture des arguments ci-dessus).
Pour vérifier le bon fonctionnement de notre nouvelle fonctionnalité, il ne faut pas oublier de modifier le job de packaging, par exemple de la manière suivante :
package:
stage: package
script:
- "tar -czf packaged-${MAJOR}.${MINOR}.${HOTFIX}.gz compiled.txt"
artifacts:
paths:
- ./*.gz
Ici, MAJOR
, MINOR
et HOTFIX
correspondent au nom des variables secrètes que l’on a créées précédemment.
Il ne reste plus qu’à lancer un nouveau pipeline en poussant sur GitLab une version du fichier VERSION_FILE
modifiée selon nos souhaits.
Pipeline
Pour récupérer notre artifact, il faut aller dans la barre de navigation à gauche sur l’interface GitLab, cliquer sur CI/CD puis sur Pipelines.
Si ce n’est pas fait automatiquement, il faut lancer un nouveau pipeline en cliquant sur le bouton New Pipeline. Et dès que cette pipeline sera terminée, c’est-à-dire dès que le job package
sera validé, nous pourrons cliquer sur ce dernier et télécharger sur la droite de l’écran les artifacts contenant le fichier packagé.
Selon ce que vous aurez renseigné, vous vous retrouverez alors avec un fichier contenant l’information de versioning directement dans son nom. Si par exemple vous avez décommenté la ligne HOTFIX
dans le fichier VERSION_FILE
, alors votre fichier s’appellera packaged-0.0.1.gz
.
Conclusion
Grâce à ce procédé, il est possible d’incrémenter semi-automatiquement (‘semi’ car l’utilisateur doit tout de même renseigner la variable à incrémenter dans un fichier texte) la version de son application lors d’une release.
Il est à noter que cette fonctionnalité a été très demandée par la communauté et GitLab a récemment ajouté une feature qui se rapproche de ce que fait ce workaround.
Cela a été évoqué dans de nombreuses issues dont celle-ci et une nouvelle variable CI_PIPELINE_IID a été créée dans la version 11.0. En quelques mots, cette variable est incrémentée à chaque lancement d’un nouveau pipeline sur un projet spécifique et peut donc faire partie du numéro de version d’une application lors du processus de release.
Ressources
Cet article s’est beaucoup inspiré du workaround suivant à qui l’on doit l’idée d’utiliser des variables secrètes : marcos/CI_PIPELINE_IID.
0 commentaire