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.
# Apéro GitLab
# le package `pre-commit`
### Thomas Grandjean
### DREAL Hauts-de-France

# 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*