Does anyone know of a way to automatically release a kanban board?

Ben Poulson
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 3, 2019

I am trying to schedule a kanban board to be automatically released on a schedule (5PM Monday-Friday). The board is mostly automated, we use it to monitor our dataload process. It has ~100 tickets created per day, so the resolved column stacks up fast and needs to be released regularly to keep it readable. Until now, we had just been doing it before we leave at night, but I'd rather have it automated. I wrote 2 scripts that are running in scriptrunner escalation services right now- one to create/assign a version to the tickets, and another that runs 5 mins later to release the version (I'll put the scripts at the bottom of this post). The scripts work as intended, but I think the actual versions in the projects aren't refreshing their issues properly. When I come in in the morning, the board has not released, but when I go to the project>Releases, it says there are only two issues for the version (When searching for the versions with a jql query, it pulls up 40+). If I click on the version, it reloads the issues and the issues disappear from the board. How can I integrate the process of refreshing the list of issues in the version into my scripts?

 

 

 

Script to create/assign the version:

import com.atlassian.jira.project.version.Version
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.project.Project
import java.util.Date
import java.text.SimpleDateFormat
import java.util.Calendar

//Query: (project = "Data Loads" or project = "Data Loads Direct") and fixVersion not in releasedVersions() and status = closed order by created DESC

def versionManager = ComponentAccessor.getVersionManager()
def project = new ArrayList<Project>()
project.add(issue.getProjectObject())
Date now = new Date()
String pattern = "MM/dd/yyyy";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
String name = simpleDateFormat.format(now)
def allVersions = versionManager.getAllVersionsForProjects(project, false)
def allNames = new ArrayList<String>()
for (v in allVersions)
{
allNames.add(v.name)
}
def versionExists = allNames.contains(name)
def currentVersion
if(versionExists)
{
currentVersion = allVersions[allNames.indexOf(name)]
}
else
{
Calendar calendar = Calendar.getInstance();
// Add 5 minutes to the calendar time
calendar.add(Calendar.MINUTE, 5);
def future = calendar.getTime()
currentVersion = versionManager.createVersion(name,now -1,future,"Autogenerated version for dataload tickets",issue.projectObject.id,null)
//currentVersion = versionManager.releaseVersion(currentVersion, true)
}
def versions = new ArrayList<Version>()
versions.add(currentVersion)
issue.setFixVersions(versions)
def user = ComponentAccessor.getUserManager().getUserByKey("ETLService")
ComponentAccessor.getIssueManager().updateIssue(user, issue, com.atlassian.jira.event.type.EventDispatchOption.DO_NOT_DISPATCH,false)

 

Script to release the version:

import com.atlassian.jira.project.version.Version
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.project.Project
import java.util.Date
import java.text.SimpleDateFormat
import java.util.Calendar
import com.atlassian.jira.bc.project.version.VersionService

//Query: (project = "Data Loads" or project = "Data Loads Direct") and fixVersion not in releasedVersions() and status = closed order by created DESC
//Cron: 0 0 17 ? * MON-FRI

def versionManager = ComponentAccessor.getVersionManager()
def project = new ArrayList<Project>()
project.add(issue.getProjectObject())
Date now = new Date()
String pattern = "MM/dd/yyyy";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
String name = simpleDateFormat.format(now)
def allVersions = versionManager.getAllVersionsForProjects(project, false)
def allNames = new ArrayList<String>()
for (v in allVersions)
{
allNames.add(v.name)
}
def versionExists = allNames.contains(name)
def currentVersion
if(versionExists)
{
currentVersion = allVersions[allNames.indexOf(name)]
}
def versionService = ComponentAccessor.getComponent(VersionService)
def user = ComponentAccessor.getUserManager().getUserByKey("ETLService")
def result = versionService.validateReleaseVersion(user, currentVersion, now)
if (result.isValid())
{
versionService.releaseVersion(result)
}
else
{
log.error "Could not release version '${currentVersion.name}' due to the following errors: $result.errorCollection.errors"
}

 

Is there a way to do this with a VersionService or something?

 

Thanks in advance!

1 answer

1 accepted

1 vote
Answer accepted
Ben Poulson
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 3, 2019

Think I may have answered my own question- I think the issues need to be reindexed after a fixversion is assigned. I'll have to wait a few hours to see if it worked (can't test it in the middle of the day), but I think it may have. New code to assign the version for posterity:

 

import com.atlassian.jira.project.version.Version
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.project.Project
import java.util.Date
import java.text.SimpleDateFormat
import java.util.Calendar
import com.atlassian.jira.issue.index.IssueIndexingService
import com.atlassian.jira.util.ImportUtils

//Query: (project = "Data Loads" or project = "Data Loads Direct") and fixVersion not in releasedVersions() and status = closed order by created DESC
//Cron: 0 0 15 ? * MON-FRI

