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

Scriptrunner: How to list approvers?

kilinich May 10, 2018

I'm trying to write script to notify approvers via slack ot issue transition.
I choose script listener (not post-finction) due to large number of possible transitions.
So how to do following:

  1. Detect if issue require approval
  2. Get list of approvers (later with their descisions)

I've done that before on cloud version via REST API, there is no problem with that, but in server version I've got original issue (not after transition) so there is no approval yet in moment of transition. I've try to access approval custom field, but there is no approvers info in it.  I've try to search examples how to work with approvals in scriptrunner, but no dice. I've try following code to test jira java api, but it's not working...

@WithPlugin ("com.atlassian.servicedesk")
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.servicedesk.api.approval
def issue = ComponentAccessor.getIssueManager().getIssueObject("DVPT-1")
ApprovalQuery query = approvalService.newQueryBuilder().issue(issue).build()

it shows error about "ApprovalQuery" class. What I need to import to have it?

How to work with approvals?

6 answers

Suggest an answer

Log in or Sign up to answer
0 votes
Aleksandar Salevski January 13, 2021

Hi All,

 

How to get the user who approved the ticket and then set him as assignee  to that ticket. second part is easy but im struggling with first one.

0 votes
Kirill Ilinich April 18, 2019

A bit simpler via customField:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.servicedesk.api.approval.ApprovalService
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
@WithPlugin("com.atlassian.servicedesk")
def issue = ComponentAccessor.getIssueManager().getIssueObject("DVPS-7010") // For console testing
def robotUser = ComponentAccessor.getUserManager().getUserByKey("robot-manager")
def approvalService = ComponentAccessor.getOSGiComponentInstanceOfType(ApprovalService)
def approval = issue.getCustomFieldValue(ComponentAccessor.getCustomFieldManager().getCustomFieldObjectsByName('Approvals').first()).getApprovals()
if (approval && !approval.first().getDecision().isPresent()) {
def approvalsNeeded = approvalService.getApprovers(robotUser, approval.first()).findAll{!it.getApproverDecision().isPresent()}.collect{it.getApproverUser().name}
log.info("Approvals needed: $approvalsNeeded")
//
// Remind to approve
//
} else {
log.warn("No pending approvals found for issue [$issue.key]")
}
Marina Veselić August 23, 2019

Nicely done! The code was very helpful!

We had a case where we needed to implement approving issues via e-mail. We used a script for that. At first, we implemented only issue transitions based on the content of the mail. That wasn't good because the approvals did not get recorded and approvers didn't see their approved issues. 

This code was a good basis to get what we needed and to trigger transitions and to get approvals to register.

Example snippet, if anyone should need it:

...
if(unansweredApproval!=null && approvalService.canAnswerApproval(approver,unansweredApproval)){
if(com.getBody().contains("Approve")){
approvalService.answerApproval(approver,unansweredApproval,ApprovalDecisionType.APPROVED);
} else if(com.getBody().contains("Decline")){
approvalService.answerApproval(approver,unansweredApproval,ApprovalDecisionType.REJECTED);
}
}
...

The only thing that didn't work for us was 

approval.first().getDecision().isPresent()

It returned the firs approval. Which is ok if you only have one level of approval. But it, in the end, was simple to find the one approval that doesn't have a decision.

Anyways, thanks for the post. I wanted you and other participants to know that somebody found it useful. :)

 

Cheers,

Marina

Evgeniy
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.
September 6, 2021

Marina, thanks for your snippet.

But what is 

com.getBody()

in your code?

Marina Veselić September 6, 2021

Hi Udjin,

the snippet is inside the loop

for(Comment com : commentManager.getComments(issue)) {

...

}

Cheers,
Marina

Evgeniy
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.
September 6, 2021

Oh, understood. You took value from comment, and approve/disapprove depending on value. Thank you!

0 votes
Kirill Ilinich April 17, 2019

@Vadim Lutsevich I've got code for Jira 8 now.

Vadim Lutsevich April 18, 2019

Thanks! But I realized this feature via JQL :)

Kirill Ilinich April 18, 2019

To list approvers? 

0 votes
Kirill Ilinich April 17, 2019

That's what I came up with:

import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.servicedesk.api.approval.ApprovalService
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
@WithPlugin("com.atlassian.servicedesk")
logs = Logger.getLogger("com.acme.customListener")
logs.setLevel(Level.DEBUG)

