🚀 Automatiza tu Linter PHP con Git y PHP-CS-Fixer
🚀 Manos a la obra
Primero vamos a ver que linter vamos a usar para automatizarlo con los git hooks. Usaremos php-cs-fixer! 🚀
🛠️ Explorando PHP-CS-Fixer: Tu Compañero en la Búsqueda de Código Impecable
Buena pregunta. PHP-CS-FIXER es una herramienta para arreglar o avisarte de algún error en tu código según los estándares definidos en los PSR de php.
Todos sabemos que seguir los estándares sin un linter es difícil, pero con un linter se vuelve una faena tediosa, ya que tenemos que estar todo el rato arreglando los errores que nos marca va marcando…
Precisamente por eso, en mi trabajo tenemos una pipeline por la que pasan todos los merge-request o pull-request, depende de la plataforma que uses, por la cual hay un job que se encarga de pasar el linter para comprobar que el código a mergear cumple los estándares.
Pues como bien podréis imaginar, si sois un poco olvidadizos como yo o estáis muy centrados en solucionar la tarea que estáis a punto de pushear, se os puede pasar algún error o warning del linter, y al final nos quedan toda la branch llena de commits como lint fixes 🤣
Aquí entra este paquete de php, php-cs-fixer, el cual nos analiza el código y arregla los errores o warnings que nos marcaría el lintern. Una maravilla! Pero oooppsss!! Si se nos olvida ejecutarlo antes de commitear estaremos en la misma situación 😥
Aquí entra el pre-commit hook! 🎉
🪝 Descubre los Git Hooks
Los git hooks son shell scripts que se ejecutan en determinado momento, en nuestro caso, queremos que se ejecute antes de hacer un commit, por lo que usaremos el hook de pre-commit.
🚀 ¡Mi primer git hook en Acción!
Para mí este ha sido mi primer git hook, no sé si para vosotros también, pero no temáis, es más fácil de lo que parece.
🧐 ¿Dónde debo crear mi git hook?
En nuestro proyecto si lo tenemos inicializado con git, tendremos una carpeta oculta .git.
En ciertos IDE o editores, por defecto los directorios ocultos no aparecen en la barra de directorios, pero que no cunda el pánico! Hay varias maneras de poder entrar en ese directorio 😉
Normalmente en las preferencias de los IDE’s/editores hay unos directorios ignorados, buscad por preferencias y os aparecerá rápido, solo tenemos que borrar de la lista el directorio .git.
Si no siempre podemos usar el terminal, en sistemas como macOS o distribuciones linux, solo tendremos que hacer un ls -a para listar los directorios ocultos, una vez estemos en el directorio que contiene el directorio .git podemos hacer cd .git y estaremos dentro.
Una vez dentro del directorio .git vemos que existe una carpeta llamado hooks. Si miramos dentro tendremos un montón de ficheros de ejemplo.
Aquí es donde empezará la mágia 🧙🏼
🚀 ¡Mi primer git hook en Acción!
Una vez localizada el directorio .git/hooks podemos crear en su interior un nuevo fichero llamado pre-commit.
En el fichero tendremos que copiar el siguiente código:
#!/bin/sh
ROOT="laravel"
echo "php-cs-fixer pre commit hook start"
PHP_CS_FIXER="laravel/vendor/bin/php-cs-fixer"
HAS_PHP_CS_FIXER=false
CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM -- '.php')
PHP_CS_CONFIG="laravel/.php_cs"\n
if [ -x laravel/vendor/bin/php-cs-fixer ]; then
HAS_PHP_CS_FIXER=true
fi\n
if $HAS_PHP_CS_FIXER; then
git status --porcelain | grep -e '^[AM]\(.\).php$' | cut -c 3- | while read line; do
$PHP_CS_FIXER fix --allow-risky=yes --config "$PHP_CS_CONFIG" $CHANGED_FILES;
git add "$line";
done
else
echo ""
echo "Please install php-cs-fixer"
echo ""
fi\n
echo "php-cs-fixer pre commit hook finish"
Tranquilos si no entendéis nada, ahora explicaré paso por paso qué hace cada linea!
Al final los hooks son scripts escritos en bash, si queréis saber más sobre bash visitar el siguiente link.
Todos los scripts en bash empiezan por
#!/bin/sh
así el sistema operativo reconoce que es un script escrito en bash.
ROOT="laravel"
En esta línea solo estamos definiendo una variable llamada ROOT que contiene el el path al directorio root que queremos analizar con el php-cs-fixer.
En esta línea solo estamos definiendo una variable llamada ROOT que contiene el el path al directorio root que queremos analizar con el php-cs-fixer.
El comando echo en bash es para imprimir por pantalla, por lo tanto
echo "php-cs-fixer pre commit hook start"
simplemente imprime por pantalla que esta empezando a ejecutarse el pre-commit.
PHP_CS_FIXER="laravel/vendor/bin/php-cs-fixer"
Aquí guardaos en la variable PHP_CS_FIXER el path donde esta el binario del php-cs-fixer, en mi caso en la carpeta laravel/vendor/bin/php-cs-fixer.
HAS_PHP_CS_FIXER=false
A continuación creamos una variable que guarda un booleano para saber si tenemos instalado el php-cs-fixer o no. La inicializamos en false y más adelante comprobaremos si esta instalado y lo cambiaremos a true o lo dejaremos como esta, dependiendo de la comprobación.
CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM -- '.php')
Seguidamente creamos una variable que guardará los archivos que han sido modificados y que se van a commitear. En este caso solo los que terminen con la extension .php ya que es los que queremos analizar en este pre-commit.
PHP_CS_CONFIG="laravel/.php_cs"
php-cs-fixer deja personalizar ciertas cosas en un fichero llamado .php_cs, por lo que aquí estamos guardando el path hacia ese fichero para más adelante decirle que use nuestra configuración.
if [ -x laravel/vendor/bin/php-cs-fixer ]; then
HAS_PHP_CS_FIXER=true
fi
Llega el momento de hacer la comprobación! Con el -x comprobamos si el ejecutable que le indicamos existe en el path que hemos indicado también. En este caso comprueba que el ejecutable php-cs-fixer exista en el path laravel/vendor/bin y si es así cambia el valor de la variable HAS_PHP_CS_FIXER a true.
if $HAS_PHP_CS_FIXER; then
git status --porcelain | grep -e '^[AM]\(.\).php$' | cut -c 3- | while read line; do
$PHP_CS_FIXER fix --allow-risky=yes --config "$PHP_CS_CONFIG" $CHANGED_FILES;
git add "$line";
done
Seguidamente si existe el ejcutable del php-cs-fixer, vemos todos los ficheros que están en el commit acabados en .php y los recorremos en un bucle.
Dentro del bucle, ejecutamos el php-cs-fixer indicandole nuestro fichero de configuración propio y los ficheros a modificados que queremos commitear.
Cada vez que se modifica un fichero por el php-cs-fixer lo añadimos a git con el commando git add y el fichero. Como este hook es de pre-commit estos cambios al haber hecho el add se sumarán al commit automáticamente.
El resto de lineas son solo prints, en los que indicamos que se instale el php-cs-fixer si no lo tenemos instalado y el último para indicar que el hook ha terminado.
😁 Y llegamos al final
En el día a día hay tareas pequeñas en las que perdemos x tiempo y a veces es tan fácil automatizarlas y ahorrar ese tiempo que vale mucho la pena.
Además como programadores nos encanta automatizar!
Espero que os resulte útil y empecéis a averiguar más utilidades de los hooks de git para haceros cada día el trabajo un pelin más fácil 😁