Skip to content
Snippets Groups Projects
Commit 7ae53f0f authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms
Browse files

ticketzuweisung ist egal, hobeln und späne

parent 44a56935
No related branches found
No related tags found
No related merge requests found
...@@ -4,6 +4,8 @@ require_once __DIR__ . '/vendor/autoload.php'; ...@@ -4,6 +4,8 @@ require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/includes/functions.php'; require_once __DIR__ . '/includes/functions.php';
$config = require __DIR__ . '/includes/config.php'; $config = require __DIR__ . '/includes/config.php';
$config['trac-clean-url'] = preg_replace('/(?<=:\/\/).*?:.*?@|\/login/', '${1}', $config['trac-url']);
$steps = [ $steps = [
'issues' => __DIR__ . '/steps/convert-tickets-to-issues.php', 'issues' => __DIR__ . '/steps/convert-tickets-to-issues.php',
'commits' => __DIR__ . '/steps/clone-svn-repository.php', 'commits' => __DIR__ . '/steps/clone-svn-repository.php',
......
...@@ -38,3 +38,83 @@ function removeDirectory($directory) ...@@ -38,3 +38,83 @@ function removeDirectory($directory)
} }
rmdir($directory); rmdir($directory);
} }
function translateTracToMarkdown($text, $trac_url) {
$text = str_replace("\r\n", "\n", $text);
// Inline code block
$text = preg_replace('/{{{(.*?)}}}/', '`$1`', $text);
// Multiline code block (optionally with language description)
$text = preg_replace("/{{{\n(?:#!(.+?)\n)?(.*?)\n}}}/s", "```\$1\n\$2\n```", $text);
// Headers
$text = preg_replace('/(?m)^======\s+(.*?)(\s+======)?$/', '###### $1', $text);
$text = preg_replace('/(?m)^=====\s+(.*?)(\s+=====)?$/', '##### $1', $text);
$text = preg_replace('/(?m)^====\s+(.*?)(\s+====)?$/', '#### $1', $text);
$text = preg_replace('/(?m)^===\s+(.*?)(\s+===)?$/', '### $1', $text);
$text = preg_replace('/(?m)^==\s+(.*?)(\s+==)?$/', '## $1', $text);
$text = preg_replace('/(?m)^=\s+(.*?)(\s+=)?$/', '# $1', $text);
// Bullet points
$text = preg_replace('/^ \* /', '****', $text);
$text = preg_replace('/^ \* /', '***', $text);
$text = preg_replace('/^ \* /', '**', $text);
$text = preg_replace('/^ \* /', '*', $text);
$text = preg_replace('/^ \d+\. /', '1.', $text);
// Make sure that horizontal rules have a line before them
$text = preg_replace("/(?m)^-{4,}$/", "\n----", $text);
$lines = array();
$isTable = false;
$isCode = false;
foreach (explode("\n", $text) as $line) {
if (strpos($line, '```') === 0) {
$isCode = !$isCode;
}
// Don't mess with code
if (!$isCode) {
// External links
$line = preg_replace('/\[(https?:\/\/[^\s\[\]]+)\s([^\[\]]+)\]/', '[$2]($1)', $line);
// Plain images (not linking to something specific)
$line = preg_replace('/\[\[Image\((?!wiki|ticket|htdocs|source)(.+?)\)\]\]/', '![image]($1)', $line);
// Remove the unnecessary exclamation mark in !WikiLinkBreaker
$line = preg_replace('/\!(([A-Z][a-z0-9]+){2,})/', '$1', $line);
// '''bold'''
$line = preg_replace("/'''([^']*?)'''/", '**$1**', $line);
// ''italic''
$line = preg_replace("/''(.*?)''/", '_$1_', $line);
// //italic//
$line = preg_replace("/\/\/(.*?)\/\//", '_$1_', $line);
// #Ticket links
$line = preg_replace('/#(\d+)/', '[#$1](' . $trac_url . '/ticket/$1)', $line);
$line = preg_replace('/ticket:(\d+)/', '[ticket:$1](' . $trac_url . '/ticket/$1)', $line);
// [changeset] links
$line = preg_replace('/\[(\d+)\]/', '[[$1]](' . $trac_url . '/changeset/$1)', $line);
$line = preg_replace('/changeset:(\d+)/', '[changeset:$1](' . $trac_url . '/changeset/$1)', $line);
$line = preg_replace('/r(\d+)/', '[r$1](' . $trac_url . '/changeset/$1)', $line);
// {report} links
$line = preg_replace('/{(\d+)}/', '[{$1}](' . $trac_url . '/report/$1)', $line);
$line = preg_replace('/report:(\d+)/', '[report:$1](' . $trac_url . '/report/$1)', $line);
if (strpos($line, '||') !== 0) {
$isTable = false;
} else {
// Makes sure both that there's a new line before the table and that a table header is generated
if (!$isTable) {
$sep = preg_replace('/[^|]/', '-', $line);
$line = "\n$line\n$sep";
$isTable = true;
}
// Makes sure that there's a space after the cell separator, since |cell| works in WikiFormatting but not in GFM
$line = preg_replace('/\|\|/', '| ', $line);
// Make trac headers bold
$line = preg_replace('/= (.+?) =/', '**$1**', $line);
}
}
$lines[] = $line;
}
$text = implode("\n", $lines);
return $text;
}
...@@ -96,13 +96,13 @@ class GitLab ...@@ -96,13 +96,13 @@ class GitLab
*/ */
public function closeIssue($projectId, $issueId, $time = '', $author = '') { public function closeIssue($projectId, $issueId, $time = '', $author = '') {
$this->client->api('issues')->update($projectId, $issueId, $this->client->api('issues')->update($projectId, $issueId,
[ array_filter([
'state_event' => 'close', 'state_event' => 'close',
'updated_at' => $time, 'updated_at' => $time,
'closed_at' => $time, 'closed_at' => $time,
'closed_by_id' => $author, 'closed_by_id' => $author,
'closed_by' => $author 'closed_by' => $author
]); ]));
} }
/** /**
...@@ -161,7 +161,7 @@ class GitLab ...@@ -161,7 +161,7 @@ class GitLab
} catch (\Gitlab\Exception\RuntimeException $e) { } catch (\Gitlab\Exception\RuntimeException $e) {
// If adding has failed because of SUDO (author does not have access to the project), create an issue without SUDO (as the Admin user whose token is configured) // If adding has failed because of SUDO (author does not have access to the project), create an issue without SUDO (as the Admin user whose token is configured)
if ($this->isAdmin) { if ($this->isAdmin && isset($data)) {
$note = $this->doCreateNote($projectId, $issueId, $data['markdown'], $authorId, false); $note = $this->doCreateNote($projectId, $issueId, $data['markdown'], $authorId, false);
} else { } else {
// If adding has failed for some other reason, propagate the exception back // If adding has failed for some other reason, propagate the exception back
......
...@@ -96,7 +96,7 @@ class Migration ...@@ -96,7 +96,7 @@ class Migration
$mapping = []; $mapping = [];
foreach($openTickets as $ticket) { foreach($openTickets as $ticket) {
$originalTicketId = $ticket[0]; $originalTicketId = $ticket[0];
$title = $ticket[3]['summary']; $title = $ticket[3]['summary'] ?: '¯\_(ツ)_/¯';
$description = $this->translateTracToMarkdown($ticket[3]['description']); $description = $this->translateTracToMarkdown($ticket[3]['description']);
if ($this->addLinkToOriginalTicket) { if ($this->addLinkToOriginalTicket) {
$description .= "\n\n---\n\nOriginal ticket: " . $this->trac->getUrl() . '/ticket/' . $originalTicketId; $description .= "\n\n---\n\nOriginal ticket: " . $this->trac->getUrl() . '/ticket/' . $originalTicketId;
......
...@@ -72,8 +72,8 @@ class Trac ...@@ -72,8 +72,8 @@ class Trac
$result[] = [ $result[] = [
'filename' => $attachment[0], 'filename' => $attachment[0],
'content' => $data['__jsonclass__'][1], 'content' => $data['__jsonclass__'][1],
'author' => $attachment[4] 'author' => $attachment[4]
]; ];
} }
......
...@@ -12,20 +12,87 @@ $migration = new Migration( ...@@ -12,20 +12,87 @@ $migration = new Migration(
$config['create-trac-links'], $config['create-trac-links'],
$userMapping = [] $userMapping = []
); );
$trac = $migration->trac->getClient(); $trac = $migration->trac;
$trac_client = $trac->getClient();
$gitlab = $migration->gitLab;
$gitlab_users = $gitlab->listUsers();
$step_size = 50; $step_size = 50;
$page = 1; $page = 1;
do { do {
$query = "{$config['trac-query']}&page={$page}&max={$step_size}"; $query = "{$config['trac-query']}&page={$page}&max={$step_size}";
try { try {
$ticket_ids = $trac->execute('ticket.query', [$query]); $ticket_ids = $trac_client->execute('ticket.query', [$query]);
$migration->migrate($ticket_ids, $config['gitlab-project']);
} catch (Exception $e) { } catch (Exception $e) {
$ticket_ids = []; $ticket_ids = [];
} }
foreach ($ticket_ids as $ticket_id) {
try {
$ticket = $trac_client->execute('ticket.get', [$ticket_id]);
$title = $ticket[3]['summary'] ?: '¯\_(ツ)_/¯';
$description = translateTracToMarkdown($ticket[3]['description'], $config['trac-clean-url']);
$description .= "\n\n---\n\nOriginal ticket: {$config['trac-clean-url']}/ticket/{$ticket_id}";
$gitLabAssignee = isset($gitlab_users[$ticket[3]['owner']]) ? $gitlab_users[$ticket[3]['owner']] : null;
$gitLabCreator = isset($gitlab_users[$ticket[3]['reporter']]) ? $gitlab_users[$ticket[3]['reporter']] : null;
$assigneeId = is_array($gitLabAssignee) ? $gitLabAssignee['id'] : null;
$creatorId = is_array($gitLabCreator) ? $gitLabCreator['id'] : null;
$labels = $ticket[3]['keywords'];
$dateCreated = $ticket[3]['time']['__jsonclass__'][1];
$dateUpdated = $ticket[3]['_ts'];
$confidential = (bool) @$ticket[3]['sensitive'];
$issue = $gitlab->createIssue($config['gitlab-project'], $title,
$description, $dateCreated, $assigneeId, $creatorId, $labels,
$confidential);
echo "Created a GitLab issue #{$issue['iid']} for Trac ticket #{$ticket_id} : {$config['trac-clean-url']}/tickets/{$ticket_id}\n";
$mapping[$ticket_id] = $issue['iid'];
$attachments = $trac->getAttachments($ticket_id);
/*
* Add files attached to Trac ticket to new Gitlab issue.
*/
foreach ($attachments as $a) {
$a['filename'] = str_replace(
['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü', 'ß'],
['ae', 'oe', 'ue', 'Ae', 'Oe', 'Ue', 'ss'],
$a['filename']
);
// TODO: Thomas! WTF! FUCK! MACHEN! SOFORT!
file_put_contents($a['filename'], base64_decode($a['content']));
$gitlab->createIssueAttachment($config['gitlab-project'], $issue['iid'], $a['filename'], $a['author']);
unlink($a['filename']);
echo "\tAttached file " . $a['filename'] . " to issue " . $issue['iid'] . ".\n";
}
// Close issue if Trac ticket was closed.
if ($ticket[3]['status'] === 'closed') {
if (isset($ticket[4])) {
$gitlab->closeIssue(
$config['gitlab-project'], $issue['iid'],
$ticket[4][0]['time']['__jsonclass__'][1], $ticket[4][0]['author']
);
} else {
$gitlab->closeIssue($config['gitlab-project'], $issue['iid']);
}
}
} catch (Exception $e) {
throw $e;
echo "Error creating issue for ticket #{$ticket_id}\n";
}
}
$page += 1; $page += 1;
} while (count($ticket_ids) > 0); } while (count($ticket_ids) > 0);
return $migration->migrateQuery( return $migration->migrateQuery(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment