phone: 07858 383794

email: james@jhitchcock.com

BitBucket API – Client – Part 1: Exporting Issues

  • posted by james
  • posted on July 21st 2012
  • 8 comments

Picture of a bitbucket API client application

Download: BitbucketClient02

Recently I decided to move the codebase of a system from Mercurial to Git, as I am more experienced with Git, and it suited our development life cycle a bit better.

As we use Bit Bucket, they support both hg, and Git.. so we didn’t have to change provider, however, its not quite as easy as clicking a button. I followed this guide (http://codeimpossible.com/2011/12/29/Moving-your-mercurial-repository-to-git/) and it went quite smoothly. The code was in the new repo.

BitBucket also provides issue/feature tracking, however, these are still left in the old repository, as well as a few other bits like the Wiki. There’s no way of transferring them on the site, and no export/import. There is however a REST API. I noticed a few threads on the feature requests that people wished to be able to export issues also, so I’ve decided to build a client for the API, so we can eventually export / import information from BitBucket.

It’s got a fair way to go, but I figured the best place to start is to allow exporting of Issues (Issue comments coming later!) so I’ve started to put together a simple windows forms app to assist. I may move this into a nice WPF app later, or even a Web app service.

I decided to use the .NET DataContractJsonSerializer, as there is nothing too complex in the API, and sometimes its just nice to Serialize / Deserialize as you please. The below methods do just that:

 

public static string Serialize<T>(T obj)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, obj);
string retVal = Encoding.UTF8.GetString(ms.ToArray());
return retVal;
}

public static T Deserialize<T>(string json)
{
T obj = Activator.CreateInstance<T>();
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
obj = (T)serializer.ReadObject(ms);
ms.Close();
return obj;
}

 

So I needed some classes to represent the json objects. Using a combination of ‘GraphicalHttpClient’ for Mac, as well as this site: http://json2csharp.com/ (Excellent site, as you can either put in a URL, or just paste in JSON) I was able to generate all the classes needed, without typing them all out.

 

We can then simply connect to the API and retrieve the data:

 

string url = "https://api.bitbucket.org/1.0/repositories/" + OwnerID + "/" + RepoName + "/issues/?start=" + start.ToString() + "&limit=" + limit.ToString();
var request = WebRequest.Create(url) as HttpWebRequest;

string credentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(UserID + ":" + Password));
request.Headers.Add("Authorization", "Basic " + credentials);

using (var response = request.GetResponse() as HttpWebResponse)
{
var reader = new StreamReader(response.GetResponseStream());
string json = reader.ReadToEnd();

RootObject r = Deserialize<RootObject>(json);

return r;
}

Or can we? Actually no.. Theres a limit of 15 results per API call.. We had over 180 issues to export, so as the API actually returns the count on the first call, and also provides parameters (start, and limit) to define which results you wish to recieve, its fairly trivial to loop through and get all the issues down.

At this stage I just wanted them out in a format I could use (Read: Open in excel) so CSV is fine. I used a great library called ‘Linq to CSV’ which takes the pain out of CSV (Theres plenty of complexities.. quotes, strings, new lines that are not worth worry about) and save it out to a file:

 

SaveFileDialog dialog = new SaveFileDialog();
dialog.Filter = "CSV File|*.csv";
dialog.Title = "Save an export CSV file";
dialog.ShowDialog();

if (!String.IsNullOrEmpty(dialog.FileName))
{

CsvFileDescription outputFileDescription = new CsvFileDescription
{
SeparatorChar = ',',
FirstLineHasColumnNames = true,
FileCultureName = "en-GB"
};
CsvContext cc = new CsvContext();

cc.Write(
issues,
dialog.FileName,
outputFileDescription);

}

So that’s about it really for now. I plan to add Importing next, to make it easy to move issues to new repos, as well as comments exporting support, but I have uploaded the current early version now in case anyone desperately needs to import. I’ll also be adding the sourcecode to my BitBucket / Git pages soon.  Give me a shout on Twitter if you get any issues.

 

8 Responses to “BitBucket API – Client – Part 1: Exporting Issues”

  1. Pavel says...

    Hi James,
    Does it produce a cvs file with all issues, including closed ones? Can the cvs file be imported to JIRA?

    Unfortunately, my user name is too long for the field, so I can’t try the app.

    Thank you,
    Pavel

  2. james says...

    Hello,

    Yes all issues.. Not sure if its suitable for JIRA, but its a CSV so you could always change around the columns to work for this. I’ll add an export to JIRA function in future.

    I’ll also update this week to accept longer usernames! Will drop a comment here when its done.

    Thanks for your comment

  3. Patrick says...

    This works great. Thanks.

    I may be back to see about the import feature someday =p

  4. james says...

    Now supports longer usernames & other fields

  5. james says...

    I have a Visual Studio plugin in development, so you can add comments to code and insert a snippet of the issue details its fixing

  6. jabbett says...

    A lifesaver! Thanks so much.
    Might you add support for version & milestone?

  7. james says...

    Looks like BB now offer these services!

  8. Sam Johnson says...

    Hi James,
    Many thanks for this tool, I found it incredibly useful earlier this year. However, I’ve just tried using it again now on our BitBucket issues, using the exact path for our repository (https://bitbucket.org/mariestopes/repository/issues), and it keeps returning the following error:
    The remote server returned an error: (404) Not Found.
    This definitely worked before – am I entering something wrongly? Or has BitBucket perhaps changed the way its API is accessed?

Leave a comment