Jira ScriptRunner(Groovy)实现跨项目复制工单时代码报错求助
问题根因排查
三个报错的核心原因逐一对应:
- 异常1根因:Project Picker类型自定义字段的返回值本身就是
Project对象,不是项目Key字符串。代码中将返回值强转为String类型后传入getProjectObjByKey(),方法实际拿到的是Project对象的toString()结果(通常是项目名称+对象哈希,并非项目Key),因此查询返回null。 - 异常2根因:
IssueManager.createIssueObject()没有接收(User, Map)格式参数的重载方法。代码中将MutableIssue对象套在key为issue的Map里传入,方法无法解析参数,导致创建失败返回null。该方法正确的传参方式是直接传入构造完成的MutableIssue对象。 - 异常3根因:属于异常2的连锁错误,由于Issue创建失败返回null,调用null对象的
id属性会直接抛出空指针异常。
修正后的可运行代码
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.project.Project import com.atlassian.jira.issue.MutableIssue import com.atlassian.jira.user.ApplicationUser // 初始化Jira组件 def issueMgr = ComponentAccessor.issueManager def customFieldManager = ComponentAccessor.customFieldManager def projectMgr = ComponentAccessor.projectManager def issueFactory = ComponentAccessor.issueFactory def issueTypeSchemeManager = ComponentAccessor.issueTypeSchemeManager def issueLinkManager = ComponentAccessor.issueLinkManager // 获取项目选择自定义字段 def cfProjectPicker = customFieldManager.getCustomFieldObjectByName("Seleccionar Proyecto") // 测试用源Issue,正式部署到工作流时可直接使用ScriptRunner自动绑定的issue变量 def sourceIssue = issueMgr.getIssueObject("MART1-1") ApplicationUser currentUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser // 存储已复制Issue ID的列表,用于后续关联Issue去重 List<String> issuesCopied = new ArrayList<>() if (issuesCopied.isEmpty()) { // 正确获取目标项目:Project Picker返回值本身就是Project对象,无需按Key二次查询 def targetProject = sourceIssue.getCustomFieldValue(cfProjectPicker) as Project log.error("选中的目标项目:${targetProject.name}(${targetProject.key})") // 空值校验 if (!targetProject) { log.error("未获取到选中的目标项目,终止复制流程") return } // 构造新Issue对象 MutableIssue newIssue = issueFactory.issue newIssue.setProjectObject(targetProject) // 校验目标项目问题类型合法性,不兼容原问题类型时自动使用目标项目的默认问题类型 def validIssueTypes = issueTypeSchemeManager.getIssueTypesForProject(targetProject) def targetIssueType = validIssueTypes.contains(sourceIssue.issueType) ? sourceIssue.issueType : validIssueTypes.first() newIssue.setIssueType(targetIssueType) newIssue.setSummary(sourceIssue.summary) newIssue.setDescription(sourceIssue.description) newIssue.setReporter(currentUser) // 调用创建方法,直接传入MutableIssue对象,无需包装为Map def createNewIssue = issueMgr.createIssueObject(currentUser, newIssue) log.error("新Issue创建成功:${createNewIssue.key}") issuesCopied.add(createNewIssue.id.toString()) }
额外注意事项
- 正式部署到工作流后置脚本时,不需要手动调用
getIssueObject()获取当前触发Issue,ScriptRunner会自动绑定issue变量为当前触发流程的Issue对象。 - 后续扩展复制关联Issue逻辑时,需通过
issuesCopied列表做已复制记录,避免双向关联的Issue出现循环复制问题。 - 当前示例仅复制了基础系统字段,若需要同步自定义字段值、附件、评论、Issue链接,需要补充对应字段的赋值逻辑。
内容的提问来源于stack exchange,提问作者Yurivexo
相关产品推荐
相关产品推荐

