Hi guys,
I have a script listener that will create and link a ticket if a ticket priority equals 'P1', or is modified to 'P1' from another priority. It seems to work flawlessly most of the time. It's designed to not create/link a ticket if a link already exists. Anyway, I got a complaint that my listener created 2 tickets and linked them to the source ticket – which is not desired. When I look at the history of the source ticket, I see that one user changes the source ticket from p2 to p1 (which triggers the listener). At the same time I see another user add an attachment to the ticket. I'm assuming this is happening before the check is made for an existing link. Below is my script. Any tips on how to prevent this from happening? By the way – I don't want to lock the script from running if it is already running – it is conceivable that this could be modifying more than one ticket at once. If a lock is needed, I need a way to lock changes from an existing ticket that is already being modified.
Tips much appreciated.
import com.atlassian.jira.event.issue.AbstractIssueEventListener import com.atlassian.jira.event.issue.IssueEvent import com.atlassian.crowd.embedded.api.User import com.atlassian.jira.issue.MutableIssue import com.atlassian.jira.issue.fields.CustomField import com.atlassian.jira.issue.link.IssueLink import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.customfields.option.Option public class LINKAssignmentListener extends AbstractIssueEventListener { @Override void workflowEvent(IssueEvent event) { // only one central way ... this.customEvent(event) } @Override void customEvent(IssueEvent event) { // Setting up the various Managers def issueManager = ComponentAccessor.getIssueManager() //for testing in console def projectManager = ComponentAccessor.getProjectManager() def customFieldManager = ComponentAccessor.getCustomFieldManager() def optionsManager = ComponentAccessor.getOptionsManager() def issueLinkManager = ComponentAccessor.getIssueLinkManager() def results = "" //def myIssue = 'FOOBAR-28234' //for testing in console def myNewIssue = '' //MutableIssue issue = issueManager.getIssueObject(myIssue) //for testing in console def issue = event.getIssue() def priority = issue.getPriorityObject().getName() // first -- we only run if ticket is a p1 //if (priority == 'P1') //for testing in console List changeItems = [] try { changeItems = event.getChangeLog().getRelated("ChildChangeItem") } catch (e) { results += "Skipping changeItems -- looks like issue created via workflow." } if ((priority == 'P1') || (priority == 'P1' && changeItems.any { it.get('field') == 'priority' })) { // Next -- we check if a link to a LINK ticket already exists, if one does, we stop script. String linkResult = ''; Collection<IssueLink> olinks = ComponentAccessor.getIssueLinkManager().getOutwardLinks(issue.getId()); Collection<IssueLink> ilinks = ComponentAccessor.getIssueLinkManager().getInwardLinks(issue.getId()); Collection<IssueLink> links = olinks + ilinks; for (IssueLink il : links) { linkResult += il.getSourceObject().getProjectObject().getKey() linkResult += il.getDestinationObject().getProjectObject().getKey() } if (linkResult.contains("LINK")) { results += "Link already exists. I shall stop now. " //for testing in console } else { // Let's create a LINK ticket // .... but first we need to copy existing custom field values from the FOOBAR ticket // Classification field. CustomField classification = customFieldManager.getCustomFieldObjects(issue).find { it.name == "Classification" } def region = issue.getCustomFieldValue(classification)[0].toString() def customer = issue.getCustomFieldValue(classification)[1].toString() def country = issue.getCustomFieldValue(classification)[2].toString() //In order to set the above Classification field values in the target LINK ticket, I need to get the Option Ids that correspond to them. Long regionId = null Long customerId = null Long countryId = null def cfConfig = classification.getRelevantConfig(issue) def classificationOptions = optionsManager.getOptions(cfConfig) for (Option regionOption : classificationOptions) { if (regionOption.getValue().equals(region)) { regionId = regionOption.getOptionId() def customers = regionOption.getChildOptions() for (Option customerOption : customers) { if (customerOption.getValue().equals(customer)) { customerId = customerOption.getOptionId() def countries = customerOption.getChildOptions() for (Option countryOption : countries) { if (countryOption.getValue().equals(country)) { countryId = countryOption.getOptionId() } } } } } } // We have the needed data from the original FOOBAR ticket. Now we can create the LINK ticket: def projectName = "Linked Ticket Example" //Target project name def project = projectManager.getProjectObjByName(projectName) // String currentUser = event.getUser().getName(); User currentUserObj = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser(); // This is used for creating the new LINK ticket def issueService = ComponentAccessor.getIssueService() def issueInputParameters = issueService.newIssueInputParameters(); // Setting System Fields issueInputParameters.setProjectId(project.id) issueInputParameters.setIssueTypeId('34') // 'Problem' issue type in LINK issueInputParameters.setSummary(issue.summary) issueInputParameters.setAssigneeId('triage') issueInputParameters.setReporterId(issue.getReporterId()) issueInputParameters.setDescription(issue.description) // Setting Custom Fields // First we'll do the classification field values, since we have that already defined from above. issueInputParameters.addCustomFieldValue(classification.getId() + ":0", regionId.toString()) issueInputParameters.addCustomFieldValue(classification.getId() + ":1", customerId.toString()) issueInputParameters.addCustomFieldValue(classification.getId() + ":2", countryId.toString()) def customField = customFieldManager.getCustomFieldObject("customfield_11135") // Support Manager issueInputParameters.addCustomFieldValue(customField.getId(), 'support-guy') // 'support-guy' option for Support Manager customField = customFieldManager.getCustomFieldObject("customfield_10891") // Action Required From issueInputParameters.addCustomFieldValue(customField.getId(), '13118') // 'Foo Bar' option for Action Required From customField = customFieldManager.getCustomFieldObject("customfield_11124") // Director issueInputParameters.addCustomFieldValue(customField.getId(), '12902') // 'Director Guy' option for Director customField = customFieldManager.getCustomFieldObject("customfield_13190") // LL Needed? issueInputParameters.addCustomFieldValue(customField.getId(), '16741') // 'No' option for LL Needed? customField = customFieldManager.getCustomFieldObject("customfield_11812") // Is there a high probability this will happen again? issueInputParameters.addCustomFieldValue(customField.getId(), '13920') // 'Yes' option for Is there a high probability this will happen again? customField = customFieldManager.getCustomFieldObject("customfield_11815") // Does the Customer perceive this as urgent? issueInputParameters.addCustomFieldValue(customField.getId(), '13926') // 'Yes' option for Does the Customer perceive this as urgent? customField = customFieldManager.getCustomFieldObject("customfield_11816") // Does it create an outage? issueInputParameters.addCustomFieldValue(customField.getId(), '13928') // 'Yes' option for Does it create an outage? customField = customFieldManager.getCustomFieldObject("customfield_11820") // Revenue Loss? issueInputParameters.addCustomFieldValue(customField.getId(), '13936') // 'Yes' option for Revenue Loss? customField = customFieldManager.getCustomFieldObject("customfield_11813") // Are there any timeline commitments / dependencies? issueInputParameters.addCustomFieldValue(customField.getId(), '13923') // 'No' option for Are there any timeline commitments / dependencies? customField = customFieldManager.getCustomFieldObject("customfield_11814") // Are there any SLA dependencies? issueInputParameters.addCustomFieldValue(customField.getId(), '13925') // 'No' option for Are there any SLA dependencies? customField = customFieldManager.getCustomFieldObject("customfield_11819") // Does this problem create an additional ongoing workload? issueInputParameters.addCustomFieldValue(customField.getId(), '13935') // 'No' option for Does this problem create an additional ongoing workload? customField = customFieldManager.getCustomFieldObject("customfield_11817") // Are either ALL users of one customer affected or ALL customers affected? issueInputParameters.addCustomFieldValue(customField.getId(), '13931') // 'No' option for Are either ALL users of one customer affected or ALL customers affected? customField = customFieldManager.getCustomFieldObject("customfield_11818") // Would there be penalties? issueInputParameters.addCustomFieldValue(customField.getId(), '13932') // 'Yes' option for Would there be penalties? // Let's create the new LINK tiket def newIssueResult = issueService.validateCreate(currentUserObj, issueInputParameters); if (!newIssueResult.isValid()) { results += "could not create target issue: " + newIssueResult.getErrorCollection() } def newIssue = issueService.create(currentUserObj, newIssueResult).getIssue() results += "Created issue ${newIssue.key} ." Long linkType = 10196 // 'Relates to' link type try { issueLinkManager.createIssueLink(issue.getId(), newIssue.getId(), linkType, Long.valueOf(1), currentUserObj) results += "Added link from ${issue.key} of type \'Relates\' to ${newIssue.key}" } catch (e) { results += "PROBLEM adding link from ${issue.key} of type ${linkType} to ${newIssue.key} :: ${e}" } } } else { results += "Ticket is not P1" } //return results -- for testing } }
We have a similar issue
We run a bulk transition on a set of issues which trigger an event which are catched by a script listener which generates a custom mail ...
What we have now is that some mails have the subject of the previous issue, which is strange to say the least.
JIRA 6.2.7
Script Listener 3.0.16
cc: @Jamie Echlin (Adaptavist)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.