Skip to content

Instantly share code, notes, and snippets.

@tbonfort
Created June 20, 2012 13:09
Show Gist options
  • Save tbonfort/2959820 to your computer and use it in GitHub Desktop.
Save tbonfort/2959820 to your computer and use it in GitHub Desktop.
<?php
/**
*
* highly modified for mapserver import
* orig author Vladimir Sibirov
*/
// Edit configuration below
$username = 'mapserver-trac-importer';
$password = 'XXX';
$project = 'mapserver';
$repo = 'mapserver';
$mysqlhost_trac = 'localhost';
$mysqluser_trac = 'trac';
$mysqlpassword_trac = 'trac';
$mysqldb_trac = 'trac';
// All users must be valid github logins!
$users_list = array(
'tbonfort' => 'tbonfort',
'hobu' => 'hobu',
'aboudreault' => 'aboudreault',
'sdlime' => 'sdlime',
'tamas' => 'szekerest',
'tomkralidis' => 'tomkralidis',
'jmckenna' => 'jmckenna',
'assefa' => 'assefay',
'pramsey' => 'pramsey',
'unicoletti' => 'unicolet',
'warmerdam' => 'warmerdam',
'schpidi' => 'schpidi',
'dmorissette' => 'dmorissette'
);
//$users_list = array();
//github_add_collaborators();
$component_filter="1 = 1 ";
//$component_filter="component like 'Doc%'";
// Do not convert milestones at this run
$skip_milestones = true;
$skip_components = true;
$skip_attachments = true;
$skip_resolution = true;
$skip_version = true;
$skip_assignee = false;
// Do not convert tickets
$skip_tickets = true;
$ticket_min = 0;
$ticket_max = 5000;
// Paths to milestone/ticket cache if you run it multiple times with skip/offset
$save_milestones = '/tmp/trac_milestones.list';
$save_tickets = '/tmp/trac_tickets.list';
$dateformat = 'Y/m/d - H:i';
// Uncomment to refresh cache
// @unlink($save_milestones);
// @unlink($save_tickets);
// DO NOT EDIT BELOW
$svn2gitorig = array();
$svn2gitms = array();
$svn2gitdocs = array();
$svn2gitauto = array();
function svn2gitrevs($text) {
global $svn2gitorig,$svn2gitms,$svn2gitdocs,$svn2gitauto;
// replace {{{ }}} by ``` ```
$text = str_replace("{{{","\n```",$text);
$text = str_replace("}}}","```\n",$text);
//does the text contain something like r1234
if(preg_match_all("/\\b(r[0-9]+)\\b/",$text,$matches)) {
$rrevs = $matches[1];
foreach($rrevs as $rrev) {
preg_match("/([0-9]+)/",$rrev,$rev);
$rev = $rev[1];
if($rev != "1") { /* skip r1.xx cvs revision format */
if(array_key_exists($rev,$svn2gitms)) {
$gitrev = $svn2gitms[$rev];
$text = str_replace("r$rev","$gitrev (r$rev)",$text);
} else {
if(array_key_exists($rev,$svn2gitdocs)) {
$gitrev = $svn2gitdocs[$rev];
$text = str_replace("r$rev","mapserver/docs@$gitrev (r$rev)",$text);
} else {
if(array_key_exists($rev,$svn2gitauto)) {
$gitrev = $svn2gitauto[$rev];
$text = str_replace("r$rev","mapserver/msautotest@$gitrev (r$rev)",$text);
} else {
//failed lookup
}
}
}
}
}
}
return $text;
}
error_reporting(E_ALL ^ E_NOTICE);
ini_set('display_errors', 1);
set_time_limit(0);
$trac_db = new PDO('pgsql:host='.$mysqlhost_trac.';dbname='.$mysqldb_trac, $mysqluser_trac, $mysqlpassword_trac);
// Create the lookup table
$lines = file("lookup-orig.txt");
foreach ($lines as $line)
{
if (empty($line)) continue;
list ($svnID, $gitID) = explode("\t", trim($line));
$svn2gitorig[$svnID] = $gitID;
}
$lines = file("lookup-mapserver.txt");
foreach ($lines as $line)
{
if (empty($line)) continue;
list ($svnID, $gitID) = explode("\t", trim($line));
$svn2gitms[$svnID] = $gitID;
}
$lines = file("lookup-docs.txt");
foreach ($lines as $line)
{
if (empty($line)) continue;
list ($svnID, $gitID) = explode("\t", trim($line));
$svn2gitdocs[$svnID] = $gitID;
}
$lines = file("lookup-autotests.txt");
foreach ($lines as $line)
{
if (empty($line)) continue;
list ($svnID, $gitID) = explode("\t", trim($line));
$svn2gitauto[$svnID] = $gitID;
}
echo 'Connected to Trac';
if(!$skip_components) {
$res = $trac_db->query("SELECT distinct component FROM ticket where $component_filter");
$mnum = 1;
foreach ($res->fetchAll() as $row) {
$resp = github_add_component(array(
'name' => $row['component'],
'color' => 'ffffff'));
if (isset($resp['url'])) {
// OK
echo "Component {$row['component']} converted to label {$resp['url']}\n";
} else {
// Error
echo "Failed to convert component {$row['component']}: $error\n";
}
}
}
$milestones = array();
if (file_exists($save_milestones)) {
$milestones = unserialize(file_get_contents($save_milestones));
}
if (!$skip_milestones) {
// Export all milestones
$res = $trac_db->query("SELECT * FROM milestone ORDER BY due");
$mnum = 1;
foreach ($res->fetchAll() as $row) {
//$milestones[$row['name']] = ++$mnum;
$resp = github_add_milestone(array(
'title' => $row['name'],
'state' => $row['completed'] == 0 ? 'open' : 'closed',
'description' => empty($row['description']) ? 'None' : $row['description'],
'due_on' => date('Y-m-d\TH:i:s\Z', (int) $row['due'])
));
if (isset($resp['number'])) {
// OK
$milestones[crc32($row['name'])] = (int) $resp['number'];
echo "Milestone {$row['name']} converted to {$resp['number']}\n";
} else {
// Error
$error = print_r($resp, 1);
echo "Failed to convert milestone {$row['name']}: $error\n";
}
}
// Serialize to restore in future
file_put_contents($save_milestones, serialize($milestones));
}
// Try get previously fetched tickets
$tickets = array();
if (file_exists($save_tickets)) {
$tickets = unserialize(file_get_contents($save_tickets));
}
if (!$skip_tickets) {
// Export tickets
$limit = ($ticket_min != 0 && $ticket_max != 0) ? "id>=$ticket_min and id<=$ticket_max": '1=1';
$res = $trac_db->query("SELECT * FROM ticket where $limit and $component_filter ORDER BY id");
foreach ($res->fetchAll() as $row) {
if($row['component'] == 'Security/Vulnerability (Private)') {
$issue = array(
'title' => 'scrubbed on import',
'body' => "imported from http://trac.osgeo.org/mapserver/ticket/$row[id]");
if(!empty($row['milestone'])) {
$issue['milestone']= $milestones[crc32($row['milestone'])];
}
$resp = github_add_issue($issue);
if (isset($resp['number'])) {
// OK
echo "Scrubbed Ticket #{$row['id']}->#{$resp['number']}\n";
}
continue;
}
$description='';
if(!empty($row['description'])) {
$description = svn2gitrevs($row['description']);
}
/* add reporter and date to ticket body */
$date = date($dateformat,$row['time']);
$description = '**Reporter: '.$row['reporter']."**\n**Date: ".$date."**\n**Trac URL:** http://trac.osgeo.org/mapserver/ticket/$row[id]\n".$description;
$labels = array($row['component']);
if(!empty($row['type'])) {
if($row['type']=='defect')
array_push($labels,"bug");
else if($row['type']=='enhancement')
array_push($labels,"enhancement");
}
$issue = array(
'title' => $row['summary'],
'body' => $description,
'labels' => $labels);
if(!empty($row['milestone'])) {
$issue['milestone']= $milestones[crc32($row['milestone'])];
}
$resp = github_add_issue($issue);
if (isset($resp['number'])) {
// OK
echo "Ticket #{$row['id']} converted to issue #{$resp['number']}\n";
$tickets[$row['id']] = (int) $resp['number'];
// now import ticket comments
if(!$skipcomments) {
$cres = $trac_db->query("SELECT * FROM ticket_change where ticket='".$row['id']."' and field = 'comment' AND newvalue != '' ORDER BY time ASC");
foreach ($cres->fetchAll() as $crow) {
$text = $crow['newvalue'];
$text = svn2gitrevs($text);
$date = date($dateformat,$crow['time']);
$text = '**Date: '.$date."**\n".$text;
if(strtolower($crow['author']) != strtolower($username)) {
$text = '**Author: ' . $crow['author'] . "**\n" . $text;
}
$cresp = github_add_comment($tickets[$crow['ticket']], $text);
if (isset($cresp['url'])) {
//echo "Added comment {$cresp['url']} to ticket #{$resp['number']}\n";
} else {
// Error
$error = print_r($cresp, 1);
echo "Failed to add a comment: $error\n";
exit();
}
}
}
if ($row['status'] == 'closed' || !empty($row['owner']) ) {
$update = array();
if(!empty($row['owner']) && isset($users_list[$row['owner']])) {
$update['assignee']= $users_list[$row['owner']];
//echo "Assigning issue #{$resp['number']} to {$users_list[$row['owner']]}\n";
}
if ($row['status'] == 'closed') {
$update['state']= 'closed';
//echo "Closing issue #{$resp['number']}\n";
}
if(!empty($update)) {
$sresp = github_update_issue($resp['number'], $update);
if (!isset($sresp['url'])) {
$error = print_r($cresp, 1);
echo "Failed to update status or assignee: $error\n";
exit();
}
}
}
} else {
// Error
$error = print_r($resp, 1);
echo "Failed to convert a ticket #{$row['id']}: $error\n";
exit();
}
}
// Serialize to restore in future
file_put_contents($save_tickets, serialize($tickets));
}
if(!$skip_attachments) {
$res = $trac_db->query("SELECT * FROM attachment where type='ticket' and id::integer>=$ticket_min and id::integer<=$ticket_max");
foreach ($res->fetchAll() as $row) {
$update = array();
$tid = $row['id'];
$fname=$row['filename'];
$com = $row['description'];
$text = "attachment http://trac.osgeo.org/mapserver/attachment/ticket/$tid/$fname :
```
$com
```";
$cresp = github_add_comment($tid, $text);
if (isset($cresp['url'])) {
echo "Added attachment {$cresp['url']} to ticket $tid\n";
} else {
// Error
$error = print_r($cresp, 1);
echo "Failed to add a comment: $error\n";
exit();
}
//http://trac.osgeo.org/mapserver/raw-attachment/ticket/15/mswms_gmap.gif
}
}
if(!$skip_resolution) {
$limit = ($ticket_min != 0 && $ticket_max != 0) ? "id>=$ticket_min and id<=$ticket_max": '1=1';
$res = $trac_db->query("SELECT * FROM ticket where $limit and resolution != '' ORDER BY id");
foreach ($res->fetchAll() as $row) {
$resol = $row['resolution'];
$tid = $row['id'];
if($resol == "duplicate" ||
$resol == "invalid" ||
$resol == "worksforme" ||
$resol == "wontfix") {
$alabel = array($resol);
$sresp = github_add_label($row['id'], array($resol));
if (!isset($sresp[0]['url'])) {
$error = print_r($sresp, 1);
echo "Failed to add label: $error\n";
exit();
} else {
echo "added label $resol to $tid\n";
}
}
}
}
if(!$skip_assignee) {
$limit = ($ticket_min != 0 && $ticket_max != 0) ? "id>=$ticket_min and id<=$ticket_max": '1=1';
$res = $trac_db->query("SELECT * FROM ticket where $limit and owner != '' ORDER BY id");
foreach ($res->fetchAll() as $row) {
if (!empty($row['owner']) ) {
$update = array();
if(isset($users_list[$row['owner']])) {
$update['assignee']= $users_list[$row['owner']];
echo "Assigning issue #{$row['id']} to {$users_list[$row['owner']]}\n";
}
if(!empty($update)) {
$sresp = github_update_issue($row['id'], $update);
if (!isset($sresp['url'])) {
$error = print_r($sresp, 1);
echo "Failed to update status or assignee: $error\n";
exit();
}
}
}
}
}
if(!$skip_version) {
$res = $trac_db->query("SELECT distinct version FROM ticket where version != '' and version != 'unspecified'");
foreach ($res->fetchAll() as $row) {
$ver = $row['version'];
if($ver == "svn-trunk (development)") {
$ver = "master";
}
$ver = "version-$ver";
$resp = github_add_component(array(
'name' => $ver,
'color' => 'ffffff'));
if (isset($resp['url'])) {
// OK
echo "Component {$row['version']} converted to label $ver\n";
} else {
// Error
$error = print_r($resp, 1);
echo "Failed to convert version {$row['version']}: $error\n";
}
}
$limit = ($ticket_min != 0 && $ticket_max != 0) ? "id>=$ticket_min and id<=$ticket_max": '1=1';
$res = $trac_db->query("SELECT * FROM ticket where $limit and version != '' and version != 'unspecified' ORDER BY id");
foreach ($res->fetchAll() as $row) {
$ver = $row['version'];
if($ver == "svn-trunk (development)") {
$ver = "master";
}
$ver = "version-$ver";
$tid = $row['id'];
$sresp = github_add_label($row['id'], array($ver));
if (!isset($sresp[0]['url'])) {
print_r($sresp);
echo "Failed to add label $ver: $error\n";
exit();
} else {
echo "added label $ver to $tid\n";
}
}
}
echo "Done whatever possible, sorry if not.\n";
$lastrequest = 0;
function github_post($url, $json, $patch = false, $method='post') {
global $username, $password,$lastrequest;
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_URL, "https://api.github.com$url");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HEADER, false);
$putData = tmpfile();
fwrite($putData, "ignore=1");
fseek($putData, 0);
if($method=='post') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
} else if($method=='put') {
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_INFILE, $putData);
curl_setopt($ch, CURLOPT_INFILESIZE, strlen("ignore=1"));
}
if ($patch) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
}
$now = microtime(true);
if($lastrequest>0 && $now-$lastrequest<1) {
//printf("rate limit: sleeping for %f\n",1-($now-$lastrequest));
usleep((1-($now-$lastrequest))*1000000);
}
$lastrequest = $now;
$ret = curl_exec($ch);
if(!$ret) {
trigger_error(curl_error($ch));
}
curl_close($ch);
fclose($putData);
return $ret;
}
function github_add_milestone($data) {
global $project, $repo;
return json_decode(github_post("/repos/$project/$repo/milestones", json_encode($data)), true);
}
function github_add_component($data) {
global $project, $repo;
return json_decode(github_post("/repos/$project/$repo/labels", json_encode($data)), true);
}
function github_add_issue($data) {
global $project, $repo;
return json_decode(github_post("/repos/$project/$repo/issues", json_encode($data)), true);
}
function github_add_comment($issue, $body) {
global $project, $repo;
return json_decode(github_post("/repos/$project/$repo/issues/$issue/comments", json_encode(array('body' => $body))), true);
}
function github_add_label($issue, $labels) {
global $project, $repo;
//echo "/repos/$project/$repo/issues/$issue/labels\n";
//print_r(json_encode($labels)); return;
return json_decode(github_post("/repos/$project/$repo/issues/$issue/labels", json_encode($labels)), true);
}
function github_update_issue($issue, $data) {
global $project, $repo;
return json_decode(github_post("/repos/$project/$repo/issues/$issue", json_encode($data), true), true);
}
function github_add_collaborators() {
global $project, $repo, $users_list;
foreach($users_list as $key => $collab) {
json_decode(github_post("/repos/$project/$repo/collaborators/$collab", '', false,'put'), true);
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment