We have noticed a bug with the Pivotal Tracker to JIRA import tool, in that it does not import epics as issue types. This has been reported to Atlassian and they are raising a bug.
While this bug could take a very long time to get fixed (if ever) i am looking at an alternative solution. Steps below -
1. Run the importer to import all issues from Pivotal Tracker excluding the Epics. Any issues linked to an Epic will have the Epic name added as a label.
2. CSV export/import the Epics from Pivotal Tracker
These newly created Epics will have Epic Name that matches some of the labels on the stories that were imported.
3. Create and run a script in the Console that does the following -
A) Get list of all Epics (Issue Key & Epic Name) in project (JQL)
B) Get list of all Stories in project that have a label (JQL)
C) If story label matches an epic name, then get the epic issue key, and add it to the story epic link field, to properly create Epic - Story relationship in Jira.
Examples of the Epic Name / Label values are -
EPIC NAME - "formalize development process"
LABEL = "formalize_development_process"
So they differ, in that spaces have been replaced with an underscore when the epic name was added as a label by the Pivotal Tracker importer
I would greatly appreciate if any of you developers out there could take a look at my requirements and code and help me fill in the gaps.
My code -
package examples.docs
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.issue.Issue
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class)
def searchProvider = ComponentAccessor.getComponent(SearchProvider.class)
def issueManager = ComponentAccessor.getIssueManager()
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
// GET EPICS - only want epic.key and epic.epic_name put into list/array - how?
def query = jqlQueryParser.parseQuery("project = PTEPICS and type = Epic")
def epic_results = searchProvider.search(query, user, PagerFilter.getUnlimitedFilter())
// GET ISSUES
def query2 = jqlQueryParser.parseQuery("project = PTEPICS and type != Epic and type not in subTaskIssueTypes()")
def issue_results = searchProvider.search(query2, user, PagerFilter.getUnlimitedFilter())
//FOR EACH ISSUE - how to do 1,2,3 below?
issue_results.getIssues().each {Issue ->
// 1. extract issue.label value
// 2. if issue.label == compare with list/arry of epic.epic_names and if a match then
// 3. set the issue.epic_link = epic.epic_key (of the matched epic)
}
Many thanks in advance,
Conor
Hey again Conor! :D
I've been playing around with this and have managed to put together a working script using the code that you've provided. Since I added quite a few lines, I've also loaded the script up with comments to help explain any of the code that may be convoluted (feel free to remove these). However, let me know if you have any other questions or concerns after looking it over and running a few tests.
See the code below:
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class)
def searchProvider = ComponentAccessor.getComponent(SearchProvider.class)
def customFieldManager = ComponentAccessor.customFieldManager
def issueManager = ComponentAccessor.issueManager
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def epicNameCF = customFieldManager.getCustomFieldObjectsByName("Epic Name").first()
def epicLinkCF = customFieldManager.getCustomFieldObjectsByName("Epic Link").first()
// GET EPICS
def query = jqlQueryParser.parseQuery("project = PTEPICS and type = Epic")
def epic_results = searchProvider.search(query, user, PagerFilter.getUnlimitedFilter())
//The query will return DocumentIssue object which can't be cast to MutableIssues
//So the below is required to obtain a full list of Issue objects (which can be cast)
def epicList = epic_results.issues.collect{issueManager.getIssueByCurrentKey(it.key)}
// GET ISSUES
def query2 = jqlQueryParser.parseQuery("project = PTEPICS and type != Epic and type not in subTaskIssueTypes()")
def issue_results = searchProvider.search(query2, user, PagerFilter.getUnlimitedFilter())
//The query will return DocumentIssue object which can't be cast to MutableIssues
//So the below is required to obtain a full list of Issue objects (which can be cast)
def issueList = issue_results.issues.collect{issueManager.getIssueByCurrentKey(it.key)}
//FOR EACH ISSUE
issueList.each{
// 1. extract issue.label value
// 2. if issue.label == compare with list/arry of epic.epic_names and if a match then
// 3. set the issue.epic_link = epic.epic_key (of the matched epic)
//Cast the issue to a MutableIssue (you can only set/change data of issues with this type)
def issue = it as MutableIssue
//Get the label (presumably the only label) and replace any underscores with spaces
def issueLabel = issue.labels.first()?.label?.replaceAll("_"," ")
//Search the list of epics for an epic with a name matching the label
def relatedEpic = epicList.find{it.getCustomFieldValue(epicNameCF) == issueLabel}
if(relatedEpic)
{
//Set the issue's Epic Link to the found epic
issue.setCustomFieldValue(epicLinkCF, relatedEpic)
//Update both of the epic and the issue in the Jira datastore
issueManager.updateIssue(user, issue, EventDispatchOption.DO_NOT_DISPATCH, false)
issueManager.updateIssue(user, relatedEpic, EventDispatchOption.DO_NOT_DISPATCH, false)
}
}
Best of luck!
Aidan
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.