23. Pre-commit: ejecutar controles de calidad antes de confirmar cambios

23.1 Objetivo del tema

Las herramientas de calidad son útiles, pero si dependemos de recordarlas manualmente es fácil olvidarlas. pre-commit permite ejecutar controles automáticamente antes de confirmar cambios en Git.

En este tema instalaremos pre-commit, crearemos una configuración básica y ejecutaremos controles como Ruff, Black, mypy y pytest antes de realizar commits.

Objetivo práctico: configurar pre-commit para que el proyecto ejecute revisiones de calidad antes de confirmar cambios.

23.2 Qué es pre-commit

pre-commit es una herramienta que ejecuta hooks antes de un commit. Un hook es un control automático: formatear código, revisar linting, validar tipos, detectar espacios sobrantes o ejecutar pruebas.

La ventaja es que los problemas se detectan temprano, antes de que lleguen al repositorio compartido.

23.3 Requisito: proyecto con Git

pre-commit trabaja con repositorios Git. Si tu proyecto todavía no tiene Git inicializado, puedes ejecutar:

git init

Luego verifica el estado:

git status

23.4 Instalar pre-commit

Activa el entorno virtual del proyecto e instala la herramienta:

python -m pip install pre-commit

Verifica la instalación:

python -m pre_commit --version

El comando usa guion bajo cuando se ejecuta como módulo: python -m pre_commit.

23.5 Crear el archivo de configuración

En la raíz del proyecto crea .pre-commit-config.yaml:

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-toml

Estos hooks revisan detalles básicos: espacios al final de línea, final de archivo, YAML y TOML válidos.

23.6 Instalar los hooks en Git

Ejecuta:

python -m pre_commit install

Desde ese momento, pre-commit se ejecutará automáticamente antes de cada commit.

23.7 Ejecutar pre-commit manualmente

Para probar la configuración en todos los archivos, ejecuta:

python -m pre_commit run --all-files

Si algún hook modifica archivos, revisa los cambios y vuelve a ejecutar el comando.

23.8 Agregar Ruff

Podemos agregar Ruff como hook:

repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.5.0
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

Ruff puede corregir algunos problemas automáticamente y también formatear si decides usar su formateador. Si el proyecto usa Black como formateador principal, puedes omitir ruff-format.

23.9 Agregar Black

Si mantienes Black como formateador, agrega:

repos:
  - repo: https://github.com/psf/black
    rev: 24.4.2
    hooks:
      - id: black

Black usará la configuración de pyproject.toml.

23.10 Agregar isort

Para ordenar imports:

repos:
  - repo: https://github.com/pycqa/isort
    rev: 5.13.2
    hooks:
      - id: isort

isort también leerá su configuración desde pyproject.toml.

23.11 Configuración completa sugerida

Una configuración práctica para ventas_demo puede ser:

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-toml

  - repo: https://github.com/pycqa/isort
    rev: 5.13.2
    hooks:
      - id: isort

  - repo: https://github.com/psf/black
    rev: 24.4.2
    hooks:
      - id: black

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.5.0
    hooks:
      - id: ruff
        args: [--fix]

Las versiones son ejemplos. En un proyecto real conviene revisarlas y actualizarlas de forma controlada.

23.12 Ejecutar mypy con pre-commit

mypy puede ejecutarse como hook local si ya está instalado en el entorno:

repos:
  - repo: local
    hooks:
      - id: mypy
        name: mypy
        entry: python -m mypy src
        language: system
        pass_filenames: false

pass_filenames: false indica que mypy revise src completo, no solo archivos modificados.

23.13 Ejecutar pytest con pre-commit

También puedes ejecutar pruebas como hook local:

repos:
  - repo: local
    hooks:
      - id: pytest
        name: pytest
        entry: python -m pytest
        language: system
        pass_filenames: false

En proyectos grandes, ejecutar toda la suite en cada commit puede ser lento. En ese caso se puede reservar para CI o usar una suite rápida.

23.14 Orden de hooks

Conviene ejecutar primero herramientas que modifican archivos y luego herramientas que revisan.

  • isort ordena imports.
  • Black formatea código.
  • Ruff revisa problemas.
  • mypy revisa tipos.
  • pytest verifica comportamiento.

Si un hook modifica archivos, debes revisar esos cambios y volver a intentar el commit.

23.15 Actualizar hooks

pre-commit puede actualizar versiones de hooks:

python -m pre_commit autoupdate

Después de actualizar, ejecuta:

python -m pre_commit run --all-files

Así verificas que las nuevas versiones no introduzcan cambios inesperados.

23.16 Saltar hooks excepcionalmente

Git permite saltar hooks con --no-verify:

git commit --no-verify -m "mensaje"

Debe usarse solo en casos excepcionales. Si se vuelve costumbre, los controles dejan de cumplir su propósito.

23.17 Documentar el flujo

Agrega al README.md una sección breve:

## Pre-commit

Instalar hooks:

python -m pre_commit install

Ejecutar todos los hooks:

python -m pre_commit run --all-files

La documentación evita que cada integrante tenga que descubrir el flujo por su cuenta.

23.18 Ejercicio guiado

En ventas_demo, realiza estos pasos:

python -m pip install pre-commit
python -m pre_commit install
python -m pre_commit run --all-files

Si aparecen archivos modificados por hooks, revisa los cambios, vuelve a ejecutar pre-commit y luego ejecuta las pruebas.

23.19 Ejercicio propuesto

Configura pre-commit para tu proyecto con estas tareas:

  • Crear .pre-commit-config.yaml.
  • Agregar hooks básicos de pre-commit.
  • Agregar isort, Black y Ruff.
  • Agregar mypy como hook local.
  • Decidir si pytest se ejecutará en cada commit o solo manualmente.
  • Documentar instalación y ejecución en el README.

23.20 Lista de verificación

Antes de continuar, verifica que puedes hacer lo siguiente:

  • Instalar pre-commit.
  • Crear .pre-commit-config.yaml.
  • Instalar hooks en Git.
  • Ejecutar hooks manualmente con --all-files.
  • Combinar hooks de formato, linting, tipos y pruebas.
  • Actualizar hooks de forma controlada.
  • Documentar el flujo para el equipo.

23.21 Conclusión

En este tema automatizamos controles de calidad antes del commit. pre-commit ayuda a detectar problemas temprano y a mantener un estándar consistente sin depender solo de la memoria del programador.

En el próximo tema trabajaremos con logging, mensajes de error y salida por consola con criterio profesional.