Groovy script help: To compare EPIC Link due date with today before transitioning the Issue in Epic State to Done.

Hi,

I add written below script validator to check whether "EPIC Link" Due Date is matching with today's date or not before transitioning the "Issue in Epic" State to Done state.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.index.IssueIndexManager
import java.util.concurrent.TimeUnit

def issue = event.issue // event is an IssueEvent
def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def issueIndexManager = ComponentAccessor.getComponent(IssueIndexManager)
issueLinkManager.getInwardLinks(issue.id).each {issueLink ->
if (issueLink.issueLinkType.name == "EPIC Link") {
def linkedIssue = issueLink.getSourceObject()
def today = new Date()
if (today == linkedIssue.getDueDate()) { return true}
issueIndexManager.reIndexIssueObjects([linkedIssue])
}
}

Error Message: Release planned "ITG_IN" Date is not yet Met to Commit the code changes into planned Release branch !

The above Error message that will be provided to the user if the condition is not true

But the above script is always returning False with the set Error message eventhough EPIC Link due date is set as today's date.


Please advice, if there is any issue in the above script posted here.

4 answers

1 accepted

1 vote

You will need a custom scripted validator on the Done transition for this. If I understand you want to only allow the transition if the epic for the issue you are transitioning has due date of todays date.

The following code should do that:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.opensymphony.workflow.InvalidInputException

def issue = issue as Issue

def customFieldManager = ComponentAccessor.getCustomFieldManager()

def epicLinkCf = customFieldManager.getCustomFieldObjectByName("Epic Link")

def epicLink = issue.getCustomFieldValue(epicLinkCf) as Issue
// This format depends on your JIRA configuration
def todaysDate = new Date().format('dd/MM/yy')

def dueDate = epicLink.dueDate?.dateString

if (! dueDate.equals(todaysDate)) {
    throw new InvalidInputException("Due date in epic is not today!")
}

You can also use a simple scripted validator for this, but you will only need as the condition:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.opensymphony.workflow.InvalidInputException

def issue = issue as Issue

def customFieldManager = ComponentAccessor.getCustomFieldManager()

def epicLinkCf = customFieldManager.getCustomFieldObjectByName("Epic Link")

def epicLink = issue.getCustomFieldValue(epicLinkCf) as Issue
def todaysDate = new Date().format('dd/MM/yy')

def dueDate = epicLink.dueDate?.dateString

! dueDate.equals(todaysDate)

For setting the due date of the epic you need the following script:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.opensymphony.workflow.InvalidInputException

def issue = issue as Issue
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issueService = ComponentAccessor.getIssueService()
def epicLinkCf = customFieldManager.getCustomFieldObjectByName("Epic Link")
def epicLink = issue.getCustomFieldValue(epicLinkCf) as Issue
def dueDate = epicLink.dueDate

if (! issue.dueDate){
    throw new InvalidInputException("Released requested 'RG_IN' Due Date is to be updated, to Commit the code changes into planned Release branch !")
}

if(issue.dueDate > dueDate){

    def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

    def epicDueDate = issue.dueDate.format("dd/MMM/yy")
    def issueInputParameters = issueService.newIssueInputParameters().setDueDate(epicDueDate)

    def updateValidationResult = issueService.validateUpdate(currentUser, epicLink.id, issueInputParameters)

    if (updateValidationResult.isValid()) {
        issueService.update(currentUser, updateValidationResult)
    } else {
        log.warn updateValidationResult.errorCollection.errors
    }
}

Here we use issue service to do the update, there is no setDueDate method on the issue which is why you were seeing that error.

Thank you very much for sharing the needed script for my usage Adam Markham .

While testing the  above shared simple scripted validator script in my worflow, I have observed the below issues and need your further feedback on the same.

1) When Due Date value set for EPIC is empty, "Issues in Epic" state transitions to Done successfully.

"Issue in Epic" state transition to DONE state should successfully happen only when the, EPIC's Due Date field is equal to today's date. otherwise it should fail and remains in current state.

Please share u'r feedback/inputs on whether the above my requirement is handling in the above script? Thanks.  

Hi, this should work for empty due dates, it seemed to work when I tested this. You can change the if statement to:

if (! dueDate || ! dueDate.equals(todaysDate)) {

Which should work.

Hi Adam Markham,

I tried to debug the script shared by you - it's really helped me a lot. Thanks again.

dueDate: 2016-07-25 16:55:04,973 DEBUG [workflow.ScriptWorkflowFunction]: 7/28/16
todaysDate: 2016-07-25 16:55:04,973 DEBUG [workflow.ScriptWorkflowFunction]: 25/Jul/16
As I am getting EPIC's Due Date in the M/dd/yy format (it's set as per my Jira server configuration).
I changed todaysDate format to M/dd/yy format - it worked for me now.
 

