You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.17 16:16:01