/examplelab.png

Integrando git y SugarCRM

author:Lucho Rossi, Hugo Ruscitti
date:Septiembre 2010

Introducción

En la cooperativa usamos git como sistema control de versiones y sugarCRM como bug tracker. Así que nos pareció buena idea integrar las dos herramientas para mejorar el seguimiento de los bugs.

La idea

¿A que nos referimos con integración?, simplemente a la posibilidad de cargar información dentro de sugarcrm escribiendo mensajes en los commits.

En nuestro trabajo diario estamos buscando una metodología que nos resulte cómoda y a la vez productiva.

Estos serían los pasos que tendríamos que seguir para realizar una tarea:

  • Crear bugs definiendo que funcionalidad o arreglo se tiene que realizar.
  • Anotar el número de bug y tenerlo en cuenta mientras trabajamos en el código.
  • Crear commits y ponerles mensajes tipo "corrijo tal cosa del bug #123".
  • Que automáticamente se agreguen notas a los bugs con mensajes de commits.

Actualmente, el último paso no se realiza de forma automática, y por eso queremos integrar las dos herramientas: git y sugarcrm.

La funcionalidad esperada

Quisiéramos que cada commit que se hace a un repositorio git dispare una acción, asociando el mensaje que escribimos en el commit con el bug correspondiente.

Para que este enlace se produzca correctamente, solo haría falta escribir el mensaje del commit respetando una nomenclatura sencilla.

Por ejemplo, los siguientes son mensajes de commits que hacen referencias a bugs:

  • arreglo menor referido al bug #1223.
  • termine el bug fixes #344.
  • cambiando permisos de archivos #134 #23.

Es decir, cuando se escribe #numero esto añade inmediatamente una nota al bug indicado por el número. Y si se usan las palabras fix, fixed o fixes se alterará la resolución del bug para marcarlo como realizado.

Por ejemplo, esta es una nota agregada automáticamente desde un commit:

images/bug.png

Solo fix, no se permite close

Actualmente no se puede cambiar el estado del bug desde los mensajes de commits porque pensamos que sería bueno que el estado se pueda cambiar solamente desde la interfaz de sugarcrm. De esta forma, un bug solo podría estar cerrado si alguien lo verifica y cambia su estado.

La resolución fixed es algo intermedio, una respuesta al bug por parte del programador que dice "solucioné el bug y a mí me anda".

En cambio, el estado closed es el segundo paso, que quisiéramos que sirva de control por otra persona que dice "tomé este bug fixed lo revisé, anda en testing y entonces lo cierto con estado closed".

Así, tendríamos dos roles (que podrían ser la misma persona, no seamos tan estrictos...).

¿Como se realizó?

Tuvimos que hacer dos cambios en las herramientas que usamos: crear un método nuevo en el soap de sugarCRM y colocar hooks en el repositorio de git.

Esta es una visión general de lo que hace el sistema usando un diagrama de secuencia [1]:

images/secuencia.png

Nuevo método de Soap en php

Sugarcrm tiene que recibir un aviso de commit por parte de git, interpretarlo y procesarlo para crear notas o alterar el estado del bug.

Para esto se realizaron dos tareas, crear el método soap para que entienda la llamada desde git y la codificación de ese método para que pueda interpretar los mensajes de commit relacionándolos con bugs.

1 - Creando el Método de soap

Se modificaron los archivos:

  • custom/include/UtilidadesGcoop.php
  • tools/sqlsoap_server.php
  • tools/sqlsoap_server_functions.php

para que sugarcrm publique un nuevo método llamado gitToBug:

images/soap.png

2 - Interpretando mensajes de commit

Para interpretar los mensajes de commits hemos usado una sola función de expresiones regulares de php llamada preg_match_all.

Veamos un ejemplo, si escribimos:

$commit_message = "Esto tiene relacion con el bug #30 y #40";

$pattern = "/#(\d+)/";
preg_match_all($pattern, $commit_message, $out);
$relacionados = $out[1];

Obtenemos un array llamado $relacionados donde figurarán todos los números de commits que se citan en el bug:

>>> print_r($relacionados)

Array
(
    [0] => 30
    [1] => 40
)

Luego para las notas que indican si se repara el bug (fix, fixed etc...) solamente hemos elaborado un poco mas la expresión regular:

$commit_message = "Creando funcion y refactorizando fixes #50";

