Jira中 Issue链接的介绍
一、基本介绍
在Jira中,Issue Link(问题链接)用于在不同的任务(Issue)中建立关联。通过这些链接,你可以清晰地展示问题之间的关系,从而更好的管理和追踪项目进度。这些链接有助于团队成员理解不同任务间的相互影响,促进有效的协作和问题解决。
Jira内置了几种常见的链接类型:比如Blocks,Cloners,Duplicate,Relates,同时还可以根据自己的业务需求创建更多的链接类型。
需要注意的是Issue Link是双向的关系,inward是指其它Issue链到自己的方向(链入),outward是指从自己链到其它Issue的方向(链出),都是以自己为视角来定义的,那么从同一个Issue Link两端的Issue来看显示的链接名称分别的inward和outward。
二、数据库设计
Issue Link相关的表只有两个,issuelinktype和issuelink表
- issuelinktype.linkname只在管理issuelinktype时会使用,在其它地方不会使用。
- issuelinktype.inward 其它issue链到自己时在自己的页面上会显示这个链接名称。
- issuelinktype.outward 自己链到其它issue时在自己的页面上会显示这个链接名称。
- issuelink.linktype 指链接类型的ID
- issuelink.source 如果当前issue在source列,那么只能查outward类型的链接,通过destinationObject取到对面的issue。
- issuelink.destination 如果当前issue在destination列,那么只能查Inward类型的链接,通过sourceObject取到对面的issue。
三、页面操作
只有具有超级管理员的权限才能管理问题链接,页面位于系统管理->问题->问题链接。
- 问题链接有全局状态,禁用之后所有问题都不显示链接,但是不会删除链接类型和Issue的链接数据,启用之后会重新显示。
- 链接类型的链入和链出描述应该准确反应实际链接方向的关系逻辑 ,避免在使用及维护中产生歧义。
- 链接名称尽量不修改,如果修改确保在自定义角本或其它程序中使用了链接名称的地方一并修改
在这里我们创建了一个名称叫"拆分任务"的链接类型,用以反映出父子关系的任务:
接着我们创建一些Issue通过"拆分任务"接连把它们关联起来,关联关系如下图所示,TEST-1拆分为TEST-6、TEST-7、TEST-8、TEST-9,其中TEST-7又拆分为TEST-10、TEST-11。
四、进阶使用
基于上图中拆分任务的链接类型,我们来实现递归查找拆分任务和递归查找父任务,找到之后可以处理一些计算或者触发关联系统的操作。
Issue间的链接数据见图2,在Scriptrunner插件中编写脚本进行测试:
import com.atlassian.jira.issue.link.IssueLink
import com.atlassian.jira.component.ComponentAccessor
def currentIssue = Issues.getByKey("TEST-1")
log.warn("\n递归查找${currentIssue.id}的子任务")
getOutwardLinkIssues(currentIssue)
def currentIssue2 = Issues.getByKey("TEST-10")
log.warn("\n递归查找${currentIssue2.id}的父任务")
getInwardLinkIssues(currentIssue2)
// 递归查找链出的问题
def getOutwardLinkIssues(issue) {
def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def outwardLinks = issueLinkManager.getOutwardLinks(issue.id)
outwardLinks.each { outwardLink -> {
log.warn("${issue.key} ${outwardLink.issueLinkType.outward }:${outwardLink.destinationObject.key} ${outwardLink.destinationObject.id}" )
getOutwardLinkIssues(outwardLink.destinationObject)
} }
}
// 递归查找链入的问题
def getInwardLinkIssues(issue) {
def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def inwardLinks = issueLinkManager.getInwardLinks(issue.id)
inwardLinks.each { inwardLink -> {
log.warn("${issue.key} ${inwardLink.issueLinkType.inward }:${inwardLink.sourceObject.key} ${inwardLink.sourceObject.id}")
getInwardLinkIssues(inwardLink.sourceObject)
} }
}
输出:
2024-09-02T12:36:51,975 WARN [runner.ScriptBindingsManager]:
递归查找11000的子任务
2024-09-02T12:36:51,978 WARN [runner.ScriptBindingsManager]: TEST-1 (11000) 拆分为(子任务):TEST-6 (11005)
2024-09-02T12:36:51,979 WARN [runner.ScriptBindingsManager]: TEST-1 (11000) 拆分为(子任务):TEST-9 (11008)
2024-09-02T12:36:51,981 WARN [runner.ScriptBindingsManager]: TEST-1 (11000) 拆分为(子任务):TEST-7 (11006)
2024-09-02T12:36:51,983 WARN [runner.ScriptBindingsManager]: TEST-7 (11006) 拆分为(子任务):TEST-10 (11009)
2024-09-02T12:36:51,985 WARN [runner.ScriptBindingsManager]: TEST-7 (11006) 拆分为(子任务):TEST-11 (11010)
2024-09-02T12:36:51,986 WARN [runner.ScriptBindingsManager]: TEST-1 (11000) 拆分为(子任务):TEST-8 (11007)
2024-09-02T12:36:51,990 WARN [runner.ScriptBindingsManager]:
递归查找11009的父任务
2024-09-02T12:36:51,991 WARN [runner.ScriptBindingsManager]: TEST-10 (11009) 拆分自(父任务):TEST-7 (11006)
2024-09-02T12:36:51,993 WARN [runner.ScriptBindingsManager]: TEST-7 (11006) 拆分自(父任务):TEST-1 (11000)
五、注意事项
在上面的脚本中我们通过递归的方式来查找Issue,如果在这些Issue中存在相同链接的相互依赖,就会出现栈内存溢出,开发中处理避免出现此类问题。
如下图TEST-6与TEST-1相互为同一个链接的两端,运行上述代码就会出现StackOverflowError,如下图:
六、结语
Issue Link在Jira中非常强大,敏捷看板中任务拆分就是基于问题链接来实现的,常见的插件比如WBS、甘特图都是基于此来实现。同时如果需要比Jira本身Epic、Story、Issue、Sub-Task的几种层级关系更多层级的话也可以基于此来实现,结合合理的规划及脚本可实现复杂的需求。