Préambule
Dans le dernier article, nous avons décrit les tests ajoutés à notre projet. Ces tests sont utiles pour vérifier notre développement localement puisque nous utilisons le TDD. Mais ils sont aussi utiles pour vérifier s’il y a des régressions. Dans cet article, nous allons
- Définir ce qu’est le CICD.
- Montrer comment ajouter les paramètres CICD à notre projet.
Qu’est-ce que le CICD ?
L’acronyme CICD signifie Continuous Integration Continuous Delivery (intégration continue, livraison continue). L’acronyme CICDCD signifie Continuous Integration Continuous Delivery Continuous Deployment (intégration continue, livraison continue, déploiement continu).
Lorsque nous parlons de CICD (ou CICDCD), nous faisons souvent référence aux pipelines. Un pipeline CICD définit un processus dans lequel certaines étapes sont exécutées l’une après l’autre, dans le but de construire et de vérifier l’application avant de la livrer et de la déployer.
Quels outils CICD ?
Il existe quelques outils pour exécuter le CICD ; nous pouvons citer :
- Gitlab-ci
- CircleCI
- GitHub Action
- Jenkins
Pour les projets open source comme le nôtre, il est plus facile d’utiliser un outil de CICD intégré dans un service d’hébergement et de gestion de développement logiciel comme GitLab ou GitHub. C’est pourquoi nous préférons utiliser GitLab, CircleCi ou GitHub Actions, car Jenkins nécessite un déploiement, une gestion et des ressources matérielles distincts.
Nous souhaitons également utiliser un service gratuit, c’est pourquoi nous n’utilisons pas de CI Gitlab ; car nous ne pouvons plus pousser le rapport de Gitlab vers Github avec l’offre gratuite.
Dans ce billet, nous allons détailler ces solutions mais nous n’en implémenterons que deux :
- CircleCI
- Action GitHub
Mise en place de notre CICD
Notre pipeline souhaité
A travers notre premier pipeline, nous voulons valider :
- construire l’application.
- vérifier que le code est formaté.
- vérifier la non-régression du code par l’exécution de tests.
Nous voulons également que le pipeline soit exécuté à chaque commit sur la branche develop et les branches CI (avec le préfixe ci_). Nous pourrions ajouter d’autres types de branches : feature(feat/), fix (fix/), documentation (docs/)
Implémentation avec CircleCI
Première connexion
CircleCI est une plateforme de CICD qui a un plan gratuit ; Pour pouvoir utiliser CircleCI, nous devons :
Créer un compte
Configurer notre code
Configurer
Il y a trois possibilités pour lier votre projet avec votre futur CI :
Création d’un job
CircleCI définit des “jobs” qui sont des tâches exécutables ; chaque job peut être divisé en étapes. Dans la première version de notre CI (cf. code ci-dessous) nous voulons :
- Construire le fichier jar.
- Exécuter les tests unitaires.
- Exécuter les tests d’intégration.
- Exécuter les tests système.
Voici le fichier .circleci/config.yml
:
1# Java Gradle CircleCI 2.0 configuration file
2# See: https://circleci.com/docs/2.0/language-java/
3version: 2.1
4
5
6# Define a job to be invoked later in a workflow.
7# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
8jobs:
9 assemble:
10 # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub.
11 # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor
12 docker:
13 # specify the version you desire here
14 - image: cimg/openjdk:17.0.5
15
16 # Specify service dependencies here if necessary
17 # CircleCI maintains a library of pre-built images
18 # documented at https://circleci.com/docs/2.0/circleci-images/
19 # - image: circleci/postgres:9.4
20
21 working_directory: ~/happraisal
22
23 environment:
24 # Customize the JVM maximum heap limit
25 JVM_OPTS: -Xmx3200m
26 TERM: dumb
27 # Add steps to the job
28 # See: https://circleci.com/docs/2.0/configuration-reference/#steps
29 steps:
30 - checkout
31 - attach_workspace:
32 at: ~/happraisal
33
34 # Download and cache dependencies
35 - restore_cache:
36 keys:
37 - v1-dependencies-{{ checksum "build.gradle" }}
38 # fallback to using the latest cache if no exact match is found
39 - v1-dependencies-
40
41 - run: ./gradlew assemble
42
43 - save_cache:
44 paths:
45 - ~/.gradle
46 key: v1-dependencies-{{ checksum "build.gradle" }}
47 - persist_to_workspace:
48 root: ~/happraisal
49 paths:
50 - ./build
51 - store_artifacts:
52 path: ~/happraisal/build/libs
53
54 unit-tests:
55 docker:
56 - image: cimg/openjdk:17.0.5
57
58 working_directory: ~/happraisal
59 steps:
60 - checkout
61 - restore_cache:
62 keys:
63 - v1-dependencies-{{ checksum "build.gradle" }}
64 # fallback to using the latest cache if no exact match is found
65 - v1-dependencies-
66 - run: ./gradlew test
67 - save_cache:
68 paths:
69 - ~/.gradle
70 key: v1-dependencies-{{ checksum "build.gradle" }}
71 - store_test_results:
72 path: ~/happraisal/build/test-results
73
74
75
76 integration-tests:
77 docker:
78 - image: cimg/openjdk:17.0.5
79
80 working_directory: ~/happraisal
81 steps:
82 - checkout
83 - restore_cache:
84 keys:
85 - v1-dependencies-{{ checksum "build.gradle" }}
86 # fallback to using the latest cache if no exact match is found
87 - v1-dependencies-
88 - run: ./gradlew integrationTest
89 - save_cache:
90 paths:
91 - ~/.gradle
92 key: v1-dependencies-{{ checksum "build.gradle" }}
93
94
95 system-tests:
96 docker:
97 - image: cimg/openjdk:17.0.5
98
99 working_directory: ~/happraisal
100 steps:
101 - checkout
102 - restore_cache:
103 keys:
104 - v1-dependencies-{{ checksum "build.gradle" }}
105 # fallback to using the latest cache if no exact match is found
106 - v1-dependencies-
107 - run: ./gradlew systemTest
108 - save_cache:
109 paths:
110 - ~/.gradle
111 key: v1-dependencies-{{ checksum "build.gradle" }}
112
113workflows:
114 version: 2.1
115 microservice:
116 jobs:
117 - assemble
118 - unit-tests:
119 requires:
120 - assemble
121 - integration-tests:
122 requires:
123 - assemble
124 - system-tests:
125 requires:
126 - assemble
Mise en oeuvre avec les actions GitHub
Terminologie
Un flux de travail : dans la documentation officielle, un workflow est défini comme “un processus automatisé configurable qui exécutera un ou plusieurs travaux”. Il est configuré via un fichier yaml cf. https://docs.github.com/fr/actions/using-workflows/about-workflows
Action : “Les actions sont des tâches individuelles que vous pouvez combiner pour créer des tâches et personnaliser votre flux de travail.” cf. https://docs.github.com/fr/actions/creating-actions/about-custom-actions
Première connexion
GitHub Actions est l’outil de CI de GitHUb. Ce CI est accessible depuis le bouton Action dans une barre d’outils
Lors du premier accès, GithUb Actions affiche une proposition de workflow en fonction de votre projet. Dans notre cas, nous avons sélectionné le workflow Java avec gradle.
Une fois que nous avons sélectionné notre workflow, nous sommes redirigés vers l’éditeur nous proposant un fichier par défaut. Il est possible de le modifier et de le sauvegarder sur une branche spécifique ; afin de tester facilement le CICD sans avoir à le pousser sur develop. Il est possible de définir le nom de la branche de travail dans la partie push.
Création de jobs
1on :
2 push :
3 branches :
4 - develop
5 - ci_*
Pour mettre en oeuvre les 3 étapes définies ci-dessus, nous devons créer les jobs :
- assemble : pour compiler le code et créer le jar.
- spotless : pour vérifier le format du nouveau code.
- unit-tests : pour exécuter les tests unitaires.
- integration-tests : pour exécuter les tests d’intégration.
- system-tests : pour exécuter les tests système.
Le code ci-dessous montre un exemple de création d’un job
1jobs:
2 assemble:
3 runs-on: ubuntu-latest
4 steps:
5 - uses: actions/checkout@v3
6 - uses: actions/setup-java@v3
7 with:
8 java-version: '17'
9 distribution: 'temurin'
10 cache: gradle
11 - run: ./gradlew assemble --no-daemon
Dans le code ci-dessus :
- Nous créons le job assemble qui est basé sur ubuntu-latest
- Nous utilisons deux actions pour vérifier le code et configurer le compilateur Java.
- Nous exécutons la tâche gradle assemble.
Résumé
Le premier objectif de cet article était de tester trois moteurs CICD (GitLab, CircleCi et GitHub Actions), mettant en oeuvre des pipelines similaires. En essayant d’implémenter le CICD sur ces moteurs, nous avons rapidement rencontré quelques limitations pour les deux premiers CICD :
- Pousser le rapport de la CI Gitlab vers GitHub n’est pas possible.
- Sur CircleCi, l’espace maximum disponible pour les artefacts et leur temps de rétention n’étaient pas compatibles avec nos objectifs. Dans ce cas, seule l’action GitHub est complètement utile.
En conclusion, je pense que pour mettre en place un CICD libre, il est préférable d’utiliser un CI intégré à son gestionnaire de version comme GItHub Actions pour GitHub ou GitLab CICD pour GitLab.
Si vous avez des remarques sur le fond ou la forme, vous pouvez laisser un commentaire…c’est en échangeant que l’on progresse.
Écrit par : Emmanuel Quinton Revue par : Daniele Cremonini
Commentaires