How to set epic link in Jira using Groovy

I need to set epic link using groovy if a condition is true. I'm using the following script:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.Issue;
def customFieldManager = ComponentAccessor.getCustomFieldManager()
IssueManager issueManager = ComponentAccessor.getOSGiComponentInstanceOfType(IssueManager.class)
def epiclink = CustomFieldManager.getCustomFieldObject("customfield_10101") 
issue.setCustomFieldValue(epiclink,"TS-14")

If I set the epic link to null it works,

    issue.setCustomFieldValue(epiclink, null)

2 answers

1 accepted

Accepted Answer
2 votes

Hi Miller,

I believe you will need to pass the issue object of the Epic in order to link it, not the Epic link's issue key.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder

def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issueManager = ComponentAccessor.getIssueManager()
def epicIssue = issueManager.getIssueObject("TS-14") // Epic issue key here
def epicLink = customFieldManager.getCustomFieldObjectByName("Epic Link")
epicLink.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(epicLink), epicIssue),new DefaultIssueChangeHolder())

Glad to help. Thanks for using ScriptRunner!

Hi @Joshua Yamdogo [Adaptavist]

When I use the:

epicLink.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(epicLink), epicIssue),new DefaultIssueChangeHolder())

I get these errors in the log:

/rest/scriptrunner/latest/user/exec/ [c.a.g.manager.issuelink.EpicLinkManagerImpl] Cannot set or mutate an ImmutableGenericValue
java.lang.UnsupportedOperationException: Cannot set or mutate an ImmutableGenericValue
at com.atlassian.jira.util.ofbiz.ImmutableGenericValue.set(ImmutableGenericValue.java:63)
at org.ofbiz.core.entity.GenericEntity.set(GenericEntity.java:283)
at com.atlassian.jira.issue.util.DefaultIssueUpdater.doUpdate(DefaultIssueUpdater.java:48)
at sun.reflect.GeneratedMethodAccessor7207.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.atlassian.plugin.util.ContextClassLoaderSettingInvocationHandler.invoke(ContextClassLoaderSettingInvocationHandler.java:26)
at com.sun.proxy.$Proxy17.doUpdate(Unknown Source)
... 2 filtered
at java.lang.reflect.Method.invoke(Method.java:498)
at com.atlassian.plugin.osgi.bridge.external.HostComponentFactoryBean$DynamicServiceInvocationHandler.invoke(HostComponentFactoryBean.java:136)
at com.sun.proxy.$Proxy17.doUpdate(Unknown Source)
at com.atlassian.greenhopper.manager.issuelink.EpicLinkManagerImpl.createChangeItem(EpicLinkManagerImpl.java:479)
at com.atlassian.greenhopper.manager.issuelink.EpicLinkManagerImpl.createChangeItem(EpicLinkManagerImpl.java:469)
at com.atlassian.greenhopper.manager.issuelink.EpicLinkManagerImpl.createEpicLinkChangeItemsForChild(EpicLinkManagerImpl.java:403)
at com.atlassian.greenhopper.manager.issuelink.EpicLinkManagerImpl.updateLinksForIssues(EpicLinkManagerImpl.java:246)
at com.atlassian.greenhopper.manager.issuelink.EpicLinkManagerImpl.associateIssuesWithEpic(EpicLinkManagerImpl.java:179)
at com.atlassian.greenhopper.service.issuelink.EpicServiceImpl.addIssuesToEpic(EpicServiceImpl.java:103)
at com.atlassian.greenhopper.customfield.epiclink.EpicLinkCFType.associateIssueWithEpic(EpicLinkCFType.java:686)
at com.atlassian.greenhopper.customfield.epiclink.EpicLinkCFType.createValue(EpicLinkCFType.java:202)
at com.atlassian.greenhopper.customfield.epiclink.EpicLinkCFType.createValue(EpicLinkCFType.java:44)
at com.atlassian.jira.issue.fields.ImmutableCustomField.createValue(ImmutableCustomField.java:693)
at com.atlassian.jira.issue.fields.ImmutableCustomField.updateValue(ImmutableCustomField.java:410)
at com.atlassian.jira.issue.fields.ImmutableCustomField.updateValue(ImmutableCustomField.java:396)
at com.atlassian.jira.issue.fields.OrderableField$updateValue.call(Unknown Source)
at Script360.run(Script360.groovy:64)
at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:352)
at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:153)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:233)
at javax.script.ScriptEngine$eval.call(Unknown Source)
at com.onresolve.scriptrunner.runner.ScriptRunnerImpl.runScriptAndGetContext(ScriptRunnerImpl.groovy:157)
at com.onresolve.scriptrunner.runner.ScriptRunner$runScriptAndGetContext$8.callCurrent(Unknown Source)
at com.onresolve.scriptrunner.runner.ScriptRunnerImpl.runStringAsScript(ScriptRunnerImpl.groovy:146)
at com.onresolve.scriptrunner.runner.ScriptRunnerImpl.runStringAsScript(ScriptRunnerImpl.groovy)
at com.onresolve.scriptrunner.runner.rest.common.UserScriptEndpoint.exec(UserScriptEndpoint.groovy:173)
... 2 filtered
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
... 13 filtered
at com.atlassian.plugins.rest.module.RestDelegatingServletFilter$JerseyOsgiServletContainer.doFilter(RestDelegatingServletFilter.java:154)
... 1 filtered
at com.atlassian.plugins.rest.module.RestDelegatingServletFilter.doFilter(RestDelegatingServletFilter.java:68)
... 41 filtered
at com.atlassian.web.servlet.plugin.request.RedirectInterceptingFilter.doFilter(RedirectInterceptingFilter.java:21)
... 53 filtered
at com.atlassian.jira.security.JiraSecurityFilter.lambda$doFilter$0(JiraSecurityFilter.java:66)
... 1 filtered
at com.atlassian.jira.security.JiraSecurityFilter.doFilter(JiraSecurityFilter.java:64)
... 16 filtered
at com.atlassian.plugins.rest.module.servlet.RestSeraphFilter.doFilter(RestSeraphFilter.java:37)
... 19 filtered
at com.atlassian.jira.servermetrics.CorrelationIdPopulatorFilter.doFilter(CorrelationIdPopulatorFilter.java:30)
... 5 filtered
at com.valiantys.jira.plugins.sql.service.servletcontext.ContextListenerServletFilter.doFilter(ContextListenerServletFilter.java:24)
... 8 filtered
at com.atlassian.web.servlet.plugin.request.RedirectInterceptingFilter.doFilter(RedirectInterceptingFilter.java:21)
... 4 filtered
at com.atlassian.web.servlet.plugin.LocationCleanerFilter.doFilter(LocationCleanerFilter.java:36)
... 26 filtered
at com.atlassian.jira.servermetrics.MetricsCollectorFilter.doFilter(MetricsCollectorFilter.java:25)
... 23 filtered
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

