Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Status Order Groomer (ScriptRunner Script)

Jonathan Rosenberg October 1, 2021

Hi everyone, I made a status order grooming script that orders all statuses in the following order by the statusCategory: To Do -> In Progress -> Done.

Currently, to do what this script does, you will have to click the up or down arrow many times!

Sharing this code so that you guys can better admin your Jira!

Reply below if there are improvements or bugs. 

import com.atlassian.jira.config.StatusManager
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.status.Status
import groovy.transform.Field
import org.apache.log4j.Level
import org.apache.log4j.Logger

@Field StatusManager statusManager = ComponentAccessor.getComponentOfType(StatusManager.class)
@Field Random random = new Random()

//Status Categories
@Field final String CAT_TO_DO = "new"
@Field final String CAT_INPROGRESS = "in progress"
@Field final String CAT_DONE = "complete"

// set up logger
@Field Logger logger = Logger.getLogger("Util Groom Statuses");
logger.setLevel(Level.DEBUG)

processStatusCategory(CAT_TO_DO)
processStatusCategory(CAT_INPROGRESS)
processStatusCategory(CAT_DONE)

/**
* Groom specific status category first
* @param statusCategory the status category to be groomed
*/
void processStatusCategory(String statusCategory) {
List<Status> statuses = statusManager.getStatuses()

int count = 0
statuses.each {
//Get current Id and position
Status currentStatus = it
String currentCategory = it.getStatusCategory().getName()
Long currentPosition = it.getSequence()

if (count.equals(0)) {
if (!currentStatus.getStatusCategory().getName().equalsIgnoreCase(CAT_TO_DO)) {
Status firstTodo = statuses.find{it.getStatusCategory().getName().equalsIgnoreCase(CAT_TO_DO)}
Long firstMove = firstTodo.getSequence() - 1
move(firstMove, firstTodo)
}
}

if (currentStatus.getStatusCategory().getName().equalsIgnoreCase(statusCategory) && !isInCorrectBlock(currentStatus)) {
//Get the status category
Long moveToPosition = getMoveToPosition(currentCategory)
logger.debug ("Last Position: $moveToPosition")

//Get the number of moves needed
Long moves = currentPosition - moveToPosition
logger.debug ("Moves needed $moves")

//perform move
move(moves, currentStatus)
}
count++
}
}

/**
* Get the last position or first position of the TO DO or COMPLETE category
* Used to calculate how many moves are required
* @param category the category we are getting the moves required
* @return
*/
Long getMoveToPosition(String category) {
logger.debug("Get Position for category: $category")
List<Status> statuses = statusManager.getStatuses()
logger.debug(statuses)
Long position = null
switch (category.toUpperCase()) {
case CAT_TO_DO.toUpperCase():
position = statuses.find{!it.getStatusCategory().getName().equalsIgnoreCase(CAT_TO_DO)}.getSequence()
break
case CAT_INPROGRESS.toUpperCase():
position = statuses.find{!it.getStatusCategory().getName().equalsIgnoreCase(CAT_TO_DO) && !it.getStatusCategory().getName().equalsIgnoreCase(CAT_INPROGRESS)}.getSequence()
break
case CAT_DONE.toUpperCase():
position = statuses.last().getSequence()
break
}
logger.debug("Last position for $category is $position")
return position
}

/**
* Move the status up or down based on the signage of the moves required
* @param moves signed Long for how many moves required. Positive move means moving up. Negative means
* down moves.
* @param status the status to be moved
*/
void move(Long moves, Status status) {
logger.debug("Starting Moves. Initial position: " + status.getSequence())
int i = 0
while (i < Math.abs(moves)){
if (moves > 0) {
statusManager.moveStatusUp(status.getId())
}
else {
statusManager.moveStatusDown(status.getId())
}
i++
}
logger.debug("Final position: " + status.getSequence())
}

/**
* Check to see if the statuses is correctly grouped with its category
* @param status the status to be checked
* @return true if the status is grouped together
*/
boolean isInCorrectBlock(Status status) {
//If it is TO_DO there should be no other categories before it
//If it is Inprogress there should be only inprogress before or after it, followed by only TO_DO or COMPLETE
//IF it is COMPLETE there should only be COMPLETE after it
boolean output = false
List<Status> statuses = statusManager.getStatuses()
List<Status> reversedOrderStatuses = statuses.reverse()
Long currentPosition = status.getSequence()

Long todoBoundaryPosition = statuses.find{!it.getStatusCategory().getName().equalsIgnoreCase(CAT_TO_DO)}.getSequence()
Long inProgressBoundaryPosition = statuses.find{!it.getStatusCategory().getName().equalsIgnoreCase(CAT_TO_DO) && !it.getStatusCategory().getName().equalsIgnoreCase(CAT_INPROGRESS)}.getSequence()
Long todoDonePosition = reversedOrderStatuses.find{!it.getStatusCategory().getName().equalsIgnoreCase(CAT_DONE)}.getSequence()

switch (status.getStatusCategory().getName().toUpperCase()) {
case CAT_TO_DO.toUpperCase():
if (currentPosition < todoBoundaryPosition) {
output = true
}
break
case CAT_INPROGRESS.toUpperCase():
if ( currentPosition >= todoBoundaryPosition && currentPosition <= inProgressBoundaryPosition) {
output = true
}
break
case CAT_DONE.toUpperCase():
if ( currentPosition > todoDonePosition) {
output = true
}
break
}
logger.debug("Check If Status in Correct Block: Current Position($currentPosition), ${status.getName()}:CurrentCat(${status.getStatusCategory().getName()}), todoBoundaryPosition(${todoBoundaryPosition}) todoDonePosition(${todoDonePosition}), Output ($output)" )
return output
}

/**
* Randomizes Statuses for testing
*/
void randomizeStatuses() {
List<Status> statuses = statusManager.getStatuses()

statuses.each {0
Long moves = random.longs(-30, 30).findFirst().getAsLong()
move(moves, it)
logger.debug("Random move ${it.getName()} moved $moves")
}
}

 

 

0 comments

Comment

Log in or Sign up to comment
TAGS
AUG Leaders

Atlassian Community Events