Document toolboxDocument toolbox

To learn more about Tempo products, please visit our Help Center. For support, see our Support Portal.

Migration of Tempo teams between Jira instances

Question

How can I migrate a Tempo team from one Jira instance to another

There might be a need a sync Tempo teams between two Jira instances. This can be the case when migrating from Jira Server to Jira Cloud or vice versa or in the case of a Tempo team has been deleted and you want to restore the Tempo team data from an available backup. This guide describes the approach on the best practice on how to achieve that job by using the Tempo APIs, some data modification in an calculation application and finally populating the data in the destination Jira instance using a script file. The approach is the same regardless of the Jira infrastructure that you are using (Server, Cloud or Data Center) but there are different API endpoints between Server and Cloud. Be aware that all APIs used in this tutorial are Tempo Server APIs.

  1. Get the information of all teams. The returned teams depend on the "browse team" permission (Tempo 8 and below) or the Team visibility (Tempo 9 and above).
    Use the API url: {yourJiraUrl}/rest/tempo-teams/1/team
    This will return a list of teams available and the JSON response will look similar to. 

    [ { "id": 4, "name": "Custom Web Development", "mission": "Developing customized web solutions for clients", "summary": "Custom Web Development Team", "lead": "erica", "program": "Greencloud Operation", "isPublic": false }, { "id": 22, "name": "GreenCloud Azome", "mission": "Develope Azome game app for IOS and Android. Goal is to get to top 100 on both Apple Store and Goolgle Play.", "summary": "Develop Azome game app", "lead": "mike", "program": "GreenCloud Product Development", "isPublic": false } ]

    From the response we can get the internal team ID.

  2. The internal team ID will be used in the next call to get all team details. Therefore we use an endpoint that we need to query two times (to check if the team has been populated by Jira groups or by single users or a mix).
    Use the API url: {yourJiraUrl}/rest/tempo-teams/2/team/{teamID}/member
    This will return a list of all your team members. We will need to gather this information to populate the team in the destination Jira instance. Your response will look similar to:

    [ { "id": 127, "member": { "teamMemberId": 127, "name": "admin", "type": "GROUP_USER", "avatar": { "48x48": "http://localhost:8080/secure/useravatar?avatarId=10142", "24x24": "http://localhost:8080/secure/useravatar?size=small&avatarId=10142", "16x16": "http://localhost:8080/secure/useravatar?size=xsmall&avatarId=10142", "32x32": "http://localhost:8080/secure/useravatar?size=medium&avatarId=10142" }, "activeInJira": true, "key": "admin", "displayname": "JIRA admin" }, "memberBean": { "teamMemberId": 127, "name": "admin", "type": "GROUP_USER", "avatar": { "48x48": "http://localhost:8080/secure/useravatar?avatarId=10142", "24x24": "http://localhost:8080/secure/useravatar?size=small&avatarId=10142", "16x16": "http://localhost:8080/secure/useravatar?size=xsmall&avatarId=10142", "32x32": "http://localhost:8080/secure/useravatar?size=medium&avatarId=10142" }, "activeInJira": true, "key": "admin", "displayname": "JIRA admin" }, "membership": { "id": 0, "role": { "id": 1, "name": "Member", "default": true }, "availability": "100", "teamMemberId": 0, "teamId": 4, "status": "active" }, "membershipBean": { "id": 0, "role": { "id": 1, "name": "Member", "default": true }, "availability": "100", "teamMemberId": 0, "teamId": 4, "status": "active" }, "groupForUser": [ "jira-administrators" ], "showDeactivate": false }, { "id": 83, "member": { "teamMemberId": 83, "name": "amy", "type": "USER", "avatar": { "48x48": "http://localhost:8080/secure/useravatar?ownerId=amy&avatarId=10929", "24x24": "http://localhost:8080/secure/useravatar?size=small&ownerId=amy&avatarId=10929", "16x16": "http://localhost:8080/secure/useravatar?size=xsmall&ownerId=amy&avatarId=10929", "32x32": "http://localhost:8080/secure/useravatar?size=medium&ownerId=amy&avatarId=10929" }, "activeInJira": true, "key": "amy", "displayname": "Amy Mitchell" }, "memberBean": { "teamMemberId": 83, "name": "amy", "type": "USER", "avatar": { "48x48": "http://localhost:8080/secure/useravatar?ownerId=amy&avatarId=10929", "24x24": "http://localhost:8080/secure/useravatar?size=small&ownerId=amy&avatarId=10929", "16x16": "http://localhost:8080/secure/useravatar?size=xsmall&ownerId=amy&avatarId=10929", "32x32": "http://localhost:8080/secure/useravatar?size=medium&ownerId=amy&avatarId=10929" }, "activeInJira": true, "key": "amy", "displayname": "Amy Mitchell" }, "membership": { "id": 83, "role": { "id": 6, "name": "Tester", "default": false }, "dateFrom": "31/Jan/19", "dateTo": "", "dateFromANSI": "2019-01-31", "dateToANSI": "", "availability": "100", "teamMemberId": 83, "teamId": 4, "status": "active" }, "membershipBean": { "id": 83, "role": { "id": 6, "name": "Tester", "default": false }, "dateFrom": "31/Jan/19", "dateTo": "", "dateFromANSI": "2019-01-31", "dateToANSI": "", "availability": "100", "teamMemberId": 83, "teamId": 4, "status": "active" }, "showDeactivate": true } ]

    There might be a mix of team member types. Those that are populated as single users ("type": "USER") and those that populated from Jira groups ("type": "GROUP_USER"). When you get team members of the type  " GROUP_USER" you will need to call the API from above but now with the parameter type=group. 

    Use the API url: {yourJiraUrl}/rest/tempo-teams/2/team/{teamID}/member?type=group. This will give you an information of what Jira groups you will need to add. The response might look like:

    [ { "id": 127, "member": { "teamMemberId": 127, "name": "jira-administrators", "type": "GROUP", "avatar": { "48x48": "http://localhost:8080/secure/useravatar?avatarId=10143", "24x24": "http://localhost:8080/secure/useravatar?size=small&avatarId=10143", "16x16": "http://localhost:8080/secure/useravatar?size=xsmall&avatarId=10143", "32x32": "http://localhost:8080/secure/useravatar?size=medium&avatarId=10143" }, "activeInJira": true, "key": "jira-administrators", "displayname": "jira-administrators" }, "memberBean": { "teamMemberId": 127, "name": "jira-administrators", "type": "GROUP", "avatar": { "48x48": "http://localhost:8080/secure/useravatar?avatarId=10143", "24x24": "http://localhost:8080/secure/useravatar?size=small&avatarId=10143", "16x16": "http://localhost:8080/secure/useravatar?size=xsmall&avatarId=10143", "32x32": "http://localhost:8080/secure/useravatar?size=medium&avatarId=10143" }, "activeInJira": true, "key": "jira-administrators", "displayname": "jira-administrators" }, "showDeactivate": false } ]

     

  3. Now as we have all information that we need we can prepare our raw data to populate the team data. First we convert the JSON response we received in step 2 to a readable csv/excel format. That can be done by any converter of your choice (e.g. http://convertcsv.com). For further processing we upload the data to a Google spreadsheet (or any other calculation application). We should now have a sheet with multiple columns.

    But we do only need a couple of columns. Delete (or hide) any columns other than:
    member/name, member/type, member/activeInJira, member/key, membership/role/id, membership/role/name, membership/availability, membership/dateFrom, membership/dateTo

  4. We can create the team in the destination Jira instance manually or by using the Tempo API.
    Use the API url: {yourJiraUrl}/rest/tempo-teams/1/team with the POST method and use the payload data from below with request:

    As the response you will get the ID of the team created in Tempo. We will need the received TeamID (24) in the next steps to populate our team with the necessary team members and their commitments.

     

  5. Now we need create the payload data to populate the team members to the newly created Tempo team in our destination instance. Therefore we need the previously created spreadsheet from step 3.
    Add a new column to the spreadsheet and rename the column to "Payload" or something else. In the first data row of this column enter the formula:
    ="{""member"":{""name"": """&D3&""",""type"": ""USER""},""membership"": {""role"": {""id"": "&F3&"},""dateFrom"": """&J3&""",""dateTo"": """&K3&""",""availability"": """&H3&"""}}" 
    The payload only needs a single quote (") but in order to work with your calculation application you might need to replace the single quote with a double quote (at least to work with a Google spreadsheet). The outcome should look similar as:


    Note: In case you have users populated by Jira groups the "member/type" column will state the value "GROUP_USER" instead of "USER". For this scenario you should add an if statement to check this. As we need to populate Jira groups with a different API call:
    =if(B3="USER","{""member"":{""name"": """&D3&""",""type"": ""USER""},""membership"": {""role"": {""id"": "&F3&"},""dateFrom"": """&J3&""",""dateTo"": """&K3&""",""availability"": """&H3&"""}}","")

  6. Add a coulmn "curl" and the following content to it:
    =if(B3="USER"," curl --request POST --url http://localhost:8080/rest/tempo-teams/2/team/24/member -D- -u fred:fred --header 'Content-Type: application/json' --data '"&N3&"'","")
    where you of course replace "fred:fred" with the username and password of your destination instance and the Jira base url with your current one.

  7. Paste the results of the "curl" column into a text editor of your choice and save the file on an executable path with a "sh" extension. 

  8. In a final step fire up your terminal and execute the script by typing: sh PopulateTeam.sh


    The terminal window will keep the responses and you should check on possible errors.

  9. If everything has gone well you should see your Tempo team that has now its populated members from the excel sheet above.

  10. From step 2 we could also see that our Tempo team needs also be populated by the Jira group "jira-administrators". In order to achieve that we use the same API but we will need to change the url used a little bit.
    Use the API url: {yourJiraUrl}/rest/tempo-teams/2/team/{teamID}/addGroups?groupNames=jira-administrators with the POST method. If you have more than one Jira group to be populated you add the group names to your API url by adding "&groupNames=jira-users".