Bug / Issue Tracker + Subversion


El twbsdbt nombrado en un post anterior, ademas de hacer basicamente lo mismo que mantis, es mas bonito y tambien es facil integrarlo con Subversion para que cambie el estado de los tickets de acuerdo con el comentario realizado en un commit de Subversion, como no encontre una solucion en la Web, decidi probar nuevamente con mis limitados conocimientos de PHP y obviamente parandome sobre hombros de gigantes (el propio mantis (/path/to/mantis/core/checkin.php) y twbsd bt (/path/to/bugtracker/feedback/feedback_report_update.php ).

La idea es la misma que describe la integracion de mantis y subversion:

  • Hacer un script php que se pueda llamar desde consola que basado en expresiones regulares encuentre el proyecto y actualice los bugs nombrados en el comentario
  • Luego de actualizar el estado y los comentarios sobre los bugs envie un correo electronico al usuario que registro el bug con las actualizaciones realizadas
  • Hacer un script en el repositorio de subversion que obtenga los datos del commit (fecha, usuario, archivos modificados, comentario) y usando esos datos como parametro ejecute el script de php

Luego de algun tiempo de cacharreo mi script de php que busca y actualiza el estado de los bugs es este:

<?php
include("/path/to/bugtracker//include/db.php");
include("/path/to/bugtracker//include/user_function.php");
include("/path/to/bugtracker//include/project_function.php");
include("/path/to/bugtracker//include/customer_function.php");
include("/path/to/bugtracker//include/feedback_email_function.php");
include("/path/to/bugtracker//include/misc.php");

# Make sure this script doesn't run via the webserver
# @@@ This is a hack to detect php-cgi, there must be a better way.
if ( isset( $_SERVER&#91;'SERVER_PORT'&#93; ) ) {
	echo "checkin.php is not allowed to run through the webserver.\n";
	exit( 1 );
}

# Check that the username is set and exists
$t_username = "SVN";

if ( !defined( "STDIN" ) ) {
	define("STDIN", fopen('php://stdin','r'));
}

# Detect references to issues + concat all lines to have the comment log.
$t_commit_regexp = '/\b(?:bug|issue)\s*&#91;#&#93;{0,1}(\d+)\b/i';
$t_commit_fixed_regexp = '/\bfix(?:ed|es)\s+(?:bug|issue)?\s*&#91;#&#93;{0,1}(\d+)\b/i';
$t_proj_regexp = '/\b(?:proyecto)\s*(\w+)\b/i';

$t_comment = '';
$t_projects = array();
$t_issues = array();
$t_fixed_issues = array();
while ( ( $t_line = fgets( STDIN, 1024 ) ) ) {
	$t_comment .= $t_line;
	if ( preg_match_all( $t_commit_regexp, $t_line, $t_matches ) ) {
		for ( $i = 0; $i < count( $t_matches&#91;0&#93; ); ++$i ) {
			$t_issues&#91;&#93; = $t_matches&#91;1&#93;&#91;$i&#93;;
		}
	}

	if ( preg_match_all( $t_commit_fixed_regexp, $t_line, $t_matches) ) {
		for ( $i = 0; $i < count( $t_matches&#91;0&#93; ); ++$i ) {
			$t_fixed_issues&#91;&#93; = $t_matches&#91;1&#93;&#91;$i&#93;;
		}
	}

	if ( preg_match_all( $t_proj_regexp, $t_line, $t_matches) ) {
		for ( $i = 0; $i < count( $t_matches&#91;0&#93; ); ++$i ) {
			$t_projects&#91;&#93; = $t_matches&#91;1&#93;&#91;$i&#93;;
		}
	}
}

# Si no se encuentra el nombre del proyecto
if ( $t_projects&#91;0&#93; == '' ) {
	echo "Comment does not reference any project.\n";
	exit(0);
}

# If no issues found, then no work to do.
if ( ( count( $t_issues ) == 0 ) && ( count( $t_fixed_issues ) == 0 ) ) {
	echo "Comment does not reference any issues.\n";
	exit(0);
}

//Busca el id de proyecto a partir del nombre
$project_sql = "select * from ".$GLOBALS&#91;'BR_project_table'&#93;." where project_name='".$t_projects&#91;0&#93;."'";
$project_result = $GLOBALS&#91;'connection'&#93;->Execute($project_sql) or DBError(__FILE__.":".__LINE__);
$line = $project_result->Recordcount();
//en caso de no obtener resultados imprime un mensaje de error
if ($line != 1) {
	echo "NO EXISTE EL PROYECTO: ", $t_projects[0], "\n";
	exit(0);
}
$project_id = $project_result->fields["project_id"];

# add note to each bug only once
$t_issues = array_unique( $t_issues );
$t_fixed_issues = array_unique( $t_fixed_issues );

# Call the custom function to register the checkin on each issue.
$new_status = "2"; // In progress
foreach ( $t_issues as $t_issue_id ) {
	if ( !in_array( $t_issue_id, $t_fixed_issues ) ) {
		update_issue($project_id, $t_issue_id, $t_comment, $new_status);
	}
}

$new_status = "4"; // Closed
foreach ( $t_fixed_issues as $t_issue_id ) {
	update_issue($project_id, $t_issue_id, $t_comment, $new_status);
}

//Funcion de actualizacion de estado y actualizacion de comentarios
function update_issue($proj_id, $issue_id, $comment, $status){
	$update_report_sql = "update proj".$proj_id."_feedback_table set
		status='$status'
		where report_id='".$issue_id."'";

	$now = $GLOBALS['connection']->DBTimeStamp(time());
	$new_log_sql = "insert into proj".$proj_id."_feedback_content_table (
		report_id, internal_user_id, post_time, description) values(
			'".$issue_id."', 'Subversion', ".$now.", '".$comment."');";

	$GLOBALS['connection']->StartTrans();
	$GLOBALS['connection']->Execute($update_report_sql) or DBError(__FILE__.":".__LINE__);
	$GLOBALS['connection']->Execute($new_log_sql) or DBError(__FILE__.":".__LINE__);
	$GLOBALS['connection']->CompleteTrans();

	//envia un email notificando los cambios
	SendFeedbackReportEmail($proj_id, $issue_id, "");
}

exit( 0 );

Sucede que en Twbsdbt necesitamos dos parametros normalmente para acceder a un reporte de bug: el numero de proyecto y el numero de bug, pero como es mas facil para un desarrollador mantener en mente el nombre del proyecto, entonces en la actualizacion mediante subversion usamos una expresion regular para obtenerlo y a partir de el obtener el id de proyecto, las expresiones regulares se basan obviamente en las elaboradas por Tom:

Para actualizar un bug al estado “In progress”: $t_commit_regexp = ‘/\b(?:bug|issue)\s*[#]{0,1}(\d+)\b/i’;
Para actualizar un bug al estado “Closed”: $t_commit_fixed_regexp = ‘/\bfix(?:ed|es)\s+(?:bug|issue)?\s*[#]{0,1}(\d+)\b/i’;
Para obtener el nombre del proyecto: $t_proj_regexp = ‘/\b(?:proyecto)\s*(\w+)\b/i’;

el script se copia en la carpeta /path/to/bugtracker/feedback/ y necesita permisos de ejecucion para el usuario apache (generalemente usuario www-data) para probar que funciona podemos ejecutar desde consola algo como esto:


php -q <<< "En el Proyecto treadstone se estan arreglando el bug #2 bug #4 y bug #7 mediante la recodificacion del proyecto orientandolo a objetos"

o algo como esto para cerrar los bugs:

php -q <<< "En el Proyecto treadstone la recodificacion del proyecto orientandolo a objetos fixed bug #2 fixed bug#4 fixed bug #7"

Lo que deberia actualizar el estado de los 3 bugs mencionados en el proyecto ‘treadstone’ con el comentario completo. Ahora el script de subversion de debe localizar en /path/to/repos/hooks/ y llamarse post-commit con permisos de ejecucion para el usuario apache (www-data), el contenido es modificado a partir del descrito por Tom:

#!/bin/bash

REPOS=”$1″
REV=”$2″

auth=$(svnlook author -r $REV $REPOS)
dt=$(svnlook date -r $REV $REPOS)
changed=$(svnlook changed -r $REV $REPOS)
log=$(svnlook log -r $REV $REPOS)
n=$’\n’
/usr/bin/php -q /path/to/bugtracker/feedback/feedback_svn.php <<< "Revision [${REV}] by $auth, $dt$n$log$n$changed" [/sourcecode] Felizmente ahora tenemos un bug tracker mas bonito que mantis integrado de forma sencilla con subversion, lo cual ahorra trabajo para todos.

Acerca de Nickman

Aunque crítico e Ingeniero (especializado en software), piloto de aeroplano soy (seré).

Un pensamiento en “Bug / Issue Tracker + Subversion

  1. Pingback: Bug / Issue Tracker + Subversion | PHP-Blog.com

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s