Tuesday, April 7, 2015

Convert Multiple Tasks to Sub-Tasks in JIRA similar to Bulk Update using Script Runner

How to Convert A Large Number of JIRA Tasks into Sub-Tasks using the Adaptavist Script Runner Plugin with JIRA

In JIRA, there is no way to convert Tasks into Sub-Tasks using the built-in Bulk Update functionality.  The lack of the feature is described in many JIRA tickets and Confluence posts on the official Atlassian site such as the two listed below:

There are many potential workarounds to this such as using selenium scripting to automate the conversion process using browser automation.  The best solution I have found is to use scripting within JIRA.

Backup your System

Before you attempt this, you should backup your JIRA instance because you potentially can make changes to tasks you did not intend.

Go to System settings and scroll down to the IMPORT & EXPORT section:

Use JIRA Backup functionality
Backup your JIRA instance

Install JIRA Adaptavist Scriptrunner

Scriptrunner by Adaptavist
Scriptrunner by Adaptavist

Download Adaptavist Scriptrunner

Get Adaptavist Scriptrunner:



The file will be named something like this: groovyrunner-3.0.6.jar...

Upload and Install Scriptrunner
Upload your downloaded JIRA plugin as a JAR File
Upload your downloaded JIRA plugin as a JAR File

Open up Scriptrunner and run the script

Here is the script you want to run. This version uses a custom JQL query to find a comma delimited list of items that have certain values in a custom Functional Requirement field. It then loops through the list of issues and converts them to a subtasks then links the task to the parent task.
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.ComponentManager
import com.atlassian.jira.security.Permissions
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.issue.UpdateIssueRequest;

//Examples, 8 is my subtask issue type id. Will be different for others
//changeToSubTaskAndLink("AXDIS-509", "AXDIS-1045", "8")
//changeToSubTaskAndLink("AXDIS-509", "AXDIS-1046", "8")

def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser.class)
def searchProvider = ComponentAccessor.getComponent(SearchProvider.class)
def issueManager = ComponentAccessor.getIssueManager()
def user = ComponentAccessor.getJiraAuthenticationContext().getUser()

//Add first function req here
//issueKey = 'AR-1231' for searching by id
def queryParamsString = "'Functional Requirement Id' ~ 5.3 " 

//Add all functional reqs after the first here
def functionalReqs = ['5.4', '5.5', '5.6', '5.7', '5.8', '5.9', '5.10', '5.11', '5.12']

functionalReqs.eachWithIndex { a, i ->
  queryParamsString += " OR 'Functional Requirement Id' ~ " + a

def parentIdKey = "AR-2125"
def subTaskIssueTypeId = "5"

def query = jqlQueryParser.parseQuery("project = AR AND affectedVersion = "Phase 2" AND 'Business Requirement Id' ~ '5' AND (" + queryParamsString + ")")
def results = searchProvider.search(query, user, PagerFilter.getUnlimitedFilter())
results.getIssues().each {documentIssue ->
    // if you need a mutable issue you can do:
    def issue = issueManager.getIssueObject(documentIssue.id)
    // do something to the issue...
    //changeToSubTaskAndLink("AR-2125", "AR-1977", "5")
    changeToSubTaskAndLink(parentIdKey, documentIssue.key, subTaskIssueTypeId)

//Method to do all the work
def changeToSubTaskAndLink(parentId, childId, subTaskIssueTypeId)
{  //Get the parent Issue 
    def parent = ComponentManager.getInstance().getIssueManager().getIssueObject(parentId) 
 //Get the child Issue 
    MutableIssue child = (MutableIssue)ComponentManager.getInstance().getIssueManager().getIssueObject(childId) 
    //Change the child to the subtask type 
    //Update the issue 
    ComponentAccessor.getIssueManager().updateIssue((ApplicationUser)ComponentManager.getInstance().jiraAuthenticationContext?.user, (MutableIssue)child, UpdateIssueRequest.builder().build())

    //Create the subtask link, if this is not done you'll end up with orphans 
    //ComponentManager.getInstance().getSubTaskManager().createSubTaskIssueLink(parent, child, ComponentManager.getInstance().jiraAuthenticationContext?.user) 
    ComponentAccessor.getSubTaskManager().createSubTaskIssueLink(parent, child, ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()) 

Wednesday, April 1, 2015

Tired Engineers: Welcome to the Future of Coffee Automation

Welcome to the Future of Coffee Automation

Introducing Brew().  A Coffee Automation system to initiate coffee brewing whenever your code quality starts to slip.

Brew detects when you start writing crappy code, brews you some coffee, and empowers you to PUT DOWN THE KEYBOARD AND PICK UP THE MUG!

The future of productivity for Software Engineers
The future of productivity for Software Engineers

Brew() will save your life and the lives of your team.  Engineers depend on it.

So what are you waiting for!?!?!

Learn more about brew here:  Brew()