Comment Faire Évoluer Une Application Pour La Rendre Plus Robuste Et Maintenable - Mise en Place Du CICD

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

    circleci-create-user.png

  • Configurer notre code

    img.png

  • Configurer

Il y a trois possibilités pour lier votre projet avec votre futur CI :

circleci-create-settings.png

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 github_action_menu.png

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.

github_action_gradle.png

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.

github_action_gradle_file.png

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


CC BY-NC-ND 4.0

Introduction Aux APIs
How to Test a Java Springboot Application

Commentaires