Cuando revisamos código, a menudo empleamos tiempo repasando pequeños fallos o detalles de estilo que nos desvían de lo verdaderamente importante. En este post presentaremos pre-commit, una herramienta que ataca este problema corrigiendo nuestro código automáticamente.
¿Qué hace pre-commit?
Antes de explicar lo que hace pre-commit, conviene tener claros ciertos aspectos de Git, y en concreto, de los Git Hooks. Se trata del mecanismo que ofrece Git para ejecutar scripts en diferentes puntos clave, como podrían ser un commit o un merge. De esta forma, podremos definir un script (Hook) que se ejecute justo antes de hacer push o después de hacer un merge.
Considerando lo anterior, podemos decir que pre-commit es un framework que nos permite añadir, gestionar y ejecutar esos hooks de forma sencilla. Como veremos a continuación en el ejemplo práctico, ofrece un sinfín de hooks listos para usar en múltiples lenguajes.
Ejemplo práctico
Lo primero que haremos será instalar pre-commit con pip
:
pip install pre-commit
Podemos validar la instalación y su versión con:
pre-commit --version
Una vez tengamos instalado pre-commit, abriremos el proyecto en el que lo queramos usar y crearemos el fichero .pre-commit-config.yaml
, que contendrá la configuración con la que queremos que la herramienta funcione.
Un ejemplo de fichero de configuración podría ser el siguiente:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
Vemos cómo se definen los repositorios de los que se van a tomar los hooks (de momento, solo estamos usando un repositorio) y los respectivos hooks. Se trata de comprobaciones generales, pero podemos ir añadiendo nuevos hooks en función de nuestras preferencias.
En Supported Hooks puedes encontrar una lista con diferentes hooks disponibles. En nuestro caso, vamos a personalizar el fichero de configuración de la siguiente manera:
default_stages:
- commit
- push
fail_fast: true
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: detect-private-key
- id: double-quote-string-fixer
- repo: https://github.com/asottile/dead
rev: v1.5.0
hooks:
- id: dead
- repo: https://github.com/dannysepler/rm_unneeded_f_str
rev: v0.1.0
hooks:
- id: rm-unneeded-f-str
En primer lugar, notamos que se ha añadido default_stages
, donde definimos las etapas en las que queremos que se disparen los hooks. En este caso, hemos definido que se disparen antes de un commit o un push. Esto solo tendrá efecto sobre los hooks que no tengan etapas definidas.
A continuación encontramos fail_fast
, que define la política de actuación tras encontrar un fallo: seguir con la ejecución (false) o parar (true).
También hemos añadido nuevos hooks, tanto del repositorio usado anteriormente como de nuevos repositorios.
Una vez que tenemos listo nuestro fichero de configuración, ejecutamos el siguiente comando para configurar los Git Hooks.
pre-commit install
Con esto, pre-commit estaría listo para mejorar nuestros commits. Sin embargo, si vamos a usarlo en un proyecto ya existente, quizá tenga sentido revisar todo el código actual en lugar de ir revisando los ficheros que van entrando a nuevos commits. Podemos hacer esto con el siguiente comando:
pre-commit run --all-files
Tanto ejecutando pre-commit contra todos los ficheros como al hacer un commit, nos mostrará el resultado y las acciones realizadas. En la siguiente captura podemos ver cómo se muestra la fase en la que ha fallado (Fix End of Files) y los ficheros afectados, en este caso, main.py.
Observamos que no se han seguido ejecutando hooks tras el fallo. Esto es debido a la configuración fail_fast
que definimos anteriormente.
Si revisamos los ficheros implicados, veremos que el hook ha aplicado los cambios necesarios por nosotros.
También podemos ver cómo se identifican claves privadas con el respectivo hook:
Conclusión
En este post hemos introducido pre-commit, una herramienta que nos permite encontrar fallos en nuestro código de forma automática. Hemos visto cómo la podemos instalar y un breve caso de uso.