显然,这是不可能用 JIRA 开箱即用的; “项目”只是不支持任何历史搜索功能: https://confluence.atlassian.com/jiracoreserver073/advanced-searching-fields-reference-861257219.html#Advancedsearchingfieldsreference-ProjectProject
但是,通过一些谷歌搜索,您似乎可以使用 ScriptRunner 来完成此任务: https://community.atlassian.com/t5/Jira-questions/View-issues-that-have-been-moved-from-one-project-to-another/qaq-p/790346
在 Jira Data Center 中有 2 种方法可以实现此目的:
让我们看看如何使用 ScriptRunner 为 Jira Data Center 创建您自己的 自定义 JQL 函数。
自定义功能:
issuesWithChangedProject(fromProject, toProject)
List<QueryLiteral>
的形式返回合适问题的 ID 列表。JQL中的自定义函数使用示例:
issue in issuesWithChangedProject('*', '*')
issue in issuesWithChangedProject('Customer triage', '*')
该功能可以有效地搜索 Jira 数据库表中存储的问题更改历史记录。
首先,您需要创建名为“local”的ScriptRunner资源/本地数据库连接。
其次,您必须将此函数代码放入 ScriptRunner 编辑器中com/onresolve/jira/groovy/jql 包文件夹中的类文件 IssuesWithChangedProject.groovy 中:
package com.onresolve.jira.groovy.jql
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.jql.operand.QueryLiteral
import com.atlassian.jira.jql.query.QueryCreationContext
import com.atlassian.jira.jql.resolver.ProjectResolver
import com.atlassian.query.clause.TerminalClause
import com.atlassian.query.operand.FunctionOperand
import groovy.sql.GroovyRowResult
import groovy.transform.CompileStatic
import com.onresolve.scriptrunner.db.DatabaseUtil
@CompileStatic
class IssuesWithChangedProject extends AbstractScriptedJqlFunction implements JqlFunction {
private static final ProjectResolver projectResolver = ComponentAccessor.getComponent(ProjectResolver)
@Override
String getDescription() {
'Issues which project has been changed'
}
@Override
List<Map> getArguments() {
[
[
description: 'From project',
optional: false,
],
[
description: 'To project',
optional: false,
]
] as List<Map>
}
@Override
String getFunctionName() {
'issuesWithChangedProject'
}
@Override
List<QueryLiteral> getValues(
QueryCreationContext queryCreationContext,
FunctionOperand operand,
TerminalClause terminalClause
) {
String fromProjectIdOrName = operand.getArgs()?.getAt(0)?.trim()
String toProjectIdOrName = operand.getArgs()?.getAt(1)?.trim()
final queryBuilder = new StringBuilder('''
SELECT
cg.issueid
FROM changegroup cg
LEFT JOIN changeitem ci ON ci.groupid = cg.id
WHERE
ci.field = 'project'
''')
if (fromProjectIdOrName && fromProjectIdOrName != '*') {
Set<String> projectIds = getProjectIds(fromProjectIdOrName)
if (projectIds) {
queryBuilder.append(" AND ci.oldvalue in ('${projectIds.join("', '")}')")
}
}
if (toProjectIdOrName && toProjectIdOrName != '*') {
Set<String> projectIds = getProjectIds(toProjectIdOrName)
if (projectIds) {
queryBuilder.append(" AND ci.newvalue in ('${projectIds.join("', '")}')")
}
}
final Set<Long> issueIds = (Set<Long>)DatabaseUtil.withSql('local') { sql ->
getIdsFromSqlRows(sql.rows(queryBuilder.toString()))
}
issueIds?.collect { new QueryLiteral(operand, it)} ?: []
}
/**
* Convert SQL result to set of issue IDs.
* @param rows SQL query result.
* @return Set of issue IDs.
*/
private static Set<Long> getIdsFromSqlRows(List<GroovyRowResult> rows) {
rows?.collect {row ->
((BigDecimal)row?.getAt(0))?.toLong()
}?.toSet()
}
/**
* Converts project ID or name into the unified set of project IDs suitable for SQL.
* @param projectIdOrName Project ID or name.
* @return Set of project IDs.
*/
private static Set<String> getProjectIds(String projectIdOrName) {
final Set<String> result = new HashSet<String>()
if (projectIdOrName) {
// Guess that projectIdOrName contains the project name and try to get IDs for it
result.addAll(projectResolver.getIdsFromName(projectIdOrName))
if (!result) {
// Suppose that projectIdOrName actually contains numeric ID of the project
try {
final project = projectResolver.get(Long.parseLong(projectIdOrName))
if (project) {
result.add(project.id.toString())
}
} catch (NumberFormatException ignored) {
// ignore
}
}
}
result
}
}
最后,打开 ScriptRunner 管理界面,转到 JQL 函数选项卡,然后单击描述中的“扫描”链接。
并尝试在 JQL 搜索中使用此功能,例如:
issue in issuesWithChangedProject('Customer triage', '*')
如果出现错误,您可以在 ScriptRunner JQL 函数部分找到新函数的执行日志。