Check for/Drop duplicate issues with same Sender, Summary and Description



since 2.6.15, 2.7.12, 3.0.0 - needs a jemhUtils.hash(..) method adding, see JEMH-6688 for backport info



The Problem

You want to match an existing issue created by the same reporter (Jira user) or sender (email user), with same summary and description.

The Approach

This is not really straightforward, as JQL breaks for complex values, to solve this case we introduced a new method into the jemhUtils helper class (see javadoc), that allows JEMH to generate a hash of the summary and description on issue creation through the Script Field Processor.

Firstly, you'll need to create 2 custom fields and turn on the directives for the script to run

Custom field section can be found under the Administration menu.

Settings → Issues → Custom fields and click "Add custom field" (make sure to select all the screens in this case)

Next is to make sure the Directives are turned on which can be found under the "Profile" configuration settings.

Set the directives from "Disabled" to "On Create or Comment" and Submit. If all done well, you'll get another section after the execution of the test case called "Field Processor".

Get the summary and description hashes

So, what we do is that when no relatedIssue is in scope (we are creating), that we first hash the summary and description:

Hashing script

if (relatedIssue === null) { print('no issue yet identified, scanning with script'); var subHash='none'; var descHash='none'; if (subject !== null && !subject.isEmpty()) { subHash=jemhUtils.hash(subject); resultMap.put("summary_hash", subHash); } if (body !== null && !body.isEmpty()) { descHash=jemhUtils.hash(body); resultMap.put("desc_hash", descHash); } }

Second, expand query to use a JQL Query to find pre-existing issues from same sender with same hashes

If the sender is an email user, remember to set up the related custom fields in the profile for email user support Configure JEMH for a Helpdesk environment from scratch.

Now we will Use JQL to locate issues in a script:

if (relatedIssue === null) { print('subject: '+subject); print('From: '+fromAddress.getAddress()); if (senderUser !== null) { print('From user: '+senderUser); } else { print('Sender has no Jira account'); } print('no issue yet identified, scanning with script'); var subHash='none'; var descHash='none'; if (subject !== null && !subject.isEmpty()) { subHash=jemhUtils.hash(subject); resultMap.put("summary_hash", subHash); } if (body !== null && !body.isEmpty()) { descHash=jemhUtils.hash(body); resultMap.put("desc_hash", descHash); } //get the user to run the JQL query as var user = userManager.getUserByName("admin"); //note the use of "static" on the below 2 lines, see the additional information below var filter = PagerFilter.static.getUnlimitedFilter(); var builder = JqlQueryBuilder.static.newBuilder(); //construct the JQL query var query = builder.where().defaultAnd() .field("summary_hash").like(subHash) .field("desc_hash").like(descHash); if (senderUser !== null) { print('scoping to reporter'); query=query.reporter().eq(senderUser.getUsername()).buildQuery(); } else if (fromAddress !== null) { print('scoping to Sender Email Address: '+fromAddress.getAddress()); query=query.field("Sender Email Address").like(fromAddress.getAddress()).buildQuery(); } else { query=query.buildQuery(); } //get list of issues (could be empty) var results = searchService.search(user, query, filter).getIssues(); //get first issue if exists and add via issueKey directive if (results.size()>0) { var issue = results[0]; print('found '+results.size()+' matching issues, using first: '+issue.getKey()); resultMap.put("issueKey",issue.getKey()); } else { print("No issues match using JQL."); } } else { print('issue '+relatedIssue+' has already been identified through subject /other means'); }


IMPORTANT if on Jira v8+

If you are using Jira 8 or above, ensure you replacing the following line:

var results = searchService.search(user, query, filter).getIssues();

with:

Jira 8+ no longer supports getIssues() function as it has been replaced with getResults(). Failing to do this will result in an exception in the Script Field Processor.

 

Do note the following line of code gets the default user which in this case is admin. Therefore, if you are signed in as a different user, you'll have to change it to the corresponding credentials. 

 

Since JEMH 3.3.21 we lock down access to arbitrary classes in the script context, they cannot be accessed using historic methods:

but need to be gained through fully specified class names:

These specific classes were not initially added, are available since JEMH 3.3.38

Due to issues highlighted on the following page,Using Java 17 | Classnotfound exception when using “java.type”. 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 33 and 34:

Non-JIra registered Sender

MIME-Version: 1.0
Received: by 10.223.112.12 with HTTP; Sat, 18 Jun 2011 22:42:26 -0700 (PDT)
Date: Sun, 19 Jun 2011 17:42:26 +1200
Message-ID: <BANLkTinB1mfSh+GwOXGNWoL4SyDvOpdBoQ@mail.gmail.com>
Subject: This is a starting email template, update as required
From: "Andy Brook" <andy@localhost>
To: changeme@thiswontwork.com
Content-Type: text/plain; charset=UTF-8

some text

This was mentioned in custom project YY-4444 but we should put this on XX-2 for further review

more text

Edit-time evaluation against test case:



Jira registered sender

MIME-Version: 1.0
Received: by 10.223.112.12 with HTTP; Sat, 18 Jun 2011 22:42:26 -0700 (PDT)
Date: Sun, 19 Jun 2011 17:42:26 +1200
Message-ID: <BANLkTinB1mfSh+GwOXGNWoL4SyDvOpdBoQ@mail.gmail.com>
Subject: This is a starting email template, update as required
From: "Andy Brook" <admin@localhost>
To: changeme@thiswontwork.com
Content-Type: text/plain; charset=UTF-8

some text

This was mentioned in custom project YY-4444 but we should put this on XX-2 for further review

more text

Edit-time evaluation against test case



Third, do something about the match

Choices choices!  

Drop the issue

We can Define message outcomes with a slight modification:

Output:

Using Supported fields for use with Directives we can choose to create the issue but link it as duplicates the previous:

Output:




Finishing up

Once operational, you can remove the hash fields from the issue screens, it will operate as expected even with the fields hidden.