It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

Set assignee from component lead using script listener Edited

Alvin Parreno Sep 13, 2018

Hello Community, I need help on scriptrunner, I need to set assignee based on the component's lead. Below is the code that I'm using

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption


// a map with select list option to Component
def componentsMap = [
"BOSS" : "Component1",
"Mashery" : "Component2",
]

def issue = event.issue as MutableIssue

def selectList = ComponentAccessor.customFieldManager.getCustomFieldObjectByName("Affected Service")
def selectListValue = issue.getCustomFieldValue(selectList) as LazyLoadedOption

// there is no value for the select list - therefore do nothing
if (! selectListValue) {
return
}

def componentManager = ComponentAccessor.projectComponentManager
def componentName = componentsMap.get(selectListValue.value)
def component = componentManager.findByComponentName(issue.projectObject.id, componentName)
def userManager = ComponentAccessor.userManager
def components = issue.componentObjects.toList()

if (component) {
componentManager.updateIssueProjectComponents(issue, [component])
}
issue.setAssignee(ComponentAccessor.userManager.getUserByKey(component.lead))

 

In this code, I have Affected Service as a single select list, if BOSS has been selected, the Component Field will update and set to Component1, but the assignee remains unassigned even if I have default assignee on my component. I know that there's something wrong with my code because I'm a beginner. I need to change assignee everytime component field is changed, that's why I used script listener. Thanks

2 answers

1 accepted

1 vote
Answer accepted
Charlie Misonne Community Leader Sep 13, 2018

Hi Alvin

Assigning an issue with a script is more complex. Jira needs to check whether the assignment is valid. Therefore you have to use th issueService.

Replace your issue.setAssignee line with:

def issueService = ComponentAccessor.getIssueService()
def user = component.componentLead
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def assignmentValidation = issueService.validateAssign(currentUser, issue.id, user.key)
if (assignmentValidation.isValid()){
    issueService.assign(user, assignmentValidation)
} else {
    log.debug(assignmentValidation) // you probably have to loop through the ErrorCollection object
}

At the top of the script you can import loggers and set the level. It can be useful to have some logging when troubleshooting:

import org.apache.log4j.Logger
import org.apache.log4j.Level
 
def log = Logger.getLogger("com.yourjira.componentupdate")
log.setLevel(Level.DEBUG)
Alvin Parreno Sep 13, 2018

Hi @Charlie Misonne, Thank you for the very fast response. will try this now and update you. Thank you!

Alvin Parreno Sep 13, 2018

Hi @Charlie Misonne , it shows some error. can you help me?

2018-09-13 10:10:19,380 ERROR [runner.AbstractScriptListener]: *************************************************************************************
2018-09-13 10:10:19,409 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: <inline script>
java.lang.NullPointerException: Cannot get property 'componentLead' on null object
 at Script1208.run(Script1208.groovy:37)

 

import org.apache.log4j.Logger
import org.apache.log4j.Level
def log = Logger.getLogger("com.yourjira.componentupdate")
log.setLevel(Level.DEBUG)
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption


// a map with select list option to Component
def componentsMap = [
"BOSS" : "Component1",
"Mashery" : "Component2",
]

def issue = event.issue as MutableIssue

def selectList = ComponentAccessor.customFieldManager.getCustomFieldObjectByName("Affected Service")
def selectListValue = issue.getCustomFieldValue(selectList) as LazyLoadedOption

// there is no value for the select list - therefore do nothing
if (! selectListValue) {
return
}

def componentManager = ComponentAccessor.projectComponentManager
def componentName = componentsMap.get(selectListValue.value)
def component = componentManager.findByComponentName(issue.projectObject.id, componentName)
def userManager = ComponentAccessor.userManager
def components = issue.componentObjects.toList()

if (component) {
componentManager.updateIssueProjectComponents(issue, [component])
}

def issueService = ComponentAccessor.getIssueService()
def user = component.componentLead
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def assignmentValidation = issueService.validateAssign(currentUser, issue.id, user.key)
if (assignmentValidation.isValid()){
issueService.assign(user, assignmentValidation)
} else {
log.debug(assignmentValidation) // you probably have to loop through the ErrorCollection object
}

and this is the whole code , already applied your suggestions 

Charlie Misonne Community Leader Sep 13, 2018

That error means the component is null.

On your issue: do you selected a value for Affected Service?

And does Component1 and Component2 exist in your project?

 

It's probably safer if you put the assignment part in your if:

log.debug(component)
if (component) {
    componentManager.updateIssueProjectComponents(issue, [component])
    def issueService = ComponentAccessor.getIssueService()
    def user = component.componentLead
    def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
    def assignmentValidation = issueService.validateAssign(currentUser, issue.id, user.key)
    if (assignmentValidation.isValid()){
        issueService.assign(user, assignmentValidation)
    } else {
        log.debug(assignmentValidation) // you probably have to loop through the ErrorCollection object
    }
}

I also added  log.debug(component)

You can check the execution log after updating your Affected Service field to check whether the component was found.

Alvin Parreno Sep 13, 2018

@Charlie Misonne That works so perfectly ! Thank you for helping me! I missed the part on editing the component1, you're a life saver. Thank you!!

Charlie Misonne Community Leader Sep 13, 2018

You're welcome @Alvin Parreno!

Alvin Parreno Sep 13, 2018 • edited

Hi @Charlie Misonne, I add Issued Updated on event to fire on because I think that's the way for the Assignee to change everytime Component/s field change. but I see that it neglects my edit and it goes back to the original issue posted. Any thoughts about this? Thank you.

