#!/usr/bin/env php . // Copyright © 2007-2014 Erwan Briand // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, version 3 only. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public // License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // Handle args and find SCM if ((!empty($argv[1]) && $argv[1] == '--git') && (!empty($argv[2]) && mb_ereg("^[0-9a-z_-]+$", $argv[2]))) { define('SCM', 'git'); $project = $argv[2]; $prev_rev = $argv[3]; $rev = $argv[4]; } elseif (!empty($argv[1]) && !empty($argv[2])) { define('SCM', 'svn'); $var = explode('/', $argv[1]); $project = $var[ count($var) - 1 ]; $rev = $argv[2]; $prev_rev = $rev - 1; } elseif (!empty($argv[1]) && mb_ereg("^[0-9a-z_-]+$", $argv[1])) { define('SCM', 'hg'); $project = $argv[1]; $node = getenv('HG_NODE'); } else exit('Error.'); // Find were we are $base = dirname(__FILE__); $whereis = '/scripts/miscellaneous'; $length = -mb_strlen($whereis); if (mb_substr($base, $length, mb_strlen($base)) == $whereis) { // Set the CodingTeam basedir $basedir = mb_substr($base, 0, $length); define('CT_BASEDIR', $basedir); require($basedir.'/inc/globalFunctions.php'); // Check if the configuration file exist if (!file_exists($basedir.'/inc/codingteam.cfg')) die ('There are no configuration file. CodingTeam cannot start.'); // Check if the configuration file is well formed $xml = new DomDocument(); $xml->load($basedir.'/inc/codingteam.cfg'); if (!$xml->schemaValidate($basedir.'/inc/codingteam-conf.xsd')) exit('POST-COMMIT HOOK FAILED'); // Import configuration $xml = simplexml_load_file($basedir.'/inc/codingteam.cfg'); $db_type = $xml->db->type; $db_hostname = $xml->db->hostname; $db_database = $xml->db->database; $db_username = $xml->db->username; $db_password = $xml->db->password; date_default_timezone_set($xml->config->timezone); // Database connection require($basedir.'/inc/classes/db.php'); $ct_db = new Database($db_type, $db_hostname, $db_database, $db_username, $db_password); // Project identifier $prj_class = getClass('projects.projects', $ct_db); $prj_obj = $prj_class->load($project, 'dbname'); if ($prj_obj) $prj_id = $prj_class->getId(); else exit('POST-COMMIT HOOK FAILED'); // Get project's dbname $dbname = htmlspecialchars($prj_class->getDbname()); // Get commits information if (SCM == 'svn') { $author = exec(escapeshellcmd('svnlook author '.$argv[1].' -r'.$rev)); $date = exec(escapeshellcmd('svnlook date '.$argv[1].' -r'.$rev)); $datetime = mb_substr($date, 0, 19); $cmd = escapeshellcmd('svnlook log '.$argv[1].' -r'.$rev); ob_start(); passthru($cmd); $log = ob_get_clean(); } elseif (SCM == 'hg') { $path = CT_BASEDIR.'/public/hg/'.$dbname; (int)$rev = exec('hg --cwd '.$path.' log -r '.$node.' -q '. '| head -n 1 | cut -f1 -d\':\''); $prev_rev = ($rev - 1); ob_start(); passthru('hg --cwd '.$path.' log -r '.$rev.' --template \'{rev}\n'. '{author}\n{date|isodate}\n{desc}\n\''); $output = ob_get_clean(); $exp = explode("\n", $output, 4); $author = (string)$exp[1]; $datetime = convertDate((string)$exp[2], 'hg', 'datetime'); $log = (string)$exp[3]; } elseif (SCM == 'git') { $path = CT_BASEDIR.'/public/git/'.$dbname; ob_start(); passthru('cd '.$path.' && git log '.$prev_rev.'..'.$rev); $output = ob_get_clean(); $lines = explode("\n", $output); $author = str_replace('Author: ', '', $lines[1]); $datetime = convertDate(str_replace('Date: ', '', $lines[2]), 'git', 'datetime'); array_pop($lines); for($i=0; $i<4; $i++) array_shift($lines); $log = ''; foreach ($lines as $line) $log .= mb_substr($line, 4)."\n"; } // Construct URL $url = 'project/'.$dbname.'/browse/diff/'.$prev_rev.'/'.$rev; // Get user identifier if (SCM == 'svn') $user = getUser($author, $ct_db, 'nickname'); elseif (SCM == 'hg' || SCM == 'git') $user = getDVCSUser($author, $ct_db); if ($user) { $user_id = $user->getId(); // Advanced hook $lines = explode("\n", $log); foreach ($lines as $line) { if (mb_eregi('.*fixe[d|s] #([0-9]+).*', $line, $ret)) if (isset($ret[1])) { $bugid = $ret[1]; // Get the bug $bug_class = getClass('project.bugs', $ct_db); $bug_obj = $bug_class->load_by_project($bugid, $prj_id); if ($bug_obj && $bug_class->getProjectid() == $prj_id) { // Add a comment to the bug $title = 'Fixed by r'.$rev; $text = 'This bug was fixed by the commit '. 'r'.$rev.'. This is an '. 'automatic fix.'; $date = date('Y-m-d H:i:s'); $lastid = $bug_class->addAnswer(array( 'bugid' => $bug_class->getId(), 'name' => $title, 'text' => $text, 'allow_nl2br' => TRUE, 'unregistered_nick' => '', 'registered_id' => $user_id, 'author_ip' => '', 'datetime' => $date)); // Update bug's log $values = array(); array_push($values, array('bugid' => $bug_class->getId())); array_push($values, array('projectid' => $prj_id)); array_push($values, array('unregistered_nick' => '')); array_push($values, array('registered_id' => $user_id)); array_push($values, array('author_ip' => '')); array_push($values, array('datetime' => $date)); array_push($values, array('milestone' => '!nochange!')); array_push($values, array('version' => '!nochange!')); array_push($values, array('priority' => '!nochange!')); array_push($values, array('type' => '!nochange!')); array_push($values, array('status' => 'resolved')); array_push($values, array('assignedid' => 0)); array_push($values, array('attachement' => 0)); array_push($values, array('answer' => $lastid)); foreach ($values as $key) foreach ($key as $key => $value) $logentry[$key] = $value; $bug_class->addLog($logentry); $bu = '/project/'.$dbname; deleteCacheVersion($bu.'/bugs/show/'.$bug_class->getId()); deleteCacheVersion($bu.'/timeline', TRUE); // Close the bug (with status: resolved) $bug_class->setStatus('resolved'); } } if (mb_eregi('.*reference[d|s]? #([0-9]+).*', $line, $ret)) if (isset($ret[1])) { $bugid = $ret[1]; // Get the bug $bug_class = getClass('project.bugs', $ct_db); $bug_obj = $bug_class->load_by_project($bugid, $prj_id); if ($bug_obj && $bug_class->getProjectid() == $prj_id) { // Add a comment to the bug $title = 'Commit reference: r'.$rev; $text = 'This bug was referenced by the commit '. 'r'.$rev.'.'; $date = date('Y-m-d H:i:s'); $lastid = $bug_class->addAnswer(array( 'bugid' => $bug_class->getId(), 'name' => $title, 'text' => $text, 'allow_nl2br' => TRUE, 'unregistered_nick' => '', 'registered_id' => $user_id, 'author_ip' => '', 'datetime' => $date)); // Add the answer to the log $values = array(); array_push($values, array('bugid' => $bug_class->getId())); array_push($values, array('projectid' => $prj_id)); array_push($values, array('unregistered_nick' => '')); array_push($values, array('registered_id' => $user_id)); array_push($values, array('author_ip' => '')); array_push($values, array('datetime' => $date)); array_push($values, array('milestone' => '!nochange!')); array_push($values, array('version' => '!nochange!')); array_push($values, array('priority' => '!nochange!')); array_push($values, array('type' => '!nochange!')); array_push($values, array('status' => '!nochange!')); array_push($values, array('assignedid' => 0)); array_push($values, array('attachement' => 0)); array_push($values, array('answer' => $lastid)); foreach ($values as $key) foreach ($key as $key => $value) $logentry[$key] = $value; $bug_class->addLog($logentry); $bu = '/project/'.$dbname; deleteCacheVersion($bu.'/bugs/show/'.$bug_class->getId()); deleteCacheVersion($bu.'/timeline', TRUE); } } } } $cmt_class = getClass('projects.commits', $ct_db); $cmt_class->push($prj_id, $rev, $prev_rev, $log, $author, $datetime); // Delete cache for source code browser deleteCacheVersion('/project/'.$project.'/browse', TRUE); deleteCacheVersion('/project/'.$project.'/timeline', TRUE); deleteCacheVersion('/index'); } ?>