Do you have any idea why?

Worth to note is that it actually seems to have worked when you browse and check the issues and Epic Links in JIRA. But it's ugly that it spams this stuff in the logs :)

Regards
Christoffer

Hi all, I was able to create a task on the Create transition for an Epic and link to Epic Link. My use case is that I want to automatically create an Estimate task (which has its own workflow) each time I create an Epic and link to it.

import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.IssueFactory
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.fields.layout.field.FieldLayoutItem
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.project.ProjectManager
import com.atlassian.jira.project.Project
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.util.ImportUtils
import com.opensymphony.workflow.WorkflowContext

import org.apache.log4j.Logger
import org.apache.log4j.Category

def Category log = Category.getInstance("com.onresolve.jira.groovy")
log.setLevel(org.apache.log4j.Level.DEBUG)

// Get project object
Project project = issue.getProjectObject()

IssueManager issueMgr = ComponentAccessor.getIssueManager()
ProjectManager projectMgr = ComponentAccessor.getProjectManager()
CustomFieldManager cfMgr = ComponentAccessor.getCustomFieldManager()

// Get user object
String currentUser = (String) ((WorkflowContext) transientVars.get("context")).getCaller();
ApplicationUser currentUserObj = ComponentAccessor.getUserManager().getUserByKey(currentUser);

def wasIndexing = ImportUtils.indexIssues
ImportUtils.indexIssues = true
IssueFactory issueFactory = ComponentAccessor.getIssueFactory()

// Epic attributes
def epicSummary = issue.getSummary()
def key = issue.getKey()
def epicIssue = issueMgr.getIssueObject(key)

// Create issue
MutableIssue newIssue = issueFactory.getIssue()

newIssue.setSummary("Estimate for: " + epicSummary)
newIssue.setProjectObject(project)
newIssue.setIssueTypeId("11302") //Estimate type
newIssue.description = "-"
newIssue.reporter = issue.getReporter()
def epicLink = cfMgr.getCustomFieldObjects(newIssue).find { it.name == 'Epic Link' }
newIssue.setCustomFieldValue(epicLink, epicIssue)

// Create Issue
issueMgr.createIssueObject(currentUserObj, newIssue)

ImportUtils.indexIssues = wasIndexing

Hi @Amy Niebel

I have a similar script and I also use the:

i.setCustomFieldValue(cfEpicLink, epicIssue)

 But for me, it generates the following errors:

No signature of method: com.atlassian.jira.issue.DocumentIssueImpl.setCustomFieldValue() is applicable for argument types: (com.atlassian.jira.issue.fields.ImmutableCustomField, com.atlassian.jira.issue.IssueImpl) values: [Epic Link, ARTINFO-185] Possible solutions: getCustomFieldValue(com.atlassian.jira.issue.fields.CustomField)

Have you ever noticed this problem?

Regards
Christoffer

Suggest an answer

Log in or Sign up to answer
Community showcase
Posted Oct 11, 2018 in Marketplace Apps

You + one app + a desert island...

Hi all! My name is Miles and I work on the Marketplace team. We’re looking for better ways to recommend and suggest apps that are truly crowd favorites, so of course we wanted to poll the Community. ...

2,555 views 5 6
Join discussion

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you