Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

This document details the Shared Groovy scripts feature of JMWE. Using this you can define global Groovy scripts that will be available from any Groovy script written in the Groovy console, post-functions, conditions and validators. This is useful for reusing complex/lengthy scripts across multiple workflow transitions. It is available under JMWE administration pages

...

Note

It is strongly recommended to remove the references to the Shared Groovy Script in any workflow extension before deleting it.

...

Shared Groovy Scripts best practices

Defining a static method

In this example, we will create a simple static method plusOne in the Class Functions. Create a shared script named Functions with this scriptGroovy Script named Functions. Note, the name of the shared script can be used as the becomes the name of a class.

Code Block
languagegroovy
linenumberstrue
static int plusOne(int i) {
  return i+1;
}

...

When you test this script in the Groovy editor against any issue the tester will return 2

Defining

...

an explicit class

In this example, we will create a shared script named GreetMe with the script:

Code Block
languagegroovy
linenumberstrue
class GreetMe{
  String aString = "Hello"
  String sayIt() {
    return aString;
 	 } 
}

You can use this in a Groovy script section of any workflow extension (e.g. a Scripted Groovy Operation post-function) like this:

...

When you test this script in the Groovy editor against any issue the tester will return Hello

Defining

...

multiple classes inside a single shared script

In this example, we will create a shared script named MyClasses with the script:

Code Block
languagegroovy
linenumberstrue
interface Animal {
  String getName()
}

class Cat implements Animal {
  String getName() {
    return "Cat"
  }
}

static String exec() {
  return new Cat().name
}

...

When you test this script in the Groovy editor against any issue the tester will return true

Defining a service with

...

access to global variables and functions

The global variables and functions that can be used in the Shared Groovy scripts are not available to the calling methods and hence should be passed as parametersany Groovy script defined in a workflow extension are not available directly in shared Groovy scripts. The easiest approach to be able to this access them is to define a class that will contain all the desired methods but not static methods(non-static) and to pass the globals to that class. This will be like a "Service". For example:

Code Block
languagegroovy
linenumberstrue
import com.atlassian.jira.issue.IssueManager

class MyService {
  private Script baseScriptglobals;
  
  public MyService(Script baseglobals) {
    this.baseScriptglobals = baseglobals;
  }
  
  public String getIssueKey() {
    return baseScriptglobals.issue.key;
  }

  public Issue getIssue(String key) {
    return baseScriptglobals.getComponent(IssueManager).getIssueObject(key)
  }
}

...

Code Block
languagegroovy
linenumberstrue
MyService utils = new MyService(this)

utils.issueKey //calls the getIssueKey() method, which accesses the issue global variable
utils.getIssue("TEST-1") //calls the getIssue method which accesses the global getComponent function

Use cases for Shared Groovy scripts

...

Create a shared Groovy script that adds a certain number of days to a date excluding the weekends

  1. Create a shared groovy script, AddDaysExcludingWeekends, with the following script

    Code Block
    languagegroovy
    linenumberstrue
    static Date addDaysaddWorkingDays(Date from, int nod){
        Calendar c1 = GregorianCalendar.getInstance();
        c1.setTime(from);
      
        int weeks = nod/5;
        int remDays = nod%5;
      
        //Adding whole weeks
        c1.add(Calendar.WEEK_OF_YEAR, weeks);
      
        //Run a loop and check each day to skip a weekend
        for(int i=1;i<=remDays;i++){
          c1.add(Calendar.DAY_OF_MONTH, 1);
        if (c1.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY)
            c1.add(Calendar.DAY_OF_MONTH, 1);
        if (c1.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
            c1.add(Calendar.DAY_OF_MONTH, 1);
            }
      
        //Skip ending weekend
        if (c1.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
            c1.add(Calendar.DAY_OF_MONTH, 1);
        if (c1.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY)
            c1.add(Calendar.DAY_OF_MONTH, 1);
         
      
        //move to 0:00
        c1.clearTime();
          
        return c1.getTime();
    }


  2. Save it.

You can use this in a post-function to set a Date-time picker field. For example Set a Date time picker field to the Due date plus 5 days, excluding weekends. The script in the post-function will be:

Code Block
languagegroovy
linenumberstrue
return AddDaysExcludingWeekends.addDaysaddWorkingDays(issue.duedate,5)

Check for attachments with a specific extension during a transition

Create a shared validator that checks for attachments of a specific extension were added to the transition screen

  1. Create a shared groovy script, AttachmentValidator, with the following script:

    Code Block
    languagegroovy
    linenumberstrue
    import com.atlassian.jira.issue.IssueFieldConstants
    import com.atlassian.jira.issue.attachment.Attachment
    import com.atlassian.jira.issue.attachment.TemporaryWebAttachment
    import com.atlassian.jira.issue.attachment.TemporaryWebAttachmentManager
    
    class AttachmentValidator{
      static fetchAttachmentscheckAttachments(issue,ext){
        TemporaryWebAttachmentManager attachmentManager = ComponentAccessor.getComponent(TemporaryWebAttachmentManager)
        try {
          List<Long> ids = issue.getModifiedFields().get(IssueFieldConstants.ATTACHMENT).getNewValue();
          if (ids)
            return ids.any { id ->
                def attachment = attachmentManager.getTemporaryWebAttachment(id).getOrNull()
                return attachment?.filename?.endsWith(ext)
            }
        } catch (Exception e) {
        }
        return false
      }
    }


  2. Save it.

Now you can use this in Scripted Groovy validator across transitions to validate the attachments added on the transition screen. Add the Scripted Groovy validator and call the method passing the issue variable and extension as parameters.

Code Block
languagegroovy
linenumberstrue
AttachmentValidator.fetchAttachmentscheckAttachments(issue,".pdf")