$pattern = "/(fix|fixed|soluciona|fixes)\s#(\d+)/";
preg_match_all($pattern, $commit_message, $out);
$reparados = $out[2];

>>> print_r($relacionados)

Array
(
    [0] => 50
)

Es decir, cambiamos las expresión regular y solo nos quedamos con lo que está en el segundo grupo $out[2].

Una prueba desde python

En este estado uno puede hacerse un script de python y enviar mensajes a sugarcrm para crear notas:

import suds

url = "http://192.168.10.22/sugarg/tools/sqlsoap_server.php?wsdl"
client = suds.client.Client(url)

response = client.service.gitToBug("", "autor", "", "un commit de prueba fix #1170", "")

Esta llamada creará una nueva nota en el bug 1170 y cambiará el estado a fixed:

images/comentario.png

La idea de hacer esta prueba es corroborar que hasta ahora nos anda...

Hooks del lado de git

El siguiente paso es hacer que git le avise a sugarcrm cada vez que llegue un nuevo commit. Para esto usamos hooks.

Git dispara eventos cada vez que algo ocurre (como un nuevo commit, cuando alguien hace push etc...) y te permite crear hooks para que puedas hacer algo cuando esos eventos ocurran.

Inicialmente, cuando se crea un repositorio git con la opción no-bare se genera un estructura como la siguiente:

branches
config
description
HEAD
hooks
info
objects
refs

El directorio hooks tiene varios scripts que se ejecutan cuando git hace algo.

Estos script tienen nombres significativos, por ejemplo, cada vez que un programador hace push sobre este repositorio se llamará al script hooks/post-receive.

El script se puede hacer en cualquier lenguaje, y los argumentos que recibe son siempre de la forma:

old_rev new_rev ref_name

Lamentablemente por cada push la información que nos da git no es exactamente la que necesitamos... Lo que nos gustaría es obtener los mensajes de cada revisión y no solamente el identificador.

Así que para resolver eso tuvimos que hacer un hook un poco mas elaborado, que obtiene todos los mensajes de los commits y llama a un método de soap remoto para avisar que llegó un commit.

Este es el script que usamos bajo el nombre post-push:

#!/usr/bin/python2.5

import sys
import subprocess
import suds

def get_commit_message(commit_id):
    "Retorna el mensaje de commit completo con los archivos que altera."

    p = subprocess.Popen(['git', 'log', commit_id, '--name-only', '-n', '1',
                            '--pretty=format:%h|%ci|%aN|%s'], stdout=subprocess.PIPE)

    # toma la salida del comando y separa todos los datos en
    # hash, fecha, autor, mensaje y archivos modificados.
    message = p.stdout.read()
    message = message.split("\n")
    message_line = message[0]
    hash, date, author, comment = tuple(message_line.split("|"))
    files = message[1:]

    return hash, date, author, comment, files

def get_commits(old_rev, new_rev):
    p = subprocess.Popen(['git', 'log', '--pretty=format:%H', '--reverse',
                          '%s..%s' % (old_rev, new_rev)],
                         stdout=subprocess.PIPE)
    return p.stdout.read().split('\n')

def parse_post_receive_line(l):
    "separa los delta de versiones en una tupla."
    return l.split()

lines = sys.stdin.readlines()

commits = []

for line in lines:
    old_rev, new_rev, ref_name = parse_post_receive_line(line)
    messages = get_commits(old_rev, new_rev)

    for msg in messages:
        commits.append(msg)

# Se conecta al servidor soap de sugar.
url = "http://WEBSITE_SUGAR.com.ar/tools/sqlsoap_server.php?wsdl"
client = suds.client.Client(url)

# por cada commit identificado le avisa al soap de sugar.
for x in commits:
    hash, date, author, comment, files = get_commit_message(x)
    client.service.gitToBug(hash, date, author, comment.decode('utf8'), '\n'.join(files))

Nota: Usamos una biblioteca llamada suds para poder comunicarnos con el servidor soap de sugarcrm desde python:

sudo easy_install suds

Conclusiones

Mantener integrados los sistemas de tickets y los repositorios de software es muy importante para casi cualquier administrador de proyectos.

Mediante este artículo hemos visto que integrarlo a sugar es posible, aunque no muy sencillo...

[1]Gracias osi por recomendarme ditaa, es una masa para hacer diagramas...