Github to Redmine

I love Github, it’s free for open source projects, looks lovely and has changed the way I distribute both my open source code and the way I work on client projects. However in terms of issue tracking it is a bit of a let down. Recently we started using Redmine in the office to keep track of projects, bugs, tasks pretty much everything. We have our GIT repos pulled in and can link issues to commits and vice versa. The only trouble I had was that I didn’t want to just forget about the 64 tickets I had on Github. (63 of which were closed).

There is no obvious way of exporting your issues from Github. Likewise there is no out of the box way to import issues into Redmine either. (I believe there are some plugins you can use to import CSV files). Both do however have APIs. So it was down to me to do the hard work myself. A little bit of PHP and were up and running. Let’s have a look.

Get the Issues from Github

The firs thing I needed to do was to get the issues from Github. Now my example deals with Organisation Repositories however you can simply edit the API call if it is your own repo.

// Github Details
$github_org = 'organisation'; //Github Organisation Name
$github_repo = 'repository'; //Github Repository Name
$github_user = 'username'; //Github Username
$github_password = 'password'; //Github Password

// Github API URL
$issues_url = "https://$github_user:$github_password@api.github.com/repos/$github_org/$github_repo/issues?state=closed?per_page=100";

// Get the data from Github
$json = file_get_contents( $issues_url );
$data = json_decode( $json, true );

Well that was easy wasn’t it? We simply grab the json and decode it into a PHP array. The thing to note is the per_page statement. Github normally returns 30 records per page however you can force it to go up to 100 per page. As I only had 64 I knew bumping it up would work for me. If you have more than 100 records you can specify the page you want to return. Also notice the state parameter, I am pulling closed issues through. Change this to open to pull open issues.

Push the Data to Redmine

Now we have the data in an array we want to send it to our Redmine setup. Firstly you want to grab PHP Active Resource from GitHub. This is a basic PHP class for accessing Ruby on Rails REST APIs in an ActiveResource style of coding. We need to bring in the class and give it some info before getting into the good bits:

require_once ( 'ActiveResource.php' );

class Issue extends ActiveResource {
	var $site = 'http://username:password@my.redmineurl.com/';
	var $request_format = 'xml';
}

Just edit the details to be your username, password and URL and we’re all set to push to Redmine. We want to iterate through the array we created with our Github data and create a new issue in Redmine using the Class.

foreach ( $data as $row ) {
	$subject = $row['title'];
	$description = $row['body'];
	
	
	$issue = new Issue(
		array(
			'subject' => $subject,
			'description' => $description,
			'project_id' => 'myproject1', // Project Identifier
			'assigned_to_id' => 3, //User ID
			'status_id' => 5, //Status ID, 5 = CLOSED, 1 = NEW
		)
	);
	
	$issue->save();
	echo $issue->id . ' created successfully<br />';
	$issue_id = $issue->id;

So we are creating a new Issue, the subject we pull from our Github issue, the same with the description. The project_id I am setting manually. You should use the project identified you set. Next we need to assign the issue to someone (or not depending on your needs, if not just remove this line), the Redmine API will only accept user ids so you will need to fine that in your admin area (just goto users and click on a user and the url shoudl tell you their id).

What about Comments?

Now we want to handle comments on our Github issues. We do a little check against our returned Github issues to see if an issue has any comments and then pull those comments using the Github API. We then use the same method as above to insert those comments into Redmine as updates to our Redmine issues.

// Add comments as updates
	if ($row['comments'] > 0 ) {
		$commentid = $row['number'];
		$comment_url = "https://$github_user:$github_password@api.github.com/repos/$github_org/$github_repo/issues/$commentid/comments";
		
		$json2 = file_get_contents( $comment_url );
		$comments = json_decode( $json2, true );

		foreach ( $comments as $comment_row ) {
			$comment_notes = $comment_row['body'];
			
			$issue->find( $issue_id );
			$issue->set( 'notes', $comment_notes )->save();
			
			echo 'Comment added';
		}
	}

Final Code

So there we have all the code, it just needs putting together:

<?php
// Github Details
$github_org = 'organisation'; //Github Organisation Name
$github_repo = 'repository'; //Github Repository Name
$github_user = 'username'; //Github Username
$github_password = 'password'; //Github Password

// Get from Github
$issues_url = "https://$github_user:$github_password@api.github.com/repos/$github_org/$github_repo/issues?state=closed?per_page=100";

$json = file_get_contents( $issues_url );
$data = json_decode( $json, true );

// Push to Redmine

/* Uses PHP Active Resouce https://github.com/lux/phpactiveresource/wiki */
require_once ( 'ActiveResource.php' );

class Issue extends ActiveResource {
	var $site = 'http://username:password@my.redmineurl.com/';
	var $request_format = 'xml';
}

foreach ( $data as $row ) {
	$subject = $row['title'];
	$description = $row['body'];
	
	
	$issue = new Issue(
		array(
			'subject' => $subject,
			'description' => $description,
			'project_id' => 'vt1', // Project ID of Vtesse Website
			'assigned_to_id' => 3, //User ID of Will
			'status_id' => 5, //Status ID, 5 = CLOSED, 1 = NEW
		)
	);
	
	$issue->save();
	echo $issue->id . ' created successfully<br />';
	$issue_id = $issue->id;
	
	// Add comments as updates
	if ($row['comments'] > 0 ) {
		$commentid = $row['number'];
		$comment_url = "https://$github_user:$github_password@api.github.com/repos/$github_org/$github_repo/issues/$commentid/comments";
		
		$json2 = file_get_contents( $comment_url );
		$comments = json_decode( $json2, true );

		foreach ( $comments as $comment_row ) {
			$comment_notes = $comment_row['body'];
			
			$issue->find( $issue_id );
			$issue->set( 'notes', $comment_notes )->save();
			
			echo 'Comment added';
		}
	}
}

Conclusion

Now I fully admit this isn’t a very elegant solution and it has plenty of places it could be better. It should however give you starting point. I was reluctant myself to dig into the APIs as I’ve not had extensive experience doing it, however with a little work I was able to come up with something that fitted my needs!

A big thank you to Graham Weldon AKA Predominant who helped me with big fixing some of my code!

 Tagged with: , , , ,

Leave a Reply

Mojowill Avatar

Who the Hell am I?

I'm Will, a full time web developer, geek and musician. I develop using PHP and MySQL and spend most of my time working with WordPress. When I'm not buried in code I'm gaming, cooking or writing and recording music in my studio. I like sci-fi, pancakes and coffee and am totally prepared for the zombie apocalypse...

Stalk me on these other sites...

Why not be super creepy and check me out on all these other sites, I think they call it social media?