Déploiement sémantique avec Gitlab CI et To-Be-Continuous
Automatisez entièrement votre flux de travail de versionnage sémantique avec GitLab CI, semantic-release et to-be-continuous. Fini les erreurs humaines dans le versionnage, fini les modifications manuelles : gain de temps et d’énergie assurés.
Introduction à la libération sémantique
Imaginons que vous soyez ingénieur logiciel, ingénieur plateforme ou tout simplement un professionnel de l'informatique. Vous suivez les modifications apportées à vos créations (applications web/mobiles, fichiers Docker, manifestes Kubernetes, scripts, documentation, etc.) via des plateformes de gestion de versions comme GitLab et travaillez en équipe ou peut-être seul.
Vous avez adopté Versionnage sémantique mais vous pensez encore à la prochaine version que vous allez publier à chaque fois et vous effectuez des mises à jour manuelles de version, ce qui demande du temps et des efforts supplémentaires.
Pour résoudre ce problème, dites bonjour à libération sémantiqueSemantic-release déterminera automatiquement le numéro de version de votre prochaine publication, mettra à jour les fichiers de version dans vos sources, créera/mettra à jour un fichier de journal des modifications contenant les types de modifications (correction de bug, fonctionnalité, changement incompatible) et les commits associés, créera et publiera des versions avec leurs notes de version et ressources associées.


Tout cela est possible car semantic-release analyse vos commits. Ils doivent donc être formatés d'une manière spécifique. Conventions des messages de commit Angular est utilisé par défaut par semantic-release et est très similaire à Engagement conventionnel que vous pourriez également utiliser.
Ensuite, je vais vous montrer une façon simple de mettre en œuvre libération sémantique avec Gitlab CI et l'open source à venir projet, qui contient des modèles et des composants Gitlab CI pour faciliter la création de pipelines.
Le projet d'exemple
Imaginons que je travaille sur le packaging et la distribution des manifestes Kubernetes pour ma toute nouvelle application open source.
J'utilise Helm pour créer les paquets et Gitlab pour le versionnage des sources et également comme registre OCI pour la distribution des paquets.
J'ai créé le dépôt GitLab et les fichiers sources Helm nécessaires pour empaqueter et distribuer les manifestes Kubernetes. Voici le contenu du dépôt à cette étape :
.
├── Chart.yaml
├── templates
│ ├── deployment.yaml
│ ├── _helpers.tpl
│ ├── hpa.yaml
│ ├── httproute.yaml
│ ├── ingress.yaml
│ ├── NOTES.txt
│ ├── serviceaccount.yaml
│ ├── service.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
Nous allons implémenter la publication sémantique sur ce projet.
Configuration Gitlab CI
Je souhaite maintenant utiliser la fonctionnalité d'intégration continue (CI) de GitLab pour implémenter la publication sémantique et automatiser le linting, la création de packages et la publication de mon graphique Helm lors de chaque modification du dépôt. Pour cela, je dois créer un fichier de configuration « .gitlab-ci.yml » avec le contenu suivant :
include:
- component: $CI_SERVER_FQDN/to-be-continuous/semantic-release/gitlab-ci-semrel@4.1
inputs:
# Make semantic-release job runs automatically, manual by default
auto-release-enabled: true
- component: $CI_SERVER_FQDN/to-be-continuous/helm/gitlab-ci-helm@9.4
inputs:
# Do not add any Helm repos
repos: ""
# Enable Charts linting
lint-disabled: false
# Run the helm-publish job only on tags pipelines
publish-on: tag
# Make the helm-package job runs only on tags pipelines
helm-package:
rules:
- if: $CI_COMMIT_TAG
# Make the helm-lint job runs only on default
# branches and Merge Requests pipelines
helm-lint:
rules:
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
Nous utilisons deux composants Gitlab CI issus de l'open source à venir projet:
- gitlab-ci-semrel - implémenter la libération sémantique
- gitlab-ci-helm - pour analyser, empaqueter et publier le graphique Helm
Si les commits de vos demandes de fusion ne sont pas transférés après la fusion, vous pouvez activer l'option « Fast Forward » pour les demandes de fusion dans GitLab (Paramètres > Demandes de fusion > Paramètres de transfert rapide des commits). Cela ajoutera l'historique des commits de votre demande de fusion à la branche cible après la fusion, au lieu de créer un nouveau commit global « Fusionner la branche… dans la branche principale ». Ainsi, semantic-release aura accès à vos commits habituels après la fusion et pourra mettre à jour les versions conformément à votre configuration.
Configuration de la version sémantique
J'utilise également un fichier de configuration '.releaserc.yml' qui sera utilisé par le composant semantic-release (gitlab-ci-semrel), pour configurer semantic-release. Voici le contenu de ce fichier :
# Run the semantic-release job only on these branches
branches:
- main
- master
plugins:
# Analyzes commit messages to determine the next version number.
# https://github.com/semantic-release/commit-analyzer
- '@semantic-release/commit-analyzer'
# Generates release notes from commit messages.
# https://github.com/semantic-release/release-notes-generator
- '@semantic-release/release-notes-generator'
# Creates or updates a changelog file.
# https://github.com/semantic-release/changelog
- '@semantic-release/changelog'
# Executes a shell command to update the Helm chart version.
# This requires `yq` to be installed in the CI environment.
# The to-be-continuous/semantic-release component we are using includes it.
# https://github.com/semantic-release/exec
- - '@semantic-release/exec'
- prepareCmd: 'yq e ''.version = "${nextRelease.version}"'' -i Chart.yaml && yq e ''.appVersion = "${nextRelease.version}"'' -i Chart.yaml'
# Commits release assets to the Git repository.
# https://github.com/semantic-release/git
- - '@semantic-release/git'
- assets:
- CHANGELOG.md
- Chart.yaml
message: "chore(release): ${nextRelease.version} [skip ci on prod]\n\n${nextRelease.notes}"
# Publishes a GitLab release.
# https://github.com/semantic-release/gitlab
- '@semantic-release/gitlab'
# Set the Git tags format to 1.0.0 instead of v1.0.0
tagFormat: "${version}"
Le travail de libération sémantique de la gitlab-ci-semrel Le composant recherchera un .releaserc.{json,yaml,etc} dans le dépôt. Si le fichier de configuration est trouvé, il est utilisé.
Sinon, la configuration sera générée à la volée par la tâche de publication sémantique à l'aide des paramètres de configuration disponibles sous forme de entrées du système gitlab-ci-semrel composant.
Voici d'autres liens utiles qui peuvent vous aider à configurer le comportement de semantic-release via le fichier de configuration '.releaserc' :
-
Exemple de page de plugin Git Vous trouverez ici des informations sur les paramètres (ressources et messages, par exemple) utilisés pour personnaliser le comportement du plugin Git (@semantic-release/git).
Octroi des autorisations d'écriture au dépôt semantic-release
Dernière chose… Il faut accorder à la tâche de publication sémantique les autorisations de lecture, de création et de mise à jour des fichiers dans le dépôt GitLab. Elle doit également pouvoir effectuer des commits et créer des tags. Pour cela, il est nécessaire de lui fournir un jeton d'accès en définissant la variable d'environnement « GITLAB_TOKEN ».
Voici trois façons de générer une valeur pour la variable « GITLAB_TOKEN » :
-
jeton d'accès au projet GitLab - limité à un projet spécifique
-
jeton d'accès au groupe GitLab - limité à un groupe pour donner accès à tous les projets de ce groupe
-
jeton d'accès personnel GitLab - rattaché à un utilisateur plutôt qu'à un groupe ou à un projet
Voici les autorisations que vous devez accorder au jeton d'accès :
api- accorde un accès en lecture et en écriture à l'APIread_repository- accorde un accès en lecture au dépôtwrite_repository- accorde un accès en écriture au dépôt
Une fois le jeton d'accès généré avec les autorisations requises, ajoutez la variable « GITLAB_TOKEN » en tant que variable Gitlab CI/CD dans « Paramètres -> CI/CD -> Variables ».
Les avantages de cette configuration
Permettez-moi maintenant d'expliquer les avantages de cette configuration pour mon flux de travail de packaging et de distribution Helm Chart.
Je n'ai plus à me soucier de la version à définir pour le graphique après une modification. Le processus de mise à jour de la version du graphique et de publication de cette nouvelle version en tant qu'artefact OCI est entièrement automatisé.
Dans les cas où une mise à jour de version est nécessaire, la tâche de publication sémantique mettra à jour les fichiers de version requis dans le dépôt et créera des étiquettes Git associées et des versions nommées avec cette nouvelle version.
S'il n'y a pas d'étiquettes Git dans le dépôt, le premier numéro de version créé par semantic-release sera 1.0.0. S'il existe déjà des étiquettes, c'est le numéro de version de la dernière étiquette existante qui sera incrémenté.
Voici des exemples de tags et de versions Gitlab associées, créées par la tâche semantic-release :

Voici un aperçu du contenu d'une publication :

Le seul effort qu'il me reste à faire est de bien configurer mes messages de commit en fonction du type de modification que j'effectue (versioning sémantique (majeure, mineure ou corrective) dans le dépôt. Je devrais préfixer mes messages de commit par :
-
fix:— Pour les correctifs (bugs, sécurité, etc.) : le comportement actuel du graphique reste inchangé. La version « patch » du graphique sera incrémentée par semantic-release. -
feat:Lors de l'ajout de nouvelles fonctionnalités : le comportement actuel du graphique est modifié. La version mineure du graphique sera alors incrémentée par semantic-release. L'ajout d'un point d'exclamation (par exemple, « feat ! ») ou la création d'un commit dont le pied de page inclut « CHANGEMENT IMPORTANT » entraînera l'incrémentation de la version majeure du graphique par semantic-release. -
chore:, doc:, ci:— pour les modifications qui ne doivent pas déclencher de mise à jour de version. Cela empêchera « semanctic-release » de mettre à jour la version.
Cette convention de commit est appelée Engagements conventionnels.
Flux de travail final
Voici un aperçu du flux de travail complet de packaging et de distribution des graphiques.
1 - J'apporte des modifications au dépôt dans une nouvelle branche. Je veille à ce que mes commits respectent les règles. Engagements conventionnels.
2 - Je crée une demande de fusion pour intégrer les modifications à la branche principale. Un pipeline GitLab CI exécute la tâche « helm-lint ». La demande de fusion est ensuite examinée.

3 - Une fois la demande de fusion approuvée, je procède à la fusion. Un pipeline Gitlab CI exécute la tâche « helm-lint » suivie de la tâche « semantic-release » sur la branche « main ».

La tâche « semantic-release » analyse les commits et met à jour les versions sémantiques du graphique dans le fichier « Chart.yaml » en conséquence :
-
Une mise à jour de version « patch » est effectuée uniquement si elle détecte des commits commençant par « fix ».
-
Une mise à jour de version « mineure » est effectuée si elle détecte au moins un commit commençant par « feat » et aucun commit commençant par « feat! » ou contenant un pied de page avec « CHANGEMENT IMPORTANT ».
-
Une mise à jour de version « majeure » est effectuée si elle détecte au moins un commit commençant par « feat! » ou contenant un pied de page avec « CHANGEMENT IMPORTANT ».

4 - La tâche de publication sémantique crée ou met à jour un fichier 'CHANGELOG.md' contenant les types de modifications (corrections de bogues, etc.) et des liens vers les commits associés.

5 - La tâche de publication sémantique crée un nouveau commit dans la branche principale, contenant ses modifications sur « CHANGELOG.md » et « Chart.yml ». Le corps de ce commit contient une note de version ajoutée au corps du message de commit.

Le titre du message de commit inclut '[skip ci on prod]' pour garantir que le commit créé par la tâche semantic-release dans la branche principale ne crée pas un nouveau pipeline de branche Gitlab CI, mais ne crée un pipeline qu'après la création d'une étiquette.
6 - La tâche de publication sémantique crée une étiquette portant le nouveau numéro de version uniquement lors de l'application d'un correctif, d'une mise à jour mineure ou majeure. La création de cette étiquette déclenche l'exécution, par un pipeline GitLab CI, de la tâche « helm-package », suivie de la tâche « helm-publish » qui publie les artefacts Helm Charts dans le registre OCI de GitLab.

Voici un exemple de sortie des journaux de la tâche semantic-release dans laquelle une mise à jour de version « patch » a été effectuée de la version 1.0.3 à la version 1.0.4 :
[semantic-release] › ℹ Running semantic-release version 25.0.3
[semantic-release] › ✔ Loaded plugin "verifyConditions" from "@semantic-release/changelog"
[semantic-release] › ✔ Loaded plugin "verifyConditions" from "@semantic-release/exec"
[semantic-release] › ✔ Loaded plugin "verifyConditions" from "@semantic-release/git"
[semantic-release] › ✔ Loaded plugin "verifyConditions" from "@semantic-release/gitlab"
[semantic-release] › ✔ Loaded plugin "analyzeCommits" from "@semantic-release/commit-analyzer"
[semantic-release] › ✔ Loaded plugin "analyzeCommits" from "@semantic-release/exec"
[semantic-release] › ✔ Loaded plugin "verifyRelease" from "@semantic-release/exec"
[semantic-release] › ✔ Loaded plugin "generateNotes" from "@semantic-release/release-notes-generator"
[semantic-release] › ✔ Loaded plugin "generateNotes" from "@semantic-release/exec"
[semantic-release] › ✔ Loaded plugin "prepare" from "@semantic-release/changelog"
[semantic-release] › ✔ Loaded plugin "prepare" from "@semantic-release/exec"
[semantic-release] › ✔ Loaded plugin "prepare" from "@semantic-release/git"
[semantic-release] › ✔ Loaded plugin "publish" from "@semantic-release/exec"
[semantic-release] › ✔ Loaded plugin "publish" from "@semantic-release/gitlab"
[semantic-release] › ✔ Loaded plugin "addChannel" from "@semantic-release/exec"
[semantic-release] › ✔ Loaded plugin "success" from "@semantic-release/exec"
[semantic-release] › ✔ Loaded plugin "success" from "@semantic-release/gitlab"
[semantic-release] › ✔ Loaded plugin "fail" from "@semantic-release/exec"
[semantic-release] › ✔ Loaded plugin "fail" from "@semantic-release/gitlab"
[semantic-release] › ✔ Run automated release from branch main on repository https://gitlab-ci-token:[secure]@gitlab.com/hackerstack/semantic-release-demo.git
[semantic-release] › ✔ Allowed to push to the Git repository
[semantic-release] › ℹ Start step "verifyConditions" of plugin "@semantic-release/changelog"
[semantic-release] › ✔ Completed step "verifyConditions" of plugin "@semantic-release/changelog"
[semantic-release] › ℹ Start step "verifyConditions" of plugin "@semantic-release/exec"
[semantic-release] › ✔ Completed step "verifyConditions" of plugin "@semantic-release/exec"
[semantic-release] › ℹ Start step "verifyConditions" of plugin "@semantic-release/git"
[semantic-release] › ✔ Completed step "verifyConditions" of plugin "@semantic-release/git"
[semantic-release] › ℹ Start step "verifyConditions" of plugin "@semantic-release/gitlab"
[semantic-release] [@semantic-release/gitlab] › ℹ Verify GitLab authentication (https://gitlab.com/api/v4)
[semantic-release] › ✔ Completed step "verifyConditions" of plugin "@semantic-release/gitlab"
[semantic-release] › ℹ Found git tag 1.0.3 associated with version 1.0.3 on branch main
[semantic-release] › ℹ Found 1 commits since last release
[semantic-release] › ℹ Start step "analyzeCommits" of plugin "@semantic-release/commit-analyzer"
[semantic-release] [@semantic-release/commit-analyzer] › ℹ Analyzing commit: fix: testing
[semantic-release] [@semantic-release/commit-analyzer] › ℹ The release type for the commit is patch
[semantic-release] [@semantic-release/commit-analyzer] › ℹ Analysis of 1 commits complete: patch release
[semantic-release] › ✔ Completed step "analyzeCommits" of plugin "@semantic-release/commit-analyzer"
[semantic-release] › ℹ Start step "analyzeCommits" of plugin "@semantic-release/exec"
[semantic-release] › ✔ Completed step "analyzeCommits" of plugin "@semantic-release/exec"
[semantic-release] › ℹ The next release version is 1.0.4
[semantic-release] › ℹ Start step "verifyRelease" of plugin "@semantic-release/exec"
[semantic-release] › ✔ Completed step "verifyRelease" of plugin "@semantic-release/exec"
[semantic-release] › ℹ Start step "generateNotes" of plugin "@semantic-release/release-notes-generator"
[semantic-release] › ✔ Completed step "generateNotes" of plugin "@semantic-release/release-notes-generator"
[semantic-release] › ℹ Start step "generateNotes" of plugin "@semantic-release/exec"
[semantic-release] › ✔ Completed step "generateNotes" of plugin "@semantic-release/exec"
[semantic-release] › ℹ Start step "prepare" of plugin "@semantic-release/changelog"
[semantic-release] [@semantic-release/changelog] › ℹ Update /builds/hackerstack/semantic-release-demo/CHANGELOG.md
[semantic-release] › ✔ Completed step "prepare" of plugin "@semantic-release/changelog"
[semantic-release] › ℹ Start step "prepare" of plugin "@semantic-release/exec"
[semantic-release] [@semantic-release/exec] › ℹ Call script yq e '.version = "1.0.4"' -i Chart.yaml && yq e '.appVersion = "1.0.4"' -i Chart.yaml
[semantic-release] › ✔ Completed step "prepare" of plugin "@semantic-release/exec"
[semantic-release] › ℹ Start step "prepare" of plugin "@semantic-release/git"
[semantic-release] [@semantic-release/git] › ℹ Found 2 file(s) to commit
[semantic-release] [@semantic-release/git] › ℹ Prepared Git release: 1.0.4
[semantic-release] › ✔ Completed step "prepare" of plugin "@semantic-release/git"
[semantic-release] › ℹ Start step "generateNotes" of plugin "@semantic-release/release-notes-generator"
[semantic-release] › ✔ Completed step "generateNotes" of plugin "@semantic-release/release-notes-generator"
[semantic-release] › ℹ Start step "generateNotes" of plugin "@semantic-release/exec"
[semantic-release] › ✔ Completed step "generateNotes" of plugin "@semantic-release/exec"
[semantic-release] › ✔ Created tag 1.0.4
[semantic-release] › ℹ Start step "publish" of plugin "@semantic-release/exec"
[semantic-release] › ✔ Completed step "publish" of plugin "@semantic-release/exec"
[semantic-release] › ℹ Start step "publish" of plugin "@semantic-release/gitlab"
[semantic-release] [@semantic-release/gitlab] › ℹ Published GitLab release: 1.0.4
[semantic-release] › ✔ Completed step "publish" of plugin "@semantic-release/gitlab"
[semantic-release] › ℹ Start step "success" of plugin "@semantic-release/exec"
[semantic-release] › ✔ Completed step "success" of plugin "@semantic-release/exec"
[semantic-release] › ℹ Start step "success" of plugin "@semantic-release/gitlab"
[semantic-release] › ✔ Completed step "success" of plugin "@semantic-release/gitlab"
[semantic-release] › ✔ Published release 1.0.4 on default channel
Grâce à ce système, je peux me concentrer pleinement sur mes développements. Fini les problèmes liés aux numéros de version et aux mises à jour manuelles… gain de temps et d'énergie… les mises à jour de version, les publications et les journaux de modifications sont automatisés, cohérents et reflètent les changements réels.
Merci de votre lecture, continuez à apprendre et à bientôt pour un prochain article 🚀