Ah I see, have updated my answer code to reflect that. No problem, glad you got it sorted.

Hi Adam,

is it possible to add one more check like before 3 days and after 2 days of dueDate.equals(todaysDate), also we should allow team to commit the changes into sub-version !

is this achievable?

  • Manju

Thanks Adam for your valuable feedback.

I tired to test the due date set script shared by you. But it's showing warning to use JiraAuthenticationContext().getUser instead of getJiraAuthenticationContext().getLoggedInUser().

After modifying as below, it throwing an error saying that "can not find the matching method".

def currentUser = ComponentAccessor.JiraAuthenticationContext().getUser()

 

Also for the below line, it's showing warning to use IssueService.validateUpdate() method.

def updateValidationResult = issueService.validateUpdate(currentUser, epicLink.id, issueInputParameters)

After modifying the above line as below, still showing the same warning ...

def updateValidationResult = IssueService.validateUpdate(currentUser, epicLink.id, issueInputParameters)

 Please advice ... I am using JIRA v6.7.11. Thanks.

Please ignore the deprecation warning. My script will work for you. 

If you really want to use:

def currentUser = ComponentAccessor.JiraAuthenticationContext().getUser()

When you pass currentUser to validateUpdate and update you will need to pass it as:

com.atlassian.jira.user.ApplicationUsers.from(currentUser)

Yes Adam, your script works as expected as per my requirement posted before.

Thank you very much Again for your prompt feedback on the same.

When I update the EPIC due date, if Issue Due date > Epic Due Date and I would like to change the EPIC status from "To Do" to "In Progress" state in the same script.

I tried to use the getStatusId() and setStatusId() functions to change the EPIC status from To Do to In Progress. But it's not working. 

def issueInputParameters1 = issueService.newIssueInputParameters().getStatusId()
if (issueInputParameters1 == 'To Do') {
log.debug ('EPIC Status in in To Do state')
def issueInputParameters2 = issueService.newIssueInputParameters().setStatusId('In Progress')
}

You need to do the actual transition you can't just set the status id, that won't work.

I'd consider using the fast-track as the final post-function which will do the transition for you: https://scriptrunner.adaptavist.com/latest/jira/builtin-scripts.html#_fast_track_transition_an_issue

Thanks for your feedback Adam.

But In Script workflow function : Fast-track transition an issue - we need to check if(issue.dueDate > dueDate) (i,e only if EPIC due date is set successfully - from the above due date set posted script), then I need to move the EPIC current status from "To Do" to "In Progress" by adding the Action(IN PROGRESS(281)) from the EPIC workflow defined (i,e different from "Issue in Epic" workflow defined).

I hope my understanding is correct from your above suggestion. Thanks.

Appreciate any quick feedback on my script shared before. Thanks.

I am looking to do the simillar functionality as below using built-in script runner (if any)::

The value of field ITG_IN Due Date will be copied to the issues linked to the current issue by the is Epic of link type (replacing existing values).

The above is done using:: Copy Field Value To Linked Issues post function is actually provided by the "JIRA Misc Workflow Extensions add-on".

Thank you very much for sharing the needed script for my usage Adam Markham .

While testing the  above shared simple scripted validator script in my worflow, I have observed the below issues and need your further feedback on the same.

1) When Due Date value set for EPIC is empty, "Issues in Epic" state transitions to Done successfully.

"Issue in Epic" state transition to DONE state should successfully happen only when the, EPIC's Due Date field is equal to today's date. otherwise it should fail and remains in current state.

Please share u'r feedback/inputs on whether the above my requirement is handling in the above script? Thanks.   

Hi Adam,

In continuation to the suggested EPIC Due Date validation, I want to modify the EPIC Due Date value into another Due Date value from the linked Issues Max Due Date set as below:

But I am getting error, while doing this set operation:: epicLink.setDueDate(issue.dueDate);

