Use Regexp and JQL to create comments or Sub-tasks on existing issues.

This example expands on a script for using Regexp to extract values from the email and uses a JQL query to find existing Jira Issue with an External ID. Please se here for that Example:

Scenario

This Script allows for a partial match on an extracted value and allows for new ‘Sub-tasks’ to be created for a Partial match. As an example Scenario:

  1. JEMH creates an issue with an ‘External ID’ of ‘1234567890 Blue’. Issue [ABC-1]

  2. A second email is processed with the same 'External ID' which creates a comment on [ABC-1]

  3. Another email with an ‘External ID’ of ‘1234567890 Green’ creates a new Sub-Task [ABC-2] which is a Sub-Task of [ABC-1]

    1. A Sub-Task is created because the first part of the External ID are the same in both cases (123456789) but does not match on the second part (Blue/Green).

  4. Another email with an ‘External ID’ of ‘0987654321 Blue’ Creates a new unrelated issue of [ABC-3]

Prerequisite

This Script requires a new Custom Field to store the extracted ‘External ID’. The field should only include values extracted using this script and should never have duplicate values, as the value is only set during creation, if no other issues were found with the same value.

Note: In the Example Script I have used a Single Line Text Custom Field called 'Ticket Key'.

Due to issues highlighted on the following page,https://thepluginpeople.atlassian.net/wiki/spaces/JEMH/pages/3974856709/Using+Java+17#Classnotfound-exception-when-using-%E2%80%9Cjava.type%E2%80%9D. It means that if you are using Java 17 with Nashorn installed within jira-install/lib then you will need to use JEMH 4.1.33+ and then use the following instead of lines 45 and 46:

  • var filter = pagerFilter; var builder = jqlQueryBuilder;

Script

//create regexp pattern to extract external id // var pattern = Java.type("java.util.regex.Pattern").compile("External ID: (([0-9]{10}) (Blue|Green|Orange|Teal))"); //This Pattern has 2 capture Groups: /* # Full Match: 1234567890 Blue # Partial Match: 1234567890 # Colour Match Blue (ignored) */ //Create a patternMatcher for the subject var matcher = pattern.matcher(subject); //define empty values for the full, and partial match var foundExternalFull = ""; var foundExternalPartial = ""; //if match exists set the found external values if (matcher.find()) { var groupOne = matcher.group(1); if (groupOne) { foundExternalFull = groupOne; } var groupTwo = matcher.group(2); if (groupTwo) { foundExternalPartial = groupTwo; } } //define values for the related issue keys for commenting and creating a subtask var issueWithExternalId = ""; var parentIssueWithExternalId = ""; //If a regexp match is found, check existing issues for the same value if(foundExternalFull){ print("Found a TicketID of [" + foundExternalFull + "]"); //get the user to run the JQL query as var user = userManager.getUserByName("admin"); var filter = Java.type("com.atlassian.jira.web.bean.PagerFilter").getUnlimitedFilter(); var builder = Java.type("com.atlassian.jira.jql.builder.JqlQueryBuilder").newBuilder(); //construct the JQL query for a Full match var fullQuery = builder.where().field("Ticket Key").like(foundExternalFull).buildQuery(); //get list of issues (could be empty) var fullResults = searchService.search(user, fullQuery, filter).getResults(); //get first issue if exists and add via issueKey directive to comment if (fullResults.size()>0) { var issue = fullResults[0]; issueWithExternalId = issue.getKey(); print("Found issue using JQL "+fullQuery+" : "+issueWithExternalId + " " + foundExternalFull); } else { print("No issues match using JQL: "+fullQuery + " running partial Query"); builder.clear(); //construct a JQL Query for a partial match (for Parent Issue Key) var partQuery = builder.where().field("Ticket Key").like(foundExternalPartial).buildQuery(); //get list of issues (could be empty) var partResults = searchService.search(user, partQuery, filter).getResults(); if (partResults.size()>0) { // cycle through each partial match for(var i = 0; i < partResults.size(); i ++){ var issue = partResults[i] //if the issue is not already a subtask, then it is the parent issue if(!issue.getIssueType().isSubTask()){ parentIssueWithExternalId = issue.getKey(); print("Found Parent Issue match using JQL "+partQuery+" : "+issueWithExternalId); break; } } } } //Setup issue values //if an issue for commenting is found, set the current issue key to this value if (!issueWithExternalId.isEmpty()) { resultMap.put("issueKey",issueWithExternalId) //else if not commenting, set the Ticket Key value to the extracted ID for future use } else if (!foundExternalFull.isEmpty()) { resultMap.put("Ticket Key",foundExternalFull); } //if a parent issue key is found, setup the issue as a Sub-Task if (!parentIssueWithExternalId.isEmpty()) { resultMap.put("parentIssueKey",parentIssueWithExternalId); resultMap.put("issueType", "sub-task") resultMap.put("priority", "low"); } }

 

Example Test cases

The following Test cases can be imported to JEMH to validate the script above:

new-issue-blue

Creates a new issue i.e. [ABC-1]

subtask-green

Creates a new sub-task issue i.e. [ABC-2] which is a child issue to [ABC-1]

different-issue-blue

Creates a new issue i.e. [ABC-3] unrelated to [ABC-1]