Dans cette partie également, vous travaillerez en pair-programming.

1. Automatisation des hooks

Comme vu précédemment, il est nécessaire de copier les hooks versionnés dans le dossier .git/hooks pour qu’ils soient pris en compte par Git. Cela poser des problèmes de maintenabilité et de synchronisation.

Un outil tel que 🐶 Husky permet d’automatiser cette tâche. C’est une librairie Node.js qui pourra s’intégrer assez “facilement” dans un projet web.

Or ce n’est pas forcément notre cas et il n’est pas nécessaire de surcharger l’environnement avec du Node.

Git propose une solution native pour aider à la synchronisation des hooks ; il s’agit d’une configuration : core.hooksPath.

Remarque : D’ailleurs, Husky repose sur l’utilisation de cette configuration.

1.1. 📋️ Instructions de la configuration Git

Manipuler et tester la configuration core.hooksPath

  1. Positionnez-vous sur la branche main et synchronisez votre dépôt local avec le dépôt distant (git pull).
  2. Récupérez le pre-commit hook : cp bin/hooks/pre-commit .git/hooks.
  3. Tentez un commit “à vide” : git commit -m "Test".
    Cette action doit être refusée par le hook : Interdiction de commiter sur la branche principale 'main' !.
  4. Supprimez les hooks personnalisés dans le .git/hooks : rm .git/hooks/pre-commit .git/hooks/pre-push.
  5. Retentez le commit “à vide”. Vous devriez avoir un message natif à Git vous indiquant qu’il n’y a rien à commiter.
  6. Configurez le chemin vers les hooks versionnés : git config --local core.hooksPath bin/hooks.
    Faites attention à bien préciser l’option --local, vous ne voudriez pas que cette configuration spécifique soit définie pour tous vos repositories.
  7. Retentez de nouveau le commit “à vide”. Vous retrouvez le message d’erreur du hook personnalisé.
  8. Modifiez le fichier bin/hooks/pre-commit pour ajouter error "Test !" && exit 1 à la ligne 8 (après la fonction error).
  9. Retentez une dernière fois le commit “à vide”. Vous devriez avoir votre message d’erreur Test !.
  10. Annulez vos modifications : git reset --hard.

Communiquer la procédure

  1. Créez la branche local-hooks-config.
  2. Modifiez le fichier README.md pour compléter la tâche Hooks en ajoutant ces deux lignes juste en-dessous :

    ⚠️ Attention à bien garder les espaces en début de ligne pour créer une sous-liste.

      - [x] Utilisation des scripts versionnés.
      - [ ] Automatiser la configuration.
    
  3. Modifiez aussi le fichier README.md au niveau de la partie 📋️ Instructions du repository pour ajouter la mise en place de la configuration Git vue au-dessus.
    Voir plus bas…
  4. Commitez ces modifications : git commit -m "📝 [hooks] Git configuration".
  5. Vous devriez connaître maintenant les instructions à suivre ensuite.

Proposition de rédaction du README.md

## 📋️ Instructions du repository
  
### Git - Configuration
  
```bash
# Définit le chemin vers les hooks versionnés.
git config --local core.hooksPath bin/hooks
```

1.2. 📋️ Instructions de l’automatisation

On ne va pas exactement faire d’automatisation ; on va éviter de faire une tâche manuelle, ce qui est une sorte d’automatisation, par le biais d’un script bash.

  1. Créez la branche local-setup-hooks.
  2. Créez le fichier bin/setup/hooks et ajoutez-y le contenu défini ci-après.
  3. Pensez à rendre ce script exécutable… Et n’oubliez pas de remplacer les TODO par le code adéquat.
  4. Modifiez le fichier README.md pour cocher la deuxième sous-tâche de Hooks définie dans la partie précédente.
  5. Modifiez de nouveau le fichier README.md pour remplacer ce qui avait été écrit sur les instructions du repository concernant la configuration Git. Toute la partie Git - Configuration peut être remplacée par le contenu fourni ci-après.
  6. Commitez : git commit -m "🔨 [hooks] Setup script".
  7. Pushez, créez la PR et demandez-moi une review.

📝 Contenu initial du script bin/setup/hooks

#!/bin/bash

set -eu

ROOT_PATH="$(realpath "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/../..")"
HOOKS_DIR="bin/hooks"
HOOKS_PATH="${ROOT_PATH}/${HOOKS_DIR}"

# 1. Vérifie si la configuration locale est définie
hooks_path_config=$(git config --local --get core.hooksPath || echo "")
# TODO: Définir la configuration locale sur la valeur de HOOKS_DIR
#   Si elle n'est pas définie ou si la valeur est différente de HOOKS_DIR => exécuter la commande correspondante
#   Pensez à afficher un message pour informer de l'action effectuée
#   Par exemple : echo "Configuration locale 'core.hooksPath' définie sur '${HOOKS_DIR}'"

# 2. Vérifie si les hooks sont exécutables
# TODO: Rendre chaque fichier hook exécutable
#   Pensez à ignorer les dossiers
#   Comme plus haut, affichez un message pour informer des actions effectuées

📝 Contenu du README.md à remplacer

Ce contenu remplace la sous-partie Git - Configuration de la partie 📋️ Instructions du repository, puisqu’elle n’est plus d’actualité grâce à notre script.

### Setup du repository

Les scripts définis dans le dossier [bin/setup](bin/setup) sont des scripts de "setup" à exécuter une première fois
après le clonage du repository. Certains scripts peuvent être lancés à nouveau pour prendre en compte certains
changements.