Charlie Misonne Community Leader Sep 13, 2018

So it was working a couple of hours ago but now it doesn't?

Issue Udpated is the correct event to use.

Have you selected your project in the Project Key picker?

Alvin Parreno Sep 13, 2018

@Charlie Misonne, yep its working perfectly. Before, the event is only Issue Created and it works really well, then now I try to add Issue Updated, so there are two events now, Issue Created and Issue Updated. But whenever I tried to Edit Component/s field, (i.e. I change it to JIRA) , it just neglect my edit and sticks to what I've created. (if I create issue with Affected Services = BOSS , Component/s = Component1 , and assignee will be the component lead , it stays the same even if I edit it.) 

But when I update issue with one event only (which is Issue Created) , it can be edited but thee Component/s Field woudn't change. 

I just want to go deeper escalation with these Component/s , Is it possible ? Thank you!

Alvin Parreno Sep 13, 2018 • edited

@Charlie Misonne , I found out  that the Component/s , and the Assignee relies on the value of the Affected Service. Thank you for helping me ! I really appreciate it. Thanks!

Charlie Misonne Community Leader Sep 14, 2018

@Alvin Parrenoglad it was resolved!

Alvin Parreno Sep 14, 2018

Hi @Charlie Misonne , I just have a quick question here, how can I map multiple attributes to one value?

 

Script below

def componentsMap = [
"BOSS" : "Component1",
"WORK" : "Component1",
"Class" : "Component1",
"Mashery" : "Component2",
]

 

 

I tried to make it like this, but no luck. Thank you 

def componentsMap = [
["BOSS","WORK,"Class" ] : "Component1",
"Mashery" : "Component2",
]

Charlie Misonne Community Leader Sep 14, 2018

Apparenlty there is a MultikeyMap but I have absolutely no experience with it. http://www.tothenew.com/blog/multikeymap-nested-maps-solution/

Alvin Parreno Sep 16, 2018

Thank you @Charlie Misonne, will check on this

Alvin Parreno Sep 25, 2018

@Ivan Tovbin I tried to use MultiKeyMap but it keeps on giving me unresolved class even if I import MultiKeyMap. Thank you

Ivan Tovbin Community Leader Sep 25, 2018

@Alvin Parreno 

I assume your idea is to be able to pull the required component by using ANY of the attributes, right? Problem with MultiKeyMap is that you have to provide a set of ALL attributes mapped to a value to get that value. Surely, it's possible to write a logic that would first search all attribute sets for the attribute you need and then use that set to pull a value, but that's a bit too complicated imho. 

That said I would suggest using a regular map. That way you'll be able to pull your component by using ANY attribute, mapped to it, not a combination of all attributes:

Map<String, String> map = new HashMap<>()
map.put("attribute1", "component1")
map.put("attribute2", "component1") 
map.put("attribute3", "component1") 
map.put("attribute4", "component2") 
map.put("attribute5", "component2") 
map.put("attribute6", "component2")

and so on.. 

Alvin Parreno Sep 25, 2018

Hi @Ivan Tovbin , Thank you for your help, just want to clarify, so if I have 150+ attribute, that would be equal to 150+ lines?

Ivan Tovbin Community Leader Sep 25, 2018

In any case, even if you have a problem importing MultiKeyMap class, you can always use a regular Map, and simply use a collection of strings as its key, like so:

Map<List<String>, String> map = new HashMap<>()
map.put(Arrays.asList("attribute1", "attribute2", "attribute3"), "component1")
map.put(Arrays.asList("attribute3", "attribute4", "attribute5"), "component2")

But like I said, to get a value from this map you'll need to either provide the whole collection of attributes or create a logic that would first search for your attribute in all collections and then use the collection that contains it. For that i'd create a function:

Map<List<String>, String> map = new HashMap<>()
map.put(Arrays.asList("attribute1", "attribute2", "attribute3"), "component1")
map.put(Arrays.asList("attribute3", "attribute4", "attribute5"), "component2")

List<String> getAttributeList(String attribute, Map map){
List<String> attributeList = new ArrayList<>()
attributeList = map.keySet().find{it.contains(attribute)}
return attributeList
}

map.get(getAttributeList("attribute4", map))
Alvin Parreno Sep 25, 2018

 Hi @Ivan Tovbin, I tried to use your code but it returned an error

Screenshot from 2018-09-25 17_06_39.png

Ivan Tovbin Community Leader Sep 25, 2018

@Alvin Parreno You can ignore these errors. Scriptrunner's static type checking is not always accurate.

Alvin Parreno Sep 25, 2018

Hi @Ivan Tovbin, will do what you've suggest. will give feedback later. Thank you so much!

0 votes
Alvin Parreno Sep 24, 2018

Hi @Charlie Misonne , I just want to ask something. How can I add Group , from Single Group picker field, based on the value of the Affected Service Field. 

Scenario right now  is  whenever requestor selects "BOSS" as value of Affected Service Field, Component Field will be updated and  Assignee will be the Component Lead.

Now I want to add Group too, based on the Value of Affected Service Field inside the condition. Can you help me? Thank you!

Suggest an answer

Log in or Sign up to answer
This widget could not be displayed.
This widget could not be displayed.
Community showcase
Published in Opsgenie

Handling Opsgenie Alerts

Hi everyone, welcome to the kb articles for Opsgenie FAQs. I'm one of the Technical Support Engineers for Opsgenie who will be providing weekly posts on FAQs from customers.   All alerts are ...

71 views 0 3
Read article

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you