Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Is it possible to have text field inherited from one issue to another based on issue links?

Jane Ellis January 12, 2021

Hello

I am running into an issue with Scriptrunner. We have a multi-line Description text field that gets filled out or edited on 2 different issue types.

Issue Type 1 is the "parent" issue and Issue Type 2 is the "child" issue. This relationship is solely based on them being linked issues.

Issue Type 1 obviously gets created first. Issue Type 2 is then created (and usually cloned from Issue Type 1 with minor updates). 

What we'd like is for any time the Description box is UPDATED in Issue Type 1, that update is automatically done in linked Issue Type 2 issues as well.

I would be so grateful for any thoughts/feedback or code that anyone is able to provide to assist with this matter. Please let me know if you need any further clarification.

1 answer

0 votes
Hana Kučerová
Community Champion
January 12, 2021

Hi @Jane Ellis ,

welcome to the Atlassian Community!

I think it will be the best to create custom script listener. Nice example can be found here (it is written for some custom field, but I think it will be very similar for the description field).

Jane Ellis January 12, 2021

Hi @Hana Kučerová! I have been trying to write a Listener and have tried the one you attached. It does not work. :(

Juan José Marchal Gómez
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 12, 2021

Hello @Jane Ellis

can you share with as your final code that doesn't work?

Best regards.

Jane Ellis January 18, 2021

@Juan José Marchal Gómez : Please don't judge, I don't have any scripting experience so I've been working off things on the web. I appreciate any assistance you may be able to provide. :)

 

It does not give me an errors... it just doesn't do anything to the issues that are cloned from it when I update the original issue.

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.IssueFieldConstants
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.isssue.MutableIssue

// the name of the field to copy
final String fieldNameToCopy = "Description"

// leave blank to copy from the last linked issue (regardless the link type)
final String issueLinkTypeName = "Cloners"

def fieldManager = ComponentAccessor.fieldManager

def fieldToCopy = fieldManager.allAvailableNavigableFields.find { it.name == fieldNameToCopy }
if (!fieldToCopy) {
log.info "Could not find field with name $fieldNameToCopy"
return
}

def linkedIssues = ComponentAccessor.issueLinkManager.getOutwardLinks(event.issue.id)
if (!linkedIssues) {
log.info "There are no linked issues"
return
}

if (issueLinkTypeName && !(issueLinkTypeName in linkedIssues*.issueLinkType*.name)) {
log.info "Could not find any issue, linked with the $issueLinkTypeName issue type"
return
}

def linkedIssue = issueLinkTypeName ?
linkedIssues.findAll { it.issueLinkType.name == issueLinkTypeName }.last().destinationObject :
linkedIssues.last().destinationObject

def fieldToCopyId = fieldToCopy.id

switch (fieldToCopyId) {
case fieldManager.&isCustomFieldId:
def customField = ComponentAccessor.customFieldManager.getCustomFieldObject(fieldToCopyId)
def linkedIssueCustomFieldValue = linkedIssue.getCustomFieldValue(customField)
(event.issue. as MutableIssue).setCustomFieldValue(customField, linkedIssueCustomFieldValue)
break

case IssueFieldConstants.COMPONENTS:
def commonComponents = linkedIssue.components.findAll { it.name in issue.components*.name }
issue.setComponent(commonComponents)
break

case IssueFieldConstants.FIX_FOR_VERSIONS:
def commonFixedVersions = linkedIssue.fixVersions.findAll { it.name in issue.fixVersions*.name }
issue.setFixVersions(commonFixedVersions)
break

case IssueFieldConstants.AFFECTED_VERSIONS:
def commonVersions = linkedIssue.affectedVersions.findAll { it.name in issue.affectedVersions*.name }
issue.setFixVersions(commonVersions)
break

default:
issue[fieldToCopyId] = linkedIssue[fieldToCopyId]
}

Hana Kučerová
Community Champion
January 18, 2021

Hi @Jane Ellis ,

please try something like this - create custom script listener for your project and and use the code bellow.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.jira.issue.link.IssueLinkManager
import com.atlassian.jira.user.ApplicationUser

import static com.atlassian.jira.issue.IssueFieldConstants.DESCRIPTION

// the name of the custom field to update
final String issueLinkTypeName = 'Cloners'

Issue issue = event.issue
def change = event.changeLog.getRelated('ChildChangeItem').find { it.field == DESCRIPTION }

// Was not the 'Description' field that changed, do nothing
if (!change) {
return
}

// Find all the linked issues to the event's issue
IssueLinkManager issueLinkManager = ComponentAccessor.getIssueLinkManager()
List<IssueLink> linkedIssues = issueLinkManager
.getOutwardLinks(issue.getId())
.findAll { IssueLink issueLink ->
issueLink.getIssueLinkType().getName() == issueLinkTypeName
}

// There are no linked issues with 'Cloners' link, do nothing
if (!linkedIssues) {
return
}

IssueManager issueManager = ComponentAccessor.getIssueManager()
ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

// Go through all linked issue and set the description based on the event's issue description
linkedIssues.each {IssueLink issueLink ->
MutableIssue linkedIssue = issueLink.getDestinationObject() as MutableIssue
linkedIssue.setDescription(issue.getDescription())
issueManager.updateIssue(loggedInUser, linkedIssue, EventDispatchOption.DO_NOT_DISPATCH, false)
}
Like # people like this
Juan José Marchal Gómez
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 18, 2021

Hello @Jane Ellis ,

try @Hana Kučerová

In my case I was the same like you at the begining with Scriptrunner. I recommend you training in scriptrunner with some expert. Is the best way to start to be independent implementing code in Scriprunner.

I'm not expert but some code similar like @Hana Kučerová code I'm able to create.

After checking this code, if fails tell us and we can help you.

Best regards.

Jane Ellis January 19, 2021

@Hana Kučerová @Juan José Marchal Gómez 

We did update the name of the field to 'Detailed Description' and it does throw an issue when I put that in the code it doesn't like it with or without spaces at this section of the code:

// Go through all linked issue and set the description based on the event's issue description
linkedIssues.each {IssueLink issueLink ->
MutableIssue linkedIssue = issueLink.getDestinationObject() as MutableIssue
linkedIssue.setDescription(issue.getDescription())
issueManager.updateIssue(loggedInUser, linkedIssue, EventDispatchOption.DO_NOT_DISPATCH, false)
}

 

But when I tried it with 'Description' and it gave me no errors but still isn't updating the issue.

Thank you!

Juan José Marchal Gómez
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 19, 2021

Hello,

If "Detailed Description" is a "Custom Field" from Jira you should use the following code

 


def cfDetailedDescription = customFieldManager.getCustomFieldObjects(event.issue).find {it.name == "Detailed Description"}
cfDetailedDescription.updateValue(null, mutableIssue, new ModifiedValue(issue.getCustomFieldValue(cfDetaildDescription), "DETAILED DESCRIPTION NEW VALUE"),changeHolder)



 instead of

 

 linkedIssue.setDescription(issue.getDescription())

 

Because Description field works different as CustomField Objects.

 

Also you will need define 

 

def customFieldManager = ComponentAccessor.getCustomFieldManager()
def changeHolder = new DefaultIssueChangeHolder()

 

and import

 

import com.atlassian.jira.issue.ModifiedValue

 

Best regards. 

Like # people like this
Jane Ellis January 19, 2021

Thank you, @Juan José Marchal Gómez !

However, I am getting an issue with:

def changeHolder = new DefaultIssueChangeHolder()

 unable to resolve class DefaultIssueChangeHolder

I then tried: import com.atlassian.jira.issue.DefaultIssueChangeHolder 
That told me the script could not be compiled.

Juan José Marchal Gómez
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 19, 2021

import com.atlassian.jira.issue.util.DefaultIssueChangeHolder

Jane Ellis January 19, 2021

Oh man. I get one issue fixed and then another pops up!

cfDetailedDescription.updateValue(null, mutableIssue, new ModifiedValue(issue.getCustomFieldValue(cfDetailedDescription), "DETAILED DESCRIPTION NEW VALUE"),changeHolder)

[Static type checking] - Cannot find matching method com.atlassian.issue.fields.CustomeField#updateValue(<unknown parameter type>, java.lang.Class
<com.atlassian.jira.issue.MutableIssue>,
com.atlassian.jira.issue.ModifiedValue 
come.atlassian.jira.issue.util.DefaultIssueChangeHolder). Please check if the declared type is correct and if the method exists.

