Debugging script/automatic due date 30 days

Hi,

I'm trying to set a due date for an issue as 30 days after the issue on issue create - specifically the first weekday 30 days after today. Using the script from Warren McInnes at https://answers.atlassian.com/questions/135802 (comment dated Feb 11, 2014), I have run into a peculiar issue. I can set the due date for any number up to 24 (twenty four) days in the future, however, if I set the variable days to any value >= 25, it ends up setting a due date in the past - appears to subtract this value.

Again, today is November 4 (Friday), 24 days in the future is November 28 (Monday) -> With the script as days = 24, JIRA creates the issue with a due date of 28/Nov/16.
With the script as days = 25, JIRA creates the issue with a due date of 10/Oct/15, that is, in the past (?coincidence 25 days).

Most important question is - can anyone reproduce this? Or is Friday getting to me?


Workflow has the following post functions on create:

  1. ScriptRunner workflow function - Custom script post-function (inline script).
  2. Creates the issue originally.
  3. Re-index
  4. Fire an Issue Created event.
import org.apache.log4j.Category
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.customfields.CustomFieldType
import com.atlassian.jira.issue.fields.CustomField
import java.sql.Timestamp;
  
int days = 25;
log.info("var days: "+days.toString());
    int dayOfWeek = 0;
    Date today = new Date();
MutableIssue myIssue = issue

    Calendar dueDate = Calendar.getInstance();
 
    while ((dayOfWeek == 0) || (dayOfWeek == Calendar.SATURDAY) || (dayOfWeek == Calendar.SUNDAY)) {
        dueDate.setTimeInMillis(today.getTime() + days*1000*24*60*60);
        dayOfWeek = dueDate.get(Calendar.DAY_OF_WEEK);
        days = days + 1;
        log.info("Days in loop: "+days.toString());
    }
         
System.out.println("script setduedate is running...and mydueDate is:" + dueDate.getTime());
log.info("Day of week: "+dayOfWeek.toString()+", Day: "+days.toString()+", Due Date: "+dueDate.getTime()); 
myIssue.setDueDate(new Timestamp(dueDate.getTime().getTime()));

Running JIRA server 7.1.7 (software/core 7.1.7 and JIRA SD 3.1.7).

