Votre navigateur ne supporte pas impress.js, cette présentation a donc été simplifiée.

Pour une meilleure expérience, utilisez un navigateur Chrome, Safari ou Firefox à jour.

Thomas GRANDJEAN
Service IDDÉE, DREAL Hauts-de-France
Apéro GitLab (25/03/2025)

# Apéro GitLab # le package `pre-commit` ### Thomas Grandjean ### DREAL Hauts-de-France ![logo-pre-commit](images/pre-commit/logo-pre-commit.png)
# Disclaimer Je ne suis **pas** un spécialiste du sujet ! Mais j'espère en savoir (juste) assez pour présenter l'outil 🤞 et convaincre de son intérêt... Cet outil ne se substitue **pas** aux autres outils (ex. SonarQube) : `pre-commit` utilise des git hooks, qui peuvent être compromis comme tout code (voir par exemple sur [https://medium.com/@3wisesiren/exploiting-pre-commit-hooks-a-practical-demonstration-4c4bcefe32c8 🔗](https://medium.com/@3wisesiren/exploiting-pre-commit-hooks-a-practical-demonstration-4c4bcefe32c8))
# Qu'est-ce qu'un Git Hook 🪝 ? Un point d'entrée pour exécuter un script avant/après un git commit, push ou autre. Les git hooks : * peuvent notamment refuser un commit ou le modifier ; * fonctionnent en ligne de commande *et* avec les interfaces ; * peuvent permettre de mettre du code en forme, détecter des erreurs, etc. * peuvent être exécutés côté client ou côté serveur. En pratique, on parle de code (scripts, etc.) : celui exécuté par les git-hooks doit être versionné dans le repo git. Exemples de git hooks :
`pre-commit`
`prepare-commit-msg`
`commit-msg`
`post-commit`
`post-checkout`
`pre-rebase`
...
Pour en savoir plus, voir la doc : [https://git-scm.com/book/ms/v2/Customizing-Git-Git-Hooks 🔗](https://git-scm.com/book/ms/v2/Customizing-Git-Git-Hooks) Voire également ce tuto (source Atlassian) plutôt bien fait : [https://www.atlassian.com/git/tutorials/git-hooks 🔗](https://www.atlassian.com/git/tutorials/git-hooks)
# Arrive le package `pre-commit` Un package python 🐍 [https://pre-commit.com/](https://pre-commit.com/) Mais qui supporte des hooks écrits dans de nombreux langages : conda, coursier, dart, docker, docker_image, dotnet, fail, golang, haskell, lua, node, perl, python, r, ruby, rust, swift, pygrep, script, system. L'installation de `pre-commit` se fait en 3 (ou 4) étapes : * installation (nécessite une distribution python), par exemple : `pip install pre-commit` * ajout d'une configuration (fichier `.pre-commit-config.yaml`) * installation des scripts : `pre-commit install` * exécution sur l'ensemble du projet : `pre-commit run --all-files` * et si besoin, désinstallation : `pre-commit uninstall`
L'idéal (mon avis personnel !) : * pour un projet python, l'ajouter aux dépendances de dev avec un environnement virtuel (par ex avec `poetry`) * pour un projet non python (ou mixte) : ajouter un environnement virtuel python pour `pre-commit` uniquement (fichier `pyproject.toml` pour `poetry` par exemple) * à faire au démarrage si possible et à un moment où il n'y a pas de branches parallèles sinon Exemple :
                
[project]
name = "pre-commit-hooks"
version = "0.1.0"
description = "This environment is only used to install pre-commit"
authors = [
    {name = "Your Name",email = "you@example.com"}
]
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
    "pre-commit (>=4.1.0,<5.0.0)",
]

[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
                
            
# Démonstration avec un projet récupéré de collègues On repart d'un projet python où le code a été poussé tel quel (production de collègues bretons pour l'hydrométrie) * j'ai ajouté * un fichier `pyproject.toml` pour gérer un environnement virtuel python (à l'aide de `poetry` dans le cas présent) * la config de deux utilitaires très utiles pour le formattage du code python : `black` et `flake8` (config reprise d'un autre projet) * la config de `pre-commit`, reprise d'un autre repo * j'ai installé (j'espère...) toutes les dépendances du projet, ainsi que quelques mes utilitaires de développement *Nota : les exemples de config sont accessibles dans les slides suivantes.*
# Démonstration
Exemple de configuration : `.pre-commit-config.yaml` *tiré du code source de `french-cities` [https://github.com/tgrandje/french-cities/blob/main/.pre-commit-config.yaml 🔗](https://github.com/tgrandje/french-cities/blob/main/.pre-commit-config.yaml)*
                
repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
    -   id: trailing-whitespace
    -   id: end-of-file-fixer
    -   id: check-yaml
    -   id: check-added-large-files
-   repo: https://github.com/pycqa/flake8
    rev: '7.1.1'
    hooks:
    -   id: flake8
        args: [--config, .flake8]
-   repo: https://github.com/psf/black
    rev: 24.10.0
    hooks:
    -   id: black
        args: [--config, pyproject.toml]
                
            
Exemple de configuration de `black` : adaptation de `pyproject.toml`
                
[...]

[tool.poetry.group.dev.dependencies]
spyder = "^6.0.4"
pre-commit = "^4.1.0"
flake8 = "^7.1.2"
black = "^25.1.0"

[tool.black]
include = '\.py$'
line-length = 79

[...]
                
            
Exemple de configuration de `flake8` :
                
[flake8]
tee = True
extend-ignore = E722,C901,E501
count = True
exclude = .git,__pycache__,docs/*,*.yaml,*.zip,.env,*.svg,*.md,*.qmd,*.css,*.txt,*.rst,Dockerfile,.spyproject,.pytest_cache,*.lock,*.toml,.venv
max-complexity = 10
statistics = True
per-file-ignores =
    __init__.py:F401,F403
    tests/*:F401
output-file = ./reports/flake8/flake8stats.txt
                
            
# Conclusion * un outil pour fiabiliser son code avant même qu'il ne soit poussé * et qui facilite aussi la vie des personnes relisant les `merge requests` / `pull requests` * testé linux / windows / WSL, git CLI et github desktop* * bonus : on peut très facilement répliquer la config d'un ancien projet \* *nota : des difficultés rencontrées par un agent sur un poste WSL avec github desktop windows, pas encore résolues*