# Regla: Hooks de Pre-commit y CI — PHP / Laravel

Los hooks automatizan la detección de errores antes de que lleguen al repositorio.
Esta regla define qué verificaciones correr en qué momento y qué debe bloquear
el commit o el merge.

---

## PHP-CS-Fixer / Pint — verificación de formato

Ejecutar antes de cada commit como verificación sin modificar:

```bash
# Laravel Pint
./vendor/bin/pint --test

# PHP-CS-Fixer
./vendor/bin/php-cs-fixer fix --dry-run --diff
```

- Si produce diferencias: **bloquear el commit**.
- El desarrollador aplica el fix y vuelve a commitear:
  ```bash
  ./vendor/bin/pint     # aplica correcciones
  git add -u && git commit
  ```
- CI también lo ejecuta como verificación. No se auto-corrige en CI.

---

## PHPStan — análisis estático antes de merge

```bash
./vendor/bin/phpstan analyse --level=6 app/ --error-format=github
```

- Ejecutar en CI en cada push a una rama con PR abierto.
- Bloquear el merge si hay errores de nivel 6 o superior.
- Los warnings se tratan como errores: `--no-progress --error-format=github`.
- El flag `--error-format=github` genera anotaciones en la UI de GitHub Actions.

---

## Detección de debug output en código no-test

Detectar `var_dump`, `dd`, `dump`, `print_r`, `var_export` fuera de `tests/`:

```bash
# En hook pre-commit o CI
git diff --cached --name-only | grep '\.php$' | xargs grep -n \
  '\bvar_dump\b\|\bdd\b\|\bdump\b\|\bprint_r\b\|\bvar_export\b' \
  2>/dev/null | grep -v '^tests/' | grep -v '^vendor/'
```

Si encuentra coincidencias en código fuera de `tests/`: **bloquear el commit**.
Los desarrolladores deben eliminar el debug output antes de commitear.

---

## Detección de env() fuera de config/

En Laravel, llamar `env()` directamente en código de aplicación (fuera de `config/`)
rompe el caché de configuración (`php artisan config:cache`):

```bash
# Detectar env() fuera de config/
grep -rn "env(" app/ bootstrap/ routes/ 2>/dev/null \
  | grep -v "config(" \
  | grep -v "^.*#"
```

- Si encuentra `env()` en `app/` o `routes/`: **bloquear el merge** con mensaje:
  "Usar `config('seccion.clave')` en lugar de `env()` fuera de `config/`."

---

## composer audit — vulnerabilidades en dependencias

```bash
composer audit --no-dev --format=json
```

- Ejecutar en CI en cada push.
- Bloquear el merge si reporta vulnerabilidades de severidad **HIGH** o **CRITICAL**.
- Vulnerabilidades **MEDIUM** generan warning pero no bloquean (registrar en JIRA).
- Ejecutar también semanalmente de forma programada para detectar CVEs nuevos
  en dependencias que no cambiaron recientemente.

---

## Verificación de rutas con artisan

En CI, después de cada cambio en `routes/`:

```bash
php artisan route:list --json > /dev/null
```

- Si falla: hay una ruta con controller o middleware inexistente. **Bloquear el merge**.
- Verificación adicional que el middleware de autenticación está presente en rutas de API:

```bash
php artisan route:list --path=api --columns=method,uri,middleware \
  | grep -v "api/auth" \
  | grep -v "sanctum\|auth"
```

Cualquier ruta de API sin middleware de autenticación es una alerta que debe
revisarse manualmente antes de aprobar el PR.

---

## Script de pre-commit completo (referencia)

Guardar como `.git/hooks/pre-commit` o con `husky`/`captain-hook`:

```bash
#!/usr/bin/env bash
set -e

echo "==> Verificando formato (Pint)..."
./vendor/bin/pint --test || {
  echo "ERROR: Hay errores de formato. Ejecuta ./vendor/bin/pint para corregir."
  exit 1
}

echo "==> Detectando debug output..."
ARCHIVOS_PHP=$(git diff --cached --name-only | grep '\.php$' | grep -v '^tests/' || true)
if [ -n "$ARCHIVOS_PHP" ]; then
  if echo "$ARCHIVOS_PHP" | xargs grep -ln '\bvar_dump\b\|\bdd(\b\|\bdump(\b' 2>/dev/null; then
    echo "ERROR: Eliminar var_dump/dd/dump antes de commitear."
    exit 1
  fi
fi

echo "==> Verificando env() fuera de config/..."
if grep -rn "env(" app/ routes/ 2>/dev/null | grep -qv "config("; then
  echo "ADVERTENCIA: Se encontró env() fuera de config/. Verificar manualmente."
fi

echo "==> Pre-commit: OK"
```

---

## Resumen de qué bloquea qué

| Verificación | Pre-commit | CI / PR | Severidad |
|-------------|-----------|---------|-----------|
| Formato (Pint) | Bloquea | Bloquea | Error |
| PHPStan nivel 6 | No | Bloquea merge | Error |
| var_dump / dd / dump | Bloquea | Bloquea | Error |
| `env()` fuera de config/ | Advertencia | Bloquea merge | Error |
| `composer audit` HIGH/CRITICAL | No | Bloquea merge | Error |
| Rutas inválidas | No | Bloquea merge | Error |

---

## Checklist de hooks antes de activar en un proyecto nuevo

- [ ] `pint.json` o `.php-cs-fixer.php` versionado en el repositorio
- [ ] `phpstan.neon` con nivel 6 versionado
- [ ] Hook pre-commit instalado (`./vendor/bin/captain-hook install` o `husky`)
- [ ] Pipeline de CI tiene los pasos: pint, phpstan, audit, route:list
- [ ] El equipo conoce cómo ejecutar cada verificación localmente