Script appears to run (Script runner doesn't say failure + no due date on create screen, but one is being set).


Alternatively, if anyone has any other ideas on how to set a due date on issue create on the first weekday after 30 days, that would also be appreciated laugh

2 answers

1 accepted

This widget could not be displayed.
Vasiliy Zverev Community Champion Nov 03, 2016

Place this post-function after "Creates the issue originally." So, it is impossible and add IssueMAanger.UpdateIssue() method to store changes. I also slightly refactor your code:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import java.sql.Timestamp;

int days = 25;
log.info("var days: "+days.toString());
int dayOfWeek = 0;
Date today = new Date();

Calendar dueDate = Calendar.getInstance();

while ((dayOfWeek == 0) || (dayOfWeek == Calendar.SATURDAY) || (dayOfWeek == Calendar.SUNDAY)) {
    dueDate.setTimeInMillis(today.getTime() + days*1000*24*60*60);
    dayOfWeek = dueDate.get(Calendar.DAY_OF_WEEK);
    days += 1;
    log.info("Days in loop: "+days.toString());
}

System.out.println("script setduedate is running...and mydueDate is:" + dueDate.getTime());
log.info("Day of week: "+dayOfWeek.toString()+", Day: "+days.toString()+", Due Date: "+dueDate.getTime());
issue.setDueDate(new Timestamp(dueDate.getTime().getTime()));

//Need only on create transition
ComponentAccessor.getIssueManager().updateIssue(
        ComponentAccessor.getJiraAuthenticationContext().getUser().getDirectoryUser()
        , issue
        , EventDispatchOption.ISSUE_UPDATED
        , false
)

Hi @Vasiliy Zverev,

I ran it, but it didn't set a due date. Script runner message (viewing from post workflow functions) shows:

Time (on server): Fri Nov 04 2016 17:18:25 GMT+1100 (AUS Eastern Standard Time)
The following log information was produced by this execution. Use statements like:log.info("...") to record logging information.
2016-11-04 17:18:23,182 ERROR [workflow.ScriptWorkflowFunction]: *************************************************************************************
2016-11-04 17:18:24,788 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: PRIV-29, actionId: 1, file: <inline script>
groovy.lang.MissingMethodException: No signature of method: com.atlassian.jira.issue.managers.DefaultIssueManager.updateIssue() is applicable for argument types: (com.atlassian.jira.user.BridgedDirectoryUser, com.atlassian.jira.issue.IssueImpl, com.atlassian.jira.event.type.EventDispatchOption$EventDispatchOptionImpl, java.lang.Boolean) values: [jvan:1, PRIV-29, com.atlassian.jira.event.type.EventDispatchOption$EventDispatchOptionImpl@24daffb0, ...]
Possible solutions: updateIssue(com.atlassian.jira.user.ApplicationUser, com.atlassian.jira.issue.MutableIssue, com.atlassian.jira.event.type.EventDispatchOption, boolean), updateIssue(com.atlassian.jira.user.ApplicationUser, com.atlassian.jira.issue.MutableIssue, com.atlassian.jira.issue.UpdateIssueRequest)
	at Script176.run(Script176.groovy:25)

I'll keep you updated (maybe Monday... the weekend waits).

Vasiliy Zverev Community Champion Nov 03, 2016

Here is version for JIRA 7

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import java.sql.Timestamp;

int days = 25;
log.info("var days: "+days.toString());
int dayOfWeek = 0;
Date today = new Date();

Calendar dueDate = Calendar.getInstance();

while ((dayOfWeek == 0) || (dayOfWeek == Calendar.SATURDAY) || (dayOfWeek == Calendar.SUNDAY)) {
    dueDate.setTimeInMillis(today.getTime() + days*1000*24*60*60);
    dayOfWeek = dueDate.get(Calendar.DAY_OF_WEEK);
    days += 1;
    log.info("Days in loop: "+days.toString());
}

System.out.println("script setduedate is running...and mydueDate is:" + dueDate.getTime());
log.info("Day of week: "+dayOfWeek.toString()+", Day: "+days.toString()+", Due Date: "+dueDate.getTime());
issue.setDueDate(new Timestamp(dueDate.getTime().getTime()));

//Need only on create transition
ComponentAccessor.getIssueManager().updateIssue(
        ComponentAccessor.getJiraAuthenticationContext().getUser()
        , issue
        , EventDispatchOption.ISSUE_UPDATED
        , false
)

Hi @Vasiliy Zverev, it also seems to be setting a due date in the past...

duedate.png

 

Is this possibly due to a regional setting?

I also tried to change line 25 to ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser(), but as above - script ran, incorrect due date set, 25 days in the past.

Vasiliy Zverev Community Champion Nov 06, 2016

It is no good idea to set time manually. It is better to use methods of Calendar. Here is updated code:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import java.sql.Timestamp;

int days = 25;
log.info("var days: "+days.toString());

Calendar dueDate = Calendar.getInstance();

while (dayOfWeek == 0) {
    dueDate.add(Calendar.DAY_OF_YEAR, 1)
    if((dueDate.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY)&&(Calendar.DAY_OF_WEEK == Calendar.SUNDAY))
        --days;
    log.info("Days in loop: "+days.toString());
}

System.out.println("script setduedate is running...and mydueDate is:" + dueDate.getTime());
log.info("Day of week: "+dayOfWeek.toString()+", Day: "+days.toString()+", Due Date: "+dueDate.getTime());
issue.setDueDate(new Timestamp(dueDate.getTime().getTime()));

//Need only on create transition
ComponentAccessor.getIssueManager().updateIssue(
        ComponentAccessor.getJiraAuthenticationContext().getUser()
        , issue
        , EventDispatchOption.ISSUE_UPDATED
        , false
)

Sorry I didn't post earlier.

The above script doesn't set a due date, it says

Time (on server): Thu Nov 10 2016 13:55:33 GMT+1100 (AUS Eastern Daylight Time)
The following log information was produced by this execution. Use statements like:log.info("...") to record logging information.
2016-11-10
 13:55:32,538 ERROR [workflow.ScriptWorkflowFunction]: 
*************************************************************************************
2016-11-10
 13:55:32,799 ERROR [workflow.ScriptWorkflowFunction]: Script function 
failed on issue: PRIV-42, actionId: 1, file: <inline script>
groovy.lang.MissingPropertyException: No such property: dayOfWeek for class: Script9
    at Script9.run(Script9.groovy:10)

I can't set the var dayOfWeek = 0 initially, as then it wouldn't escape the while loop.

Vasiliy Zverev Community Champion Nov 09, 2016

Do you really need this variable? This is only for debug. I think it is better to delete it:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import java.sql.Timestamp;

int days = 25;
log.info("var days: "+days.toString());

Calendar dueDate = Calendar.getInstance();

while (dayOfWeek == 0) {
    dueDate.add(Calendar.DAY_OF_YEAR, 1)
    if((dueDate.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY)&&(Calendar.DAY_OF_WEEK == Calendar.SUNDAY))
        --days;
    log.info("Days in loop: "+ days.toString());
}

System.out.println("script setduedate is running...and mydueDate is:" + dueDate.getTime());
log.info("Day: " + days.toString() + ", Due Date: " + dueDate.getTime());
issue.setDueDate(new Timestamp(dueDate.getTime().getTime()));

//Need only on create transition
ComponentAccessor.getIssueManager().updateIssue(
        ComponentAccessor.getJiraAuthenticationContext().getUser()
        , issue
        , EventDispatchOption.ISSUE_UPDATED
        , false
)

Hi @Vasiliy Zverev, I'm not particularly attached to the variable (or any of the debugging, have commented it out), but I think the script requires it:

image2016-11-10 16:44:0.png

Message reads:

[Static type checking] - The variable [dayOfWeek] is undeclared.

Thanks so much for your help to date, I appreciate it.

Vasiliy Zverev Community Champion Nov 09, 2016

Hm, this is a misprint. Into while loop days should be used. 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import java.sql.Timestamp;

int days = 25;
log.info("var days: "+days.toString());

Calendar dueDate = Calendar.getInstance();

while (days == 0) {
    dueDate.add(Calendar.DAY_OF_YEAR, 1)
    if((dueDate.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY)&&(Calendar.DAY_OF_WEEK == Calendar.SUNDAY))
        --days;
    log.info("Days in loop: "+ days.toString());
}

System.out.println("script setduedate is running...and mydueDate is:" + dueDate.getTime());
log.info("Day: " + days.toString() + ", Due Date: " + dueDate.getTime());
issue.setDueDate(new Timestamp(dueDate.getTime().getTime()));

//Need only on create transition
ComponentAccessor.getIssueManager().updateIssue(
        ComponentAccessor.getJiraAuthenticationContext().getUser()
        , issue
        , EventDispatchOption.ISSUE_UPDATED
        , false
)

So this one set a due date of today:

image2016-11-10 17:14:11.png

Vasiliy Zverev Community Champion Nov 09, 2016

It seems that this posrt-function is used on create transition. So it should be placed after issue created post-function.

It's being run as the second step:

step2.png

which produces the second change on create:

step3.png

Vasiliy Zverev Community Champion Nov 14, 2016

Hm,  there were some bugs in code. Try this

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption


import java.sql.Timestamp;

int days = 25;
log.info("var days: "+ days.toString());

Calendar dueDate = Calendar.getInstance();

while (days > 0) {
    dueDate.add(Calendar.DAY_OF_YEAR, 1)
    if((dueDate.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY)&&(dueDate.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY)) {
        --days;
    }
    log.info("Days in loop: "+ days.toString());
}

//return dueDate.toString()

System.out.println("script setduedate is running...and mydueDate is:" + dueDate.getTime());
log.info("Day: " + days.toString() + ", Due Date: " + dueDate.getTime());

issue.setDueDate(new Timestamp(dueDate.getTimeInMillis()));

//Need only on create transition
ComponentAccessor.getIssueManager().updateIssue(
        ComponentAccessor.getJiraAuthenticationContext().getUser()
        , issue
        , EventDispatchOption.ISSUE_UPDATED
        , false
)

This one set the due date to 22/Dec/16 for an issue created 17/Nov/16, so 35 days in the future. Thanks for your patience and still looking at this issue after all this time!

Update, I changed var days a few times to see what would happen.

varCreate dateDue datedifference
2017/Nov/1615/Dec/1628
2117/Nov/1616/Dec/1629
2217/Nov/1619/Dec/1632
2317/Nov/1620/Dec/1633
2517/Nov/1622/Dec/1635
Vasiliy Zverev Community Champion Nov 16, 2016

Note, that only working days are counted. Pay attention heer:

if((dueDate.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY)&&(dueDate.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY)) {
        --days;
    }
Sundays and Saturdays are not counted.

My apologies... So this won't set a due date for the first weekday after 30 days from today as in the original request? That is, something created on 17/Nov/16, should be due 17/Dec/16 (30 days later). But because 17/Dec is a Sunday, it pushes it out to Monday/19/Dec?

Vasiliy Zverev Community Champion Nov 17, 2016

Hm, if you need to set duedate to first monday after 25 days of creation date try this:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption

import java.sql.Timestamp;

int days = 25;
log.info("var days: " + days.toString());

Calendar dueDate = Calendar.getInstance();
dueDate.add(Calendar.DAY_OF_YEAR, days)

while (dueDate.DAY_OF_WEEK += Calendar.MONDAY > 0) {
    dueDate.add(Calendar.DAY_OF_YEAR, 1)
}

System.out.println("script setduedate is running...and mydueDate is:" + dueDate.getTime());
log.info("Day: " + days.toString() + ", Due Date: " + dueDate.getTime());

issue.setDueDate(new Timestamp(dueDate.getTimeInMillis()));

//Need only on create transition
ComponentAccessor.getIssueManager().updateIssue(
        ComponentAccessor.getJiraAuthenticationContext().getUser()
        , issue
        , EventDispatchOption.ISSUE_UPDATED
        , false
)
This widget could not be displayed.

So, this is what I settled on, based on @Vasiliy Zverev's answers.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import java.sql.Timestamp;
int days = 30;
Calendar dueDate = Calendar.getInstance();

while (days > 0) {
    dueDate.add(Calendar.DAY_OF_YEAR, 1)
    --days;
}

/* Adjust for weekends -> set to following Monday */
int dow = dueDate.get(Calendar.DAY_OF_WEEK);
if (dow == 7) {
    dueDate.add(Calendar.DAY_OF_YEAR, 2)
} else if (dow == 1) {
    dueDate.add(Calendar.DAY_OF_YEAR, 1)
}

issue.setDueDate(new Timestamp(dueDate.getTimeInMillis()));

/* Need only on create transition */
ComponentAccessor.getIssueManager().updateIssue(
        ComponentAccessor.getJiraAuthenticationContext().getUser()
        , issue
        , EventDispatchOption.ISSUE_UPDATED
        , false
)

Thanks so much mate!

Suggest an answer

Log in or Sign up to answer
Atlassian Summit 2018

Meet the community IRL

Atlassian Summit is an excellent opportunity for in-person support, training, and networking.

Learn more
Community showcase
Posted Wednesday in New to Jira

Are you planning to trial, or are currently trialling Jira Software? - We want to talk to you!

Hello! I'm Rayen, a product manager at Atlassian. My team and I are working hard to improve the trial experience for Jira Software Cloud. We are interested in   talking to 20 people planning t...

128 views 2 0
Join discussion

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