Skip to content
Snippets Groups Projects
Commit 359f2877 authored by Thomas Hackl's avatar Thomas Hackl
Browse files

use transliterator, migrate milestones

parent 734a08ea
No related branches found
No related tags found
No related merge requests found
......@@ -12,7 +12,7 @@
}
],
"require": {
"php": ">=5.3.0",
"php": ">=5.6.0",
"ext-mbstring": "*",
"ext-json": "*",
"m4tthumphrey/php-gitlab-api": "9.9.0",
......
......@@ -14,7 +14,11 @@ $steps = [
'comments' => __DIR__ . '/steps/add-comments.php',
];
$result = ['issues' => [8641 => 398]];
if (!class_exists('Transliterator')) {
die("PHP extension intl with Transliterator class is needed.\n");
}
$result = [];
foreach ($steps as $number => $step) {
$result[$number] = require $step;
}
......@@ -69,16 +69,21 @@ class GitLab
* @param int $authorId Numeric user id of the user who created the issue. Only used in admin mode. Can be null.
* @param array $labels Array of string labels to be attached to the issue. Analoguous to trac keywords.
* @param bool $confidential Is this issue confidential?
* @para, int $milestoneId Optional ID of a milestone to assign this issue to
* @return Gitlab\Model\Issue
*/
public function createIssue($projectId, $title, $description, $createdAt, $assigneeId, $authorId, $labels, $confidential = false) {
public function createIssue($projectId, $title, $description, $createdAt, $assigneeId, $authorId, $labels,
$confidential = false, $milestoneId = 0
) {
try {
// Try to add, potentially as an admin (SUDO authorId)
$issue = $this->doCreateIssue($projectId, $title, $description, $createdAt, $assigneeId, $authorId, $labels, $confidential, $this->isAdmin);
$issue = $this->doCreateIssue($projectId, $title, $description, $createdAt, $assigneeId, $authorId,
$labels, $confidential, $milestoneId, $this->isAdmin);
} 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 ($this->isAdmin) {
$issue = $this->doCreateIssue($projectId, $title, $description, $createdAt, $assigneeId, $authorId, $labels, $confidential, false);
$issue = $this->doCreateIssue($projectId, $title, $description, $createdAt, $assigneeId, $authorId,
$labels, $confidential, $milestoneId, false);
} else {
// If adding has failed for some other reason, propagate the exception back
throw $e;
......@@ -170,8 +175,41 @@ class GitLab
}
}
/**
* Gets milestones of project.
* @param string $projectId project to check
* @param array $ids get only milestones with the given IDs.
* @param string $state if set, return only milestones with the given status
* @param string $search optional filter on milestone title or description
* @return array
*/
public function getMilestones($projectId, $ids = [], $state = '', $search = '') {
$parameters = [];
if (count($ids) > 0) {
$parameters['iids'] = $ids;
}
if ($state !== '') {
$parameters['state'] = $state;
}
if ($search !== '') {
$parameters['search'] = $search;
}
return $this->client->api('milestones')->all($projectId, $parameters);
}
public function createMilestone($projectId, $title, $description = '', $dueDate = '', $startDate = '') {
return $this->client->api('milestones')->create($projectId,
['title' => $title, 'description' => $description, 'due_date' => $dueDate, 'start_date' => $startDate]);
}
public function closeMilestone($projectId, $id) {
return $this->client->api('milestones')->update($projectId, $id, ['state_event' => 'close']);
}
// Actually creates the issue
private function doCreateIssue($projectId, $title, $description, $createdAt, $assigneeId, $authorId, $labels, $confidential, $isAdmin) {
private function doCreateIssue($projectId, $title, $description, $createdAt, $assigneeId, $authorId, $labels,
$confidential, $milestoneId = 0, $isAdmin
) {
$issueProperties = array(
'title' => $title,
'description' => $description,
......@@ -181,6 +219,9 @@ class GitLab
);
if ($confidential) {
$issueProperties['confidential'] = true;
}
if ($milestoneId !== '') {
$issueProperties['milestone_id'] = $milestoneId;
}
if ($isAdmin) {
$issueProperties['sudo'] = $authorId;
......
......@@ -156,7 +156,8 @@ class Migration
// Close issue if Trac ticket was closed.
if ($ticket[3]['status'] === 'closed') {
$this->gitLab->closeIssue($gitLabProject, $issue['iid'],
$ticket[4][0]['time']['__jsonclass__'][1], $ticket[4][0]['author']);
isset($ticket[4]) ? $ticket[4][0]['time']['__jsonclass__'][1] : $ticket[3]['_ts'],
isset($ticket[4]) ? $ticket[4][0]['author'] : '');
}
}
......
......@@ -115,5 +115,23 @@ class Trac
{
return $this->client;
}
/**
* Fetches all existing milestone names.
* @return array
*/
public function getMilestones() {
return $this->client->execute('ticket.milestone.getAll');
}
/**
* Gets the milestone with the given name.
* @param string $name
* @return array
*/
public function getMilestone($name) {
return $this->client->execute('ticket.milestone.get', [$name]);
}
}
?>
......@@ -20,6 +20,11 @@ $gitlab_users = $gitlab->listUsers();
$step_size = 50;
$page = 1;
// Trac Milestones that have already been created in Gitlab.
$milestones = [];
// Milestones that have already been migrated and closed.
$closedMilestones = [];
do {
$query = "{$config['trac-query']}&page={$page}&max={$step_size}";
try {
......@@ -28,6 +33,7 @@ do {
$ticket_ids = [];
}
foreach ($ticket_ids as $ticket_id) {
try {
$ticket = $trac_client->execute('ticket.get', [$ticket_id]);
......@@ -44,9 +50,34 @@ do {
$dateUpdated = $ticket[3]['_ts'];
$confidential = (bool) @$ticket[3]['sensitive'];
// Check if milestone must be created.
if (is_array($ticket[3]) && isset($ticket[3]['milestone']) && $ticket[3]['milestone'] !== '') {
/*
* Create a new milestone in Gitlab and use its ID it if
* it doesn't exist in Gitlab yet.
*/
if (!isset($milestones[$ticket[3]['milestone']]) || !is_array($milestones[$ticket[3]['milestone']])) {
$m = $trac->getMilestone($ticket[3]['milestone']);
$g = $gitlab->createMilestone($config['gitlab-project'], $m['name'],
translateTracToMarkdown($m['description'], $trac->getUrl()),
is_array($m['due']) ? $m['due']['__jsonclass__'][1] : '', '');
$milestones[$ticket[3]['milestone']] = [
'id' => $g['id'],
'closed' => is_array($m['completed'])
];
echo "Created milestone " . $ticket[3]['milestone'] . ".\n";
}
}
$milestone = is_array($ticket[3]) &&
$ticket[3]['milestone'] !== '' &&
$milestones[$ticket[3]['milestone']] ?
$milestones[$ticket[3]['milestone']]['id'] : 0;
$issue = $gitlab->createIssue($config['gitlab-project'], $title,
$description, $dateCreated, $assigneeId, $creatorId, $labels,
$confidential);
$confidential, $milestone);
echo "Created a GitLab issue #{$issue['iid']} for Trac ticket #{$ticket_id} : {$config['trac-clean-url']}/tickets/{$ticket_id}\n";
......@@ -54,24 +85,25 @@ do {
$attachments = $trac->getAttachments($ticket_id);
/*
* Create a transliterator for treating file names with special
* characters in them.
*/
$trans = \Transliterator::create('Latin-ASCII');
/*
* 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!
// Transliterate file name, using only "safe" characters.
$filename = $trans->transliterate($a['filename']);
file_put_contents($a['filename'], base64_decode($a['content']));
file_put_contents($filename, base64_decode($a['content']));
$gitlab->createIssueAttachment($config['gitlab-project'], $issue['iid'], $a['filename'], $a['author']);
unlink($a['filename']);
$gitlab->createIssueAttachment($config['gitlab-project'], $issue['iid'], $filename, $a['author']);
unlink($filename);
echo "\tAttached file " . $a['filename'] . " to issue " . $issue['iid'] . ".\n";
echo "\tAttached file " . $filename . " to issue " . $issue['iid'] . ".\n";
}
// Close issue if Trac ticket was closed.
......@@ -85,6 +117,17 @@ do {
$gitlab->closeIssue($config['gitlab-project'], $issue['iid']);
}
}
// Close milestone if necessary.
if (is_array($ticket[3]) && $ticket[3]['milestone'] !== '' &&
!in_array($milestones[$ticket[3]['milestone']]['id'], $closedMilestones)
) {
$gitlab->closeMilestone($config['gitlab-project'], $milestones[$ticket[3]['milestone']]['id']);
$closedMilestones[] = $milestones[$ticket[3]['milestone']]['id'];
echo "\tClosed milestone " . $ticket[3]['milestone'] . ".\n";
}
} catch (Exception $e) {
throw $e;
echo "Error creating issue for ticket #{$ticket_id}\n";
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment