Mise à jour : 27 mai 2025
Lecture : 6 min
Découvrez comment configurer un pipeline CI/CD dans GitLab pour un dépôt monorepo et simplifier l'hébergement de plusieurs applications dans un seul dépôt.

Les monorepos permettent d’héberger le code de plusieurs applications au sein d'un seul dépôt. Dans GitLab, cela consiste à organiser le code source de chaque application dans des répertoires distincts au sein d'un même projet. Bien que cette approche facilite le contrôle de version pour l'ensemble du code, tirer parti des capacités avancées des pipelines CI/CD de GitLab pouvait s'avérer complexe... jusqu'à l'arrivée d'une nouvelle fonctionnalité dans GitLab 16.4 !
Lorsque plusieurs applications coexistent dans un même dépôt, il est logique de vouloir disposer de pipelines CI/CD distincts pour chacune d'elles. Par exemple, si l'un de vos projets regroupe une application .NET et une application Spring, chacune d'elle nécessitera des jobs de compilation et de test différents. L'idéal serait donc de pouvoir découpler ces pipelines pour qu'ils s'exécutent uniquement lorsque des modifications sont apportées au code source de l'application concernée.
Techniquement, cela revient à configurer un fichier de pipeline .gitlab-ci.yml au niveau du projet, qui inclut des fichiers YAML spécifiques basés sur les modifications détectées dans certains répertoires. Le fichier de pipeline .gitlab-ci.yml agit comme un plan de contrôle qui déclenche le pipeline approprié en fonction des modifications apportées au code.
Avant l'introduction de nouvelles fonctionnalités dans GitLab 16.4, il n'était pas possible d'inclure directement un fichier YAML en fonction des modifications apportées à un répertoire ou un fichier spécifique. Une solution de contournement était toutefois disponible.
Prenons un exemple concret : un monorepo avec deux répertoires, java et python, contenant respectivement le code source d'une application Java et d'une application Python. Chaque répertoire disposait d'un fichier YAML propre à l'application pour gérer sa compilation. Le fichier de pipeline principal du projet incluait simplement les deux fichiers YAML des applications, mais une logique de gestion des modifications devait être directement intégrée dans ces fichiers.
.gitlab-ci.yml :
stages:
- build
- test
- deploy
top-level-job:
stage: build
script:
- echo "Hello world..."
include:
- local: '/java/j.gitlab-ci.yml'
- local: '/python/py.gitlab-ci.yml'
Pour chaque application, il était nécessaire de créer un job masqué (par exemple, .java-common ou .python-common), qui ne s'exécutait qu'en présence de modifications apportées au répertoire correspondant. Les jobs masqués ne s'exécutaient pas par défaut. Ils servaient à centraliser la logique de déclenchement et à la réutiliser dans d'autres jobs. Cependant, cela impliquait d'étendre le job masqué dans chaque pipeline afin de respecter les règles de détection des modifications, qui déclenchaient alors le job d'exécution du pipeline.
'j.gitlab-ci.yml':
''' stages:
.java-common: rules: - changes: - ../java/*'
java-build-job: extends: .java-common stage: build script: - echo "Building Java"
java-test-job: extends: .java-common stage: test script: - echo "Testing Java"
'''
'py.gitlab-ci.yml':
''' stages:
.python-common: rules: - changes: - "../python/*"
python-build-job: extends: .python-common stage: build script: - echo "Building Python"
python-test-job: extends: .python-common stage: test script: - echo "Testing Python"
'''
Cette méthode fonctionnait, mais présentait des inconvénients majeurs. En effet, chaque pipeline devait étendre le job masqué pour chaque autre job dans le fichier YAML afin de respecter les règles de déclenchement. Elle avait pour conséquence la création de code redondant et l'augmentation du risque d'erreur humaine. De plus, les jobs étendus n'acceptaient pas de clés en double. Vous ne pouviez donc pas définir votre propre logique de règles (rules), car cela entraînait des conflits de clés et leurs valeurs n'étaient pas fusionnées.
Malgré tout, avec cette méthode, le pipeline est opérationnel, incluant les jobs j.gitlab-ci.yml dès que le répertoire java/ est mis à jour, et les jobs py.gitlab-ci.yml dès que le répertoire python/ est mis à jour.
Avec le lancement de GitLab 16.4, nous avons introduit une nouvelle fonctionnalité : la possibilité d'utiliser le terme include avec rules:changes dans les pipelines CI/CD. Auparavant, vous pouviez utiliser l'option include avec rules:if, mais pas avec rules:changes. Cette nouvelle version est donc une amélioration majeure. Désormais, vous pouvez simplement utiliser le terme include et définir les règles du monorepo dans la configuration du pipeline de votre projet.
Nouveau fichier .gitlab-ci.yml :
stages:
- build
- test
top-level-job:
stage: build
script:
- echo "Hello world..."
include:
- local: '/java/j.gitlab-ci.yml'
rules:
- changes:
- 'java/*'
- local: '/python/py.gitlab-ci.yml'
rules:
- changes:
- 'python/*'
Ainsi, le fichier YAML de chaque application se concentre exclusivement sur les jobs nécessaires à cette application, comme la compilation et le test du code, sans avoir à étendre à plusieurs reprises un job masqué. Cette approche permet une plus grande flexibilité dans les définitions de job et les ingénieurs n'ont plus besoin de réécrire le code des configurations.
Nouveau fichier j.gitlab-ci.yml (Java) :
stages:
- build
- test
- deploy
java-build-job:
stage: build
script:
- echo "Building Java"
java-test-job:
stage: test
script:
- echo "Testing Java"
Nouveau fichier py.gitlab-ci.yml (Python) :
stages:
- build
- test
- deploy
python-build-job:
stage: build
script:
- echo "Building Python"
python-test-job:
stage: test
script:
- echo "Testing Python"
Cette méthode permet d'inclure les jobs Java et Python uniquement lorsque leurs répertoires respectifs sont modifiés. Cependant, il convient de noter que les jobs peuvent s'exécuter de manière inattendue lors de l'utilisation de changes. La règle de déclenchement des modifications est toujours évaluée comme vraie lors du push d'une nouvelle branche ou d'un nouveau tag dans GitLab. Ainsi, tous les jobs inclus dans le pipeline s'exécuteront lors du premier push d'une branche, même si des règles rules:changes spécifiques sont définies. Vous pouvez résoudre ce problème en créant d'abord votre branche de fonctionnalité, puis en ouvrant une merge request pour commencer votre développement, car le premier push vers la branche lors de sa création forcera l'exécution de tous les jobs.
En fin de compte, les monorepos constituent une stratégie adaptée à GitLab et à l'approche CI/CD. La fonctionnalité include avec rules:changes est une bonne pratique que nous recommandons lors de l'utilisation de GitLab CI avec des monorepos. Pour utiliser les monorepos, commencez par essayer Gitlab Ultimate gratuitement dès aujourd'hui.
Cet article de blog vous a plu ou vous avez des questions ou des commentaires ? Partagez vos réflexions en créant un sujet dans le forum de la communauté GitLab.
Donnez votre avis