def versionManager = ComponentAccessor.getVersionManager()
def project = new ArrayList<Project>()
project.add(issue.getProjectObject())
Date now = new Date()
String pattern = "MM/dd/yyyy";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
String name = simpleDateFormat.format(now)
def allVersions = versionManager.getAllVersionsForProjects(project, false)
def allNames = new ArrayList<String>()
for (v in allVersions)
{
allNames.add(v.name)
}
def versionExists = allNames.contains(name)
def currentVersion
if(versionExists)
{
currentVersion = allVersions[allNames.indexOf(name)]
}
else
{
Calendar calendar = Calendar.getInstance();
// Add 5 minutes to the calendar time
calendar.add(Calendar.MINUTE, 5);
//If the release time of the version is not set to be in the future, it doesnt work
//Because issues assigned to version after version is released stay on the board
def future = calendar.getTime()
currentVersion = versionManager.createVersion(name,now -1,future,"Autogenerated version for dataload tickets",issue.projectObject.id,null)
//currentVersion = versionManager.releaseVersion(currentVersion, true)
}
def versions = new ArrayList<Version>()
versions.add(currentVersion)
issue.setFixVersions(versions)
def user = ComponentAccessor.getUserManager().getUserByKey("ETLService")

//Commit the change
ComponentAccessor.getIssueManager().updateIssue(user, issue, com.atlassian.jira.event.type.EventDispatchOption.DO_NOT_DISPATCH,false)

//Reindex the issue
def issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService)
boolean wasIndexing = ImportUtils.isIndexIssues();
ImportUtils.setIndexIssues(true);
log.warn("Reindex issue ${issue.key} ${issue.id}")
issueIndexingService.reIndex(issue);
ImportUtils.setIndexIssues(wasIndexing);
Ben Poulson
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 3, 2019

I was right, this was the solution.

oidc-tc-edu January 1, 2020

Dear Mr. Poulson,

I have the similar situation like yours,

but I am kind a newbie to jira and programming,

my team is trying with this powerful tool to managing our customers' and programmers' issues,

would you like to kindly enlighten me about how to make your scripts work like charm?

what I mean is,

Are these scripts based on Python or JavaScript?

or I should build scripts with Groovy like the instruction described?

I found an instruction here:

https://igorpopov.io/2014/11/24/rocking-with-jira-script-runner/

and where should I put these two scripts inside jira working directories or a Linux system location to make them work?

our jira is built on a standalone Linux Cent OS 6.3 with MySQL database,

and I assume that I need to install script runner plugin on jira, right?

I will be grateful for your profound experience.

Respectfully,

Ben Poulson
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 3, 2020

Hi @oidc-tc-edu !

Are these scripts based on Python or JavaScript?

The script in the above comment is actually written in Groovy. Groovy is the language used with the ScriptRunner add-on (which is required to do this, as far as I know). Groovy is basically an offshoot of Java (it's a little more complicated than that, but that's the basic jist).

 

Don't use that guide, it's very outdated (its from 2014).

 

I assume that I need to install script runner plugin on jira, right?

Correct.

 

The way I'm running that script is using a feature of the ScriptRunner add-on called "Jobs". They used to be called "Escalation Services", but were renamed in a recent update. Basically, a job lets you schedule a script to run at a certain time using something called a cron expression. Cron expressions let you specify a time as specifically or broadly as you want (anything from "at midnight every day" to "every 3 minutes in every 6th hour on the 20th of every 3rd month")- here's some documentation on how to write them, they're pretty simple once you get your head around it http://javadox.com/org.quartz-scheduler/quartz/1.8.6/org/quartz/CronExpression.html. The cron expression I've set for this script is "0 0 17 ? * MON-FRI" (from 5PM, Monday to friday). 

 

The script above is actually only one half of the story. There's 2 steps to releasing a board: assigning a version to the tickets you want to drop off that board, and releasing that version. The script above does the first part. The second part is handled by the script below, which runs 5 minutes after the first one (the cron expression for the second script is "0 5 17 ? * MON-FRI").

 

import com.atlassian.jira.project.version.Versionimport com.atlassian.jira.component.ComponentAccessorimport com.atlassian.jira.project.Projectimport java.util.Dateimport java.text.SimpleDateFormatimport java.util.Calendarimport com.atlassian.jira.bc.project.version.VersionService
//Query: (project = "Data Loads" or project = "Data Loads Direct") and fixVersion not in releasedVersions() and status = closed order by created DESC//Cron: 0 5 15 ? * MON-FRI
def versionManager = ComponentAccessor.getVersionManager()def project = new ArrayList<Project>()project.add(issue.getProjectObject())Date now = new Date()String pattern = "MM/dd/yyyy";SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);String name = simpleDateFormat.format(now)def allVersions = versionManager.getAllVersionsForProjects(project, false)def allNames = new ArrayList<String>()for (v in allVersions){    allNames.add(v.name)}def versionExists = allNames.contains(name)def currentVersionif(versionExists){    currentVersion = allVersions[allNames.indexOf(name)]}def versionService = ComponentAccessor.getComponent(VersionService)def user = ComponentAccessor.getUserManager().getUserByKey("ETLService")def result = versionService.validateReleaseVersion(user, currentVersion, now)if (result.isValid()) {    versionService.releaseVersion(result)else{    log.error "Could not relase version '${currentVersion.name}' due to the following errors: ${result.errorCollection.errors}"}

Also note that the JQL query associated with the job needs to be the same for both jobs. The JQL query finds which issues the jobs are run on. Let me know if there is anything else I can help with!

Like oidc-tc-edu likes this

Suggest an answer

Log in or Sign up to answer