Juan José Marchal Gómez
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 19, 2021

Hello @Jane Ellis ,

could you add all the code again, please. 

Best regards.

Jane Ellis January 19, 2021

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.jira.issue.link.IssueLinkManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue

import static com.atlassian.jira.issue.IssueFieldConstants.DETAILEDDESCRIPTION

// the name of the custom field to update
final String issueLinkTypeName = 'Cloners'

Issue issue = event.issue
def change = event.changeLog.getRelated('ChildChangeItem').find { it.field == DETAILED DESCRIPTION }

// Was not the 'Detailed Description' field that changed, do nothing
if (!change) {
    return
}

// Find all the linked issues to the event's issue
IssueLinkManager issueLinkManager = ComponentAccessor.getIssueLinkManager()
List<IssueLink> linkedIssues = issueLinkManager
        .getOutwardLinks(issue.getId())
        .findAll { IssueLink issueLink ->
            issueLink.getIssueLinkType().getName() == issueLinkTypeName
        }

// There are no linked issues with 'Cloners' link, do nothing
if (!linkedIssues) {
    return
}

IssueManager issueManager = ComponentAccessor.getIssueManager()
ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

// Go through all linked issue and set the description based on the event's issue description
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def changeHolder = new DefaultIssueChangeHolder(

linkedIssues.each {IssueLink issueLink ->
    MutableIssue linkedIssue = issueLink.getDestinationObject() as MutableIssue
    def cfDetailedDescription = customFieldManager.getCustomFieldObjects(event.issue).find {it.name == "Detailed Description"}
cfDetailedDescription.updateValue(null, MutableIssue, new ModifiedValue(issue.getCustomFieldValue(cfDetaildDescription), "DETAILED DESCRIPTION NEW VALUE"),changeHolder)


    issueManager.updateIssue(loggedInUser, linkedIssue, EventDispatchOption.DO_NOT_DISPATCH, false)
}

Juan José Marchal Gómez
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 22, 2021

Hello @Jane Ellis ,

I've checked your code. 

About this part:

Are you going to update linked issues or issue parent?

If you are going to update linked issues you should change (event.issue) for linkedIssue.

Make sense?

 

linkedIssues.each {IssueLink issueLink ->
    MutableIssue linkedIssue = issueLink.getDestinationObject() as MutableIssue
    def cfDetailedDescription = customFieldManager.getCustomFieldObjects(event.issue).find {it.name == "Detailed Description"}
cfDetailedDescription.updateValue(null, MutableIssue, new ModifiedValue(issue.getCustomFieldValue(cfDetaildDescription), "DETAILED DESCRIPTION NEW VALUE"),changeHolder)
Jane Ellis January 26, 2021

We are going to update the issue parent and want that information to flow down to the linked issue(s).

    issueManager.updateIssue(loggedInUser, linkedIssue, EventDispatchOption.DO_NOT_DISPATCH, false)
}

"unexpected token" on the bold/italicized guy.

Juan José Marchal Gómez
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
January 26, 2021

Hello @Jane Ellis ,

could you share always all the code, please?

Best regards.

Suggest an answer

Log in or Sign up to answer