Git - [solucionado] Crear un sencillo hook para verificar la sintaxis de los archivos

 
Vista:
Imágen de perfil de kip
Val: 22
Ha mantenido su posición en Git (en relación al último mes)
Gráfica de Git

[solucionado] Crear un sencillo hook para verificar la sintaxis de los archivos

Publicado por kip (6 intervenciones) el 12/09/2017 04:27:35
Hola, Git proporciona de varios hooks(https://es.wikipedia.org/wiki/Hooking) para poder alterar el comportamiento de ciertos eventos a nuestro beneficio, en este caso mostrare como usar uno de estos para realizar un checkeo simple de la sintaxis del código y de esa forma poder cancelar el commit si es que algunos de los scripts en en el staging area no pasan esta prueba.

Tenemos dos archivos PHP simples:
1
2
3
4
./main.php
 
./carpeta:
'main 2.php'

En cada uno de ellos tengo lo siguiente:

1
2
3
4
5
$ cat main.php
<?php
 
$var = 1;
echo $var;

1
2
3
4
5
$ cat carpeta/main\ 2.php
<?php
 
$var = 1;
echo $var;

Podemos ver el log del repositorio:
1
2
3
4
5
6
$ git log
commit ****bc1a033d4e6f67f7a9a1d6a9dfa0d29e104c
Author: KIP <---->
Date:   Mon Sep 11 23:05:38 2017 -0300
 
    Primer commit

Ahora intentemos hacer un cambio con mala sintaxis en uno de los archivos PHP, por ejemplo no coloquemos el ;

1
2
3
4
5
<?php
 
$var = 1;
echo $var;
echo 'Final !'

Vemos que nos marca el archivo que ha sido modificado:

1
2
3
4
5
6
7
8
9
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
 
        modified:   main.php
 
no changes added to commit (use "git add" and/or "git commit -a")

Ahora intentemos aplicar el cambio junto con un mensaje de commit:
Screenshot_583

Me ha mostrado un mensaje y me ha cancelado el commit !

Git, como dije al inicio, te da la oportunidad de ejecutar código en ciertos eventos, los posibles eventos en los que podemos correr algún código son:

1
2
3
4
5
6
7
8
9
applypatch-msg
pre-push
commit-msg
pre-rebase
post-update
prepare-commit-msg
pre-applypatch
update
pre-commit

En este caso ejecutamos el código de checkeo de sintaxis en el evento pre-commit, que como su nombre lo indice se ejecuta antes de realizar un commit, dandote la oportunidad de poderlo cancelar.

Pero donde estan localizados o donde colocaremos el codigo para que Git lo ejecute en algun evento ?
Para que Git corra el codigo que desees debes acceder a la carpeta hooks dentro de la carpeta base de git en tu repositorio que es .git/

1
2
3
4
5
6
7
8
9
10
11
$ ls -1 .git/
COMMIT_EDITMSG
config
description
HEAD
hooks/ <--- AQUI !
index
info/
logs/
objects/
refs/

Y dentro de hooks podemos ver ejemplos de codigo de cada evento que te ofrece Git como guia:

1
2
3
4
5
6
7
8
9
10
11
$ ls -1 .git/hooks/
applypatch-msg.sample
commit-msg.sample
post-update.sample
pre-applypatch.sample
pre-commit.sample
prepare-commit-msg.sample
pre-push.sample
pre-rebase.sample
pre-receive.sample
update.sample

Si nos damos cuenta tiene el .sample, debemos saber que Git solo reconocera el archivo a ejecutar si este se llama tal como el evento sin el sample, por ejemplo para que Git ejecute algun codigo en el evento pre-commit deberemos crear un archivo con ese nombre y dentro de el colocar el codigo que quieras.

Debemos saber que dentro de este archivo, o estos archivos, podemos colocar código en cualquier lenguaje !! Solo debemos tener en cuenta de que el sistema pueda ejecutar este(puedes usar COBOL si quieres), en nuestro ejemplo usare bash y python, veamos como seria en bash un checkeo de sintaxis simple:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
 
oIFS="$IFS"
IFS=$'\n'
RED='\033[1;31m'
GREEN='\033[1;32m'
NC='\033[0m'
files=($(git diff --cached --name-only))
errors=()
 
for f in ${files[@]}
do
    errors+=($(php -l "$f" | grep -v "No syntax errors detected"))
done
 
IFS="$oIFS"
 
if [ ${#errors[@]} -eq 0 ]
then
    printf "${GREEN}Sintaxis correcta !${NC}"
    exit 0;
else
    printf "${RED}No es posible realizar el commit por error de sintaxis !${NC}\n\n"
    printf "%s\n" "${errors[@]}"
    exit 1;
fi
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
1
Responder
Imágen de perfil de kip
Val: 22
Ha mantenido su posición en Git (en relación al último mes)
Gráfica de Git

[solucionado] Crear un sencillo hook para verificar la sintaxis de los archivos

Publicado por kip (6 intervenciones) el 12/09/2017 04:52:38
CONTINUACIÓN:

No importa si no entiendes el código, debes tener claro solo 2 cosas muy importantes:

1era:
Para poder tomar los archivos con cambios o modificados puedes usar la linea
1
git diff --cached --name-only
Es posible usar alguna otra, pero esta es la mas simple que he encontrado para hacerlo.

2da:
En el evento pre-commit para poder cancelarlo se debe finalizar el script enviando un entero diferente de cero, recomiendo usar el 1, como se puede ver en el codigo:
1
exit 1;

En el caso de checkeo de sintaxis he usado el propio PHP que provee a traves de la linea de comandos(igual que muchos otros lenguajes) un 'syntax checker' (http://php.net/manual/es/features.commandline.options.php).

Veamos ahora como podemos usar Python para realizar la misma tarea:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import re
from sys import exit
from subprocess import check_output, CalledProcessError
 
RED = '\033[1;31m'
GREEN = '\033[1;32m'
NC = '\033[0m'
commandChecker = 'php -l "%s"'
 
files = check_output('git diff --cached --name-only').strip()
errors = []
 
for file in re.split(r'\n', files):
    try:
        if not file.strip():
            continue
        check_output(commandChecker % file)
    except CalledProcessError, e:
        errors += [e.output]
 
if errors:
    print '%sNo es posible realizar el commit por error de sintaxis !%s' % (RED, NC)
    print '%s' % ''.join(errors)
    exit(1)
 
print '%sSintaxis correcta !%s' % (GREEN, NC)
exit(0)

Como puede verse, es parecido, siempre mantengo la mismas bases de uso de las dos cosas importantes que mencione anteriormente.

Bien, ahora intentemos corregir el error colocando el ; y veamos que sucede:

Screenshot_584

Me muestra un mensaje diciendome que la sintaxis es correcta y mas abajo detalles del commit realizado, podemos verificarlo con git log:

1
2
3
4
5
6
7
8
9
10
11
12
$ git log
commit ****ab667514962b1436603d1e4f3661255a19b
Author: KIP <--->
Date:   Mon Sep 11 23:49:40 2017 -0300
 
    Pasara la prueba ?
 
commit ****bc1a033d4e6f67f7a9a1d6a9dfa0d29e104c
Author: KIP <--->
Date:   Mon Sep 11 23:05:38 2017 -0300
 
    Primer commit

Se debe tener cuidado con nombres de archivos con acentos, espacios o algun formato fuera del estandar, ya que tendras problemas al intentar obtenerlos para luego realizar cualquier cosa con ellos, recomiendo usar el estilo camelCase o snake_case, en mi ejemplo he colocado un archivo fuera del estandar para probar y con ambos codigos anteriores funciona muy bien, veamos:

1
2
3
4
5
6
7
8
9
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
 
        modified:   carpeta/main 2.php
 
no changes added to commit (use "git add" and/or "git commit -a")

Screenshot_585

Luego puedo añadir el ; y podra realizarse el commit.

Si no funciona el comando

1
git diff --cached --name-only

Pueden usar:

1
git diff HEAD --name-only

Este tema fue inspirado por Xve y su post de checkeo de sintaxis http://www.lawebdelprogramador.com/foros/PHP/1621143-solucionado-Check-de-sintaxis-en-todos-nuestros-archivos-PHP-desde-la-linea-de-comandos-en-linux.html.

Enlace de interes:
https://www.atlassian.com/git/tutorials/git-hooks
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
Imágen de perfil de xve
Val: 47
Ha mantenido su posición en Git (en relación al último mes)
Gráfica de Git

[solucionado] Crear un sencillo hook para verificar la sintaxis de los archivos

Publicado por xve (18 intervenciones) el 12/09/2017 08:43:43
IMPRESIONANTE Kip!!!!

Muy útil... ya he aplicado la solución de bash a mis proyectos git!!!
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar