Importing from JIRA to VSTS
In this post we’ll share our research on how to import your current project information from JIRA to VSTS.
Overview
There is a rising demand from our customers to sync/move project items from JIRA to VSTS in order to support a wide variety of integration scenarios. Capitalizing on how extensible both platforms are, in this post we will walk you through a step-by-step guide on how to create a simple tool to do so.
Prerequisites
You'll need to meet the following prerequisites:
- Visual Studio
- Atlassian.SDK
- Microsoft.VisualStudio.Services.Client
Steps
These steps were generated as part of our research and shared “as is”. You are encouraged to use and provide feedback; however, these steps and sample code are not supported, nor are any commitments made as to their longevity.
- Start by creating a simple console application.
- Add the following NuGet packages to connect to both repositories:
- Create a connection to the VSTS repository
string vstsUrl = "https://{vstsAccount}.visualstudio.com";string vstsPAT = "{vstsPersonalAccessToken}";VssConnection connection = new VssConnection(new Uri(vstsUrl), new VssBasicCredential(string.Empty, vstsPAT));WorkItemTrackingHttpClient witClient = connection.GetClient<WorkItemTrackingHttpClient>();
In this case we are connecting using a VSTS Personal Access Token. - Create a connection to the JIRA repository
string jUserID = "{jiraUserID}";string jPassword = "{jiraUserPassword}";string jUrl = "https://{jiraAccount}.atlassian.net";Jira jiraConn = Jira.CreateRestClient(jUrl, jUserID, jPassword);
- Get the list of issues from JIRA (the list will contain all versions for every issue)
IList issues = (from i in jiraConn.Issues.Queryable orderby i.Created select i).ToList();
If the repositories is big, consider fetching issues by slices. - For each issue in the list...
- Ensure the imported iteration value exists.
Get the existing iterations defined in VSTS
WorkItemClassificationNode all = WorkItemTrackingHttpClient.GetClassificationNodeAsync(project, TreeStructureGroup.Iterations, null, 10).Result;
Navigate in the existing iterations and if necessary, create new values:
WorkItemClassificationNode workItemClassificationNode = witClient.CreateOrUpdateClassificationNodeAsync( new WorkItemClassificationNode() { Name = iterationName, }, projectName, TreeStructureGroup.Iterations, parentPath).Result;
Consider creating a local cache of iteration defined in VSTS to avoid querying VSTS multiple times for the same values. - Create the JSON necessary to create/update the WorkItem in VSTS
JsonPatchDocument document = new JsonPatchDocument(); string title = String.Format ( "[{0}] [{1}] {2}" + , DateTime.Now.ToLongTimeString(), issue.Key, issue.Summary); title = title.Substring(0, Math.Min(title.Length, 128)); document.Add(new JsonPatchOperation { Operation = Operation.Add, Path = "/fields/System.Title", Value = title }); if (issue.Description != null) { document.Add(new JsonPatchOperation { Operation = Operation.Add, Path = "/fields/System.Description", Value = issue.Description }); } [...]
This "mapping" process should take care of all the differences between the item definition in JIRA and in VSTS.
In this case, for example, in VSTS the title property is created by concatenating the issue key with the issue summary value.
To map identities from JIRA to VSTS use the EMail address defined in the identity.
JiraUser user = jiraConn.Users.SearchUsersAsync(issue.Reporter).Result.FirstOrDefault(); if (user != null) document.Add(new JsonPatchOperation { Operation = Operation.Add, Path = "/fields/System.CreatedBy", Value = user.Email });
- Create/Update the workitem in VSTS
[...]workItem = witClient.CreateWorkItemAsync(document, project, workItemType).Result;[...]
or
[...] workItem = witClient.UpdateWorkItemAsync(document, id).Result; [...]
This part of the process should take care of the project template state transitions and the work item type management.
Additionally, consider maintaining a cache of mapping ids from both system to easily find existing items in the repositories.
- Ensure the imported iteration value exists.
Challenges not addressed in the sample:
- Custom template mapping
- Custom field mapping
- Custom field value mapping
Authors: Hosam Kamel, João Paulo Rodrigues, Vladimir Gusarov
Comments
- Anonymous
April 13, 2017
HI, I read with interest your post, howeverconnection.GetClient();
seems doesn't exists any more. It is necessary now to add aType
but I don't what kind ofType
- Anonymous
April 19, 2017
Hello Enrico Rossini,You are right on your comment, my code snippet was incomplete. Use the following code instead:WorkItemTrackingHttpClient witClient = connection.GetClient();
- Anonymous
- Anonymous
April 18, 2018
I am always stuck at the given key is not present in dictionary.check image https://ibb.co/hBMxGn- Anonymous
July 03, 2018
What method call is throwing that exception?
- Anonymous
- Anonymous
July 03, 2018
Hello JP, This guide was really helpful and informative and explains the migration process very well