Cann't find matching method; please suggest why it's so??

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.opensymphony.workflow.InvalidInputException
log.setLevel(org.apache.log4j.Level.DEBUG)
def issue = issue as Issue
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def epicLinkCf = customFieldManager.getCustomFieldObjectByName("Epic Link")
def epicLink = issue.getCustomFieldValue(epicLinkCf) as Issue
def dueDate = epicLink.dueDate
log.debug (dueDate)
log.debug (issue.dueDate)
if (! issue.dueDate){
throw new InvalidInputException("Release requested 'ITG_IN' Due Date is to be updated, to Commit the code changes into planned Release branch !")

if(issue.dueDate > dueDate){
epicLink.setDueDate(issue.dueDate)
log.debug (issue.dueDate)
log.debug (dueDate)
return true }

Also I need to change/set the EPIC JIRA Issue status along with modifying the EPIC's Due Date, based on the "Issues in Epic" Issue Type's Status after validating the Due Dates as explained above. 

Hi Adam,

I tried to do "epicLink.dueDate?.dateString = issue.dueDate" for change/set the the EPIC due date with one of the Issues in EPIC issue type's due date value. But got the readOnlyPropertyException error as below::

 

2016-08-10 14:30:22,978 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: KPTT-8151, actionId: 71, file: <inline script>
groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: dateString for class: java.sql.Timestamp
	at Script1273.run(Script1273.groovy:17)
  • Manju

Hi Adam,

How we have done the above shared script before for updating the EPIC Due date based on the associated Issues's due date Max value.

I tried to write a script to copy one of the custom field(i,e SDD Document Version updated) value from an associate issues of a specific EPIC to Epic's custom field(i,e SDD Doc Version Committed in Sprint) value.

But it's not updated as part of the EPIC, when I check in the view screen and also there is no error when it updated into EPIC's custom field value as below.

 

Time (on server): Mon Mar 06 2017 12:07:46 GMT+0530 (India Standard Time)

The following log information was produced by this execution. Use statements like:log.info("...") to record logging information.

2017-03-06 12:07:46,048 DEBUG [workflow.ScriptWorkflowFunction]: 12.0
2017-03-06 12:07:46,049 DEBUG [workflow.ScriptWorkflowFunction]: KPTT-7982
2017-03-06 12:07:46,050 DEBUG [workflow.ScriptWorkflowFunction]: 12.0

I tried to debug, why the versionUpdated value is not copied into the customfield value of a epicLink even though setCustomFieldValue() is success in the above posted script.  But didn't get any clue yet... Please advice why it's so? whether the script approach used is wrong???

SDD Doc Version Committed in Sprint (EPIC's custom field) and SDD Document Version updated (Associated issues custom field) are number data type fields.

import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.component.ComponentAccessor
  
log.setLevel(org.apache.log4j.Level.DEBUG)

CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
  
def versionUpdated = issue.getCustomFieldValue(ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("SDD Document Version updated"));

log.debug(versionUpdated) 
 
MutableIssue epicLink = issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Epic Link")) as MutableIssue;
log.debug(epicLink)

//Here I am trying copy SDD Document Version updated field value to "SDD Doc Version Committed in Sprint" field of EPIC associated to the current issue..

epicLink.setCustomFieldValue(
        ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("SDD Doc Version Committed in Sprint"),
        versionUpdated
)

/* this is to verify whether EPIC's custom field value is updated or not */
def SprintversionUpdated = epicLink.getCustomFieldValue(ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("SDD Doc Version Committed in Sprint"));

log.debug(SprintversionUpdated)

@Adam Markham [Adaptavist]

Please let me know, whether the script approach/method used is wrong or right approach???

Hi, this is a very old question. I've answered your initial question.

Could you please open another question with your script and explain what you want to achieve. Then someone will look at it for you otherwise it will get lost here.

Thanks Adam for your prompt response.

Your true, I will do the same based on your suggestion.

Adam - If you don't mind, I will try to add you in the another opened question to point this issue easily for you.

As I am not getting any clue on why EPIC's custom field value is not updated even though I am able to set the value successfully using epicLink.setCustomFieldValue() without any errors and able to retrieve the set value also using epicLink.getCustomFieldValue().

But if I open the KPTT-7982 EPIC ticket and check this set value, but it's empty. I need some debugging clue to proceed further Adam as I had blocked with this. Thanks in advance.

Suggest an answer

Log in or Sign up to answer
How to earn badges on the Atlassian Community

How to earn badges on the Atlassian Community

Badges are a great way to show off community activity, whether you’re a newbie or a Champion.

Learn more
Community showcase
Published May 30, 2018 in Marketplace Apps

Three tips for boosting your board's efficiency with Story Maps

Trello is one of the most effective tools for driving your sprints. It's customizable for every Agile team and product owners and Scrum masters (SM) love it. However, Agile teams often struggle with:...

849 views 2 9
Read article

Atlassian User Groups

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

Find a group

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

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you