Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Help with script to add new Cascading Select parent and child options to multiple contexts for field

Bryan Karsh December 11, 2018 edited

Hi there,

I know this type of question has been asked many times here, but I am stuck on my particular edge case. We have a Cascading Select field that is used throughout our company for business logic. It has over a hundred contexts. Fairly often, requests will be made to add an option (or more) to all contexts in the field. This would be a manual nightmare.

I know there is the most excellent built-in scriptrunner script for bulk updating custom fields options... and I would certainly use that if it could apply to all contexts at once. But alas, it makes me pick one at a time.

I know back in the day, the source for that script was available to look at. I know that is no longer an option. So.. looking at various examples, I started to cobble something together (see below). Right now what I have will iterate through all the contexts and list the Parent  and Child options.

What I need help with is the bit where I want to add the new options. Let's say I have:

Foo1

  Bar1

  Bar2

Foo2

  Bar3

  Bar4

 

-- and I want to add those as options to each context. I'm assuming I'd need to put it in some sort of map, and add it to the options that way. But the devil's in the details, and I am hitting a wall.

 

1 answer

1 accepted

0 votes
Answer accepted
Bryan Karsh December 15, 2018 edited

I ended up creating this -- which seems to do the job. Feel free to suggest ways it can be improved! It uses a delimited text file (projectKey#parentOption#childOption) as its source.

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.context.IssueContextImpl;
import com.atlassian.jira.issue.customfields.option.Option
import groovy.xml.MarkupBuilder

def customFieldManager = ComponentAccessor.getCustomFieldManager();
def optionsManager = ComponentAccessor.getOptionsManager()
def projectManager = ComponentAccessor.getProjectManager()

def writer = new StringWriter()
def xml = new MarkupBuilder(writer)


Long parentSequence = 100L // used to indicate where parent option is displayed in field

Long childSequence = 100L // use to indicate where child option is displayed in field


/*

Notes:

-- script doesn't create contexts -- still need to implement that
it works fine if contexts exist already

-- it tokenizes on '#' currently, since some options may have
commas in them


*/


String filePath = "/path/to/file.txt"

filePath = filePath.trim()

def inputFile = new File(filePath);

def cf = customFieldManager.getCustomFieldObject(10107L) // Enter cf id

String issueTypeId = '10000' // Incident IssueType (replace with whatever) -- used (with projectKey) to find issueContext.

// so I can get pretty output in the script runner console (could be used for email results too)
xml.style(type: "text/css",
'''
#scriptField, #scriptField *{
border: 1px solid black;
}

#scriptField{
border-collapse: collapse;
}
''')

xml.table(id: "scriptField") {
tr {
th("Project")
th("Parent")
th("Child")
th("notes")
}


List lines = inputFile.readLines()
//lines.remove(0) // remove header in input file
lines.each {


def fields = it.tokenize('#')

def projectKey = ""
def parent = ""
def child = ""

if (fields.size() == 3) {


projectKey = fields.get(0)
parent = fields.get(1)
child = fields.get(2) ?: "all"

} else {
projectKey = fields.get(0)
parent = fields.get(1)
child = "all"


}


// if (projeKey.equals("Foobar")) { // incase you want to test on one project first

try {

def projectId = projectManager.getProjectObjByKey(projectKey).getId()

def issueContext = new IssueContextImpl(projectId, issueTypeId)

def fieldConfig = cf.getRelevantConfig(issueContext);

def options = optionsManager.getOptions(fieldConfig);

def rootOptions = options.getRootOptions()

if (parentAlreadyPresent(rootOptions, parent)) { // don't add parent, but look it up

def parentOption = getExistingParent(rootOptions, parent)

Long parentOptionID = parentOption.optionId

if (childAlreadyPresent(parentOption, child)) { // don't add child, go to next line in file
tr {
td(projectKey)
td(parent)
td(child)
td("Parent exists; Child exists")
}

return
} else {
optionsManager.createOption(fieldConfig, parentOptionID, childSequence, child) // add child


childSequence++

tr {
td(projectKey)
td(parent)
td(child)
td("Parent exists; Child added")
}

}
} else {


def parentOption = optionsManager.createOption(fieldConfig, null, parentSequence, parent)


parentSequence++




if (childAlreadyPresent(parentOption, child)) { // don't add child, go to next line ine file
tr {
td(projectKey)
td(parent)
td(child)
td("Parent added; Child already exists (note: this shouldn't happen!!)")
}


return
} else {

Long parentOptionID = parentOption.optionId
optionsManager.createOption(fieldConfig, parentOptionID, childSequence, child)

childSequence++

tr {
td(projectKey)
td(parent)
td(child)
td("Parent added; Child added")
}

}


}
}
catch (e) {
td(projectKey)
td(parent)
td(child)
td(e.message)

}

// }

// else {

// return
// }


}
}


return (writer.toString())


boolean parentAlreadyPresent(List<Option> rootOptions, String value) {
for (Option o : rootOptions) {
if (o.getValue().equals(value)) {
return true;
}
}
return false;
}

def getExistingParent(List<Option> rootOptions, String value) {
for (Option o : rootOptions) {
if (o.getValue().equals(value)) {
return o;
}
}

}


boolean childAlreadyPresent(Option parentOption, String value) {

def childOptions = parentOption.getChildOptions()

for (Option childOption in childOptions) {

if (childOption.getValue().equals(value)) {
return true;
}
}

return false;
}

 

Suggest an answer

Log in or Sign up to answer
TAGS
atlassian, social impact bingo, may it forward, atlassian foundation, community engagement, atlassian community events, atlassian learning, social impact challenge, volunteering, community kudos, atlassian social impact, atlassian community

Come one, come all!

Hey everyone! Are you ready to make a difference? Join the Atlassian Social Impact Bingo event! ❌⭕

Play Bingo! 🙋🏻‍♂️
AUG Leaders

Atlassian Community Events