* [bin/setup/hooks](bin/setup/hooks) : Agit sur les hooks Git spécifiques au repository.
  1. Définie la configuration locale pour utiliser les hooks versionnés.
  2. Rend les hooks exécutables.
  - Ce script peut être exécuté à nouveau dès qu'un nouveau hook est ajouté au repository afin de le rendre exécutable. 

2. GitHub Actions

GitHub met à disposition un outil d’automatisation permettant notamment de réaliser des tâches de CI/CI : GitHub Actions.

Il faut définir des workflows qui seront exécutés lors d’événements spécifiques (push, pull request, etc.). Ces workflows intègrent un ensemble de jobs qui sont eux-mêmes composés d’étapes.

Lorsqu’un événement GitHub déclenche un workflow, celui-ci va exécuter les jobs dans l’ordre défini sur des machines virtuelles mises à disposition (appelées « runners »). Chaque job exécute ses propres étapes.

Dès lors qu’une étape échoue, le job et le workflow associés sont échus également et l’événement GitHub peut alors s’interrompre complètement tant que le problème n’est pas résolu.

On peut, par exemple, empêcher un push sur une branche si les tests unitaires ne passent pas.

2.1. 📋️ Instructions de la prise en main de GitHub Actions

1) Créez la branche ci-actions-quality-git.

2) Modifiez le fichier .editorconfig pour ajouter une nouvelle règle sur les fichiers yaml :

[*.yaml]
indent_size = 2

3) Créez un nouveau fichier .github/workflows/quality.yaml et ajoutez-y le contenu défini suivant :

name: Qualité
on: [pull_request]
jobs:
  git_standards:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: git fetch origin
      - name: Vérification des commits de la branche
        run: "echo \"PR from: ${{ github.head_ref }} to: ${{ github.base_ref }}\""

4) Commitez vos modifications, cette fois avec un message plus complet :

👷 [quality] Init

👷 GitHub Actions
=================

* Define new `workflow` to check defined Git standards

🐁 EditorConfig
===============

* New rules for `yaml` files

5) Pushez et créez la PR sur GitHub.

GitHub prend alors en compte le workflow et l’exécute : un cadre apparaît sur la PR pour indiquer que le workflow est en cours d’exécution et une nouvelle entrée apparaît dans l’onglet Actions du repository, correspondant à l’exécution de l’ensemble des GitHub Actions générées par la PR.

6) Vérifiez que le workflow s’est bien exécuté, qu’il n’y a pas d’erreur et que la step avec l’instruction echo a bien affiché le message attendu.

2.2. 📋️ Instructions du script exécuté par GitHub Actions

Maintenant, il faut écrire le script qui va effectuer l’action “qualité” que l’on souhaite implémenter, à savoir une vérification du nombre de commits sur la branche à merger, comme on l’avait fait avec les hooks.

L’environnement Git de la VM de GitHub étant un peu différent de celui de vos machines, le hook pre-push ne pourra pas être utilisé tel quel. Il faut écrire un script qui effectue la même action, mais qui soit plus adapté à l’environnement de GitHub.

Il a fallu plusieurs essais pour arriver à un script fonctionnel, donc je vous le donne directement.

  1. Récupérez le fichier : actions-quality-git-01.
  2. Déplacez-le dans le dossier bin/actions/quality/git_standards et renommez-le branch-commits.
  3. Pensez à rendre ce script exécutable.
  4. Modifiez la step Vérification des commits de la branche du fichier quality.yaml pour exécuter le script : run: bin/actions/quality/git_standards/branch-commits ${{ github.head_ref }}.
    On fournit le nom de la branche à merger en paramètre du script grâce aux variables des contextes GitHub Actions.

    Bien sûr, vous remplacez l’instruction echo définie précédemment.
  5. Rajoutez une clef if entre les clefs runs-on et steps du job afin d’ajouter une condition sur l’exécution du job :
    if: github.base_ref == github.event.repository.default_branch.

    Cette condition permet de n’exécuter le job que si la branche de destination est la branche principale du repository.
  6. Ajoutez ces changements au commit précédent : git commit --amend --no-edit.
  7. Avant de pushez, n’oubliez pas la modification habituelle du README.md au sujet des tâches à faire / réalisées. Rajoutez une nouvelle tâche à la liste :
    - [x] **GitHub Actions** : Initialisation du workflow `Quality` pour l'assurance qualité (QA)..
  8. Cette fois, créez un deuxième commit pour tester le job.
    Pour rappel, l’option --no-verify permet de ne pas exécuter les hooks lors d’un git commit ou d’un git push.
  9. Vous devriez avoir 2 commits en local et donc 2 commits sur votre PR.
  10. Le workflow s’exécute de nouveau et cette fois échoue à l’étape Vérification des commits de la branche avec le message d’erreur Vous avez plusieurs commits. [...].
  11. Faites un rebase interactif en local pour squasher vos 2 commits en un seul. Ne gardez que le message du premier commit.
  12. Faites ensuite un git push --force pour forcer la mise à jour de l’historique de la branche distante.
  13. Le workflow devrait cette fois être en succès.
  14. Demandez-moi une review pour valider tout ça.

Pour la suite…

Vous vous êtes familiarisés avec le scripting afin d’effectuer des actions manuelles ou d’exécuter des vérifications répétitives, notamment dans le cadre de l’intégration continue (CI) avec les GitHub Actions. Tout ceci est assez sommaire et il sera nécessaire de vous investir personnellement pour mieux appréhender et manipuler ces sujets.

Dans la prochaine partie du TP, vous allez continuer à utiliser le scripting pour mettre en place un environnement avec l’aide de Docker.