def issue = ComponentAccessor.getIssueManager().getIssueObject("DVPS-7011") // console testing

def robotUser = ComponentAccessor.getUserManager().getUserByKey("robot-manager")
def approvalService = ComponentAccessor.getOSGiComponentInstanceOfType(ApprovalService)
def approvalQuery = approvalService.newQueryBuilder().issue(issue.id).build()
def approvalOpt = approvalService.getApprovals(robotUser, approvalQuery).findFirst()
if (approvalOpt.isPresent() && !approvalOpt.get().getDecision().isPresent()) {
def approvalsNeeded = approvalService.getApprovers(robotUser, approvalOpt.get()).findAll{!it.getApproverDecision().isPresent()}.collect{it.getApproverUser().name}
logs.info("Approvals needed: $approvalsNeeded")
//
// Remind to approve
//
} else {
logs.info("No pending approvals found for issue [$issue.key]")
}

 

0 votes
Kirill Ilinich April 17, 2019

Not working in Jira 8 anymore. Need code update!

0 votes
Thanos Batagiannis _Adaptavist_
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.
July 17, 2018

Hi Kirill,

The Approvals and the Approvers are actually custom fields, therefore you can retrieve their values in the usual way 

import com.atlassian.jira.component.ComponentAccessor

def issue = ComponentAccessor.getIssueManager().getIssueObject("SD-2")

def approversCF = ComponentAccessor.customFieldManager.getCustomFieldObjects(issue).find {it.name == "Approvers"}
def approvers = issue.getCustomFieldValue(approversCF)

log.debug approvers //a list of ApplicationUsers

def approvalsCF = ComponentAccessor.customFieldManager.getCustomFieldObjects(issue).find {it.name == "Approvals"}
def approvals = issue.getCustomFieldValue(approvalsCF)

log.debug approvals // a list of Approval see https://docs.atlassian.com/jira-servicedesk/3.9.0-m0124/com/atlassian/servicedesk/api/approval/Approval.html
kilinich July 17, 2018

Jira Server 7.11?
Actually, you are waaay wrong /-)

You script returns:


2018-07-17 16:38:48,068 INFO [runner.ScriptRunnerImpl]:
2018-07-17 16:38:48,072 INFO [runner.ScriptRunnerImpl]: com.atlassian.servicedesk.plugins.approvals.internal.customfield.ApprovalsCFValue@475f642

 I found the way to get those values, but another bug (no values on transition) prevents me from implement listener script:

import com.atlassian.jira.component.ComponentAccessor


def issue = ComponentAccessor.getIssueManager().getIssueObject('DVPT-1')
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
log.info("User: $currentUser.name")

import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.atlassian.servicedesk.api.approval.ApprovalService

@WithPlugin
("com.atlassian.servicedesk")

def approvalService = ComponentAccessor.getOSGiComponentInstanceOfType(ApprovalService)
def approvalQuery = approvalService.newQueryBuilder().issue(issue.id).build()
def approvalEither = approvalService.getApprovals(currentUser, approvalQuery)
def approvals = approvalEither.isRight() ? approvalEither.right : []
def pendingApproval = approvals.find{!it.getDecisionDetails().getOrNull()?.getDecision()}
def approversList = []
if (pendingApproval) {
def approversEither = approvalService.getApprovers(currentUser, pendingApproval)
def approvers = approversEither.isRight() ? approversEither.right : []
approversList
= approvers.findAll{!it.getApproverDecision().getOrNull()}.collect{it.getApproverUser().name}
log.info("Pending approval of: $approversList")
}
Thanos Batagiannis _Adaptavist_
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.
July 18, 2018

Kirill, 

The ApprovalCFValue is a collection of approvals

public ApprovalsCFValue(Collection<Approval> approvals) {
this.approvals = approvals;
}

Do not try to overcomplicate things, those are custom fields treat them as custom fields. 

kilinich July 18, 2018

Colud you drop me a working code for listing pending approvers please? 

Code should return just a list of login...

Thank you!

Vadim Lutsevich March 1, 2019

@kilinich do you have any working code? Share it please, I can't make my script (that based on this topic) works.

Kirill Skachkov March 1, 2019

Nope, Adaptavista confirm that problem but there is no solution yet, so I add notification in post-function instead of listener

TAGS
AUG Leaders

Atlassian Community Events