-
-
Save hermannschwaerzler/ecc1883bda7bc06b6e34 to your computer and use it in GitHub Desktop.
JIRA: move issue programmatically (in groovy; supported by scriptrunner plugin).
In Jira 4 and 5 storing the changed issue has to be done in a new thread.
Everything wrapped up into a utility class.
Still missing: Thorough testing as well as error and exception handling
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.atlassian.jira.ComponentManager | |
import com.atlassian.crowd.embedded.api.User | |
import com.atlassian.crowd.model.user.UserTemplate | |
import com.atlassian.jira.user.preferences.PreferenceKeys | |
import com.atlassian.jira.issue.Issue | |
import com.atlassian.jira.project.Project | |
import org.ofbiz.core.entity.*; | |
import com.atlassian.jira.issue.MutableIssue | |
import com.atlassian.jira.issue.util.IssueChangeHolder | |
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder | |
import com.atlassian.jira.issue.history.ChangeItemBean | |
import com.atlassian.jira.issue.history.ChangeLogUtils | |
import com.atlassian.jira.issue.attachment.Attachment | |
import com.atlassian.jira.util.AttachmentUtils | |
import com.atlassian.jira.event.issue.IssueEventDispatcher | |
import com.atlassian.jira.event.type.EventType | |
import java.io.File | |
class UIBKUtils { | |
static ComponentManager componentManager = ComponentManager.getInstance() | |
def static indexManager = componentManager.getIndexManager() | |
def static projectManager = componentManager.getProjectManager() | |
def static issueManager = componentManager.getIssueManager() | |
// ... | |
public static void moveIssueToProject(MutableIssue currentIssue, Project targetProject, boolean dispatchEvent = true) { | |
GenericDelegator delegator = GenericDelegator.getGenericDelegator("default") | |
Long issueId = currentIssue.getId() | |
GenericValue originalIssueGV = delegator.findByPrimaryKey(makeIssuePk(delegator, issueId)) | |
String oldKey = currentIssue.getKey() | |
def newIssueNumber = projectManager.getNextId(targetProject) | |
String newKey = targetProject.getKey() + "-" + newIssueNumber | |
Long newProjectId = targetProject.getId() | |
Project currentProject = currentIssue.getProjectObject() | |
// do nothing if target project is the same as source project | |
Long currentProjectId = currentProject.getId() | |
if (newProjectId == currentProjectId) { | |
return | |
} | |
moveAttachments(issueId, newKey, targetProject) | |
GenericValue updatedIssueGV = delegator.findByPrimaryKey(makeIssuePk(delegator, issueId)) | |
updatedIssueGV.setString("key", newKey) | |
updatedIssueGV.setString("project", newProjectId.toString()) | |
IssueChangeHolder changeHolder = new DefaultIssueChangeHolder() | |
changeHolder.addChangeItem( | |
new ChangeItemBean( | |
ChangeItemBean.STATIC_FIELD, | |
"Project", | |
currentProject.getId().toString(), | |
currentProject.getName(), | |
targetProject.getId().toString(), | |
targetProject.getName() | |
) | |
) | |
changeHolder.addChangeItem( | |
new ChangeItemBean( | |
ChangeItemBean.STATIC_FIELD, | |
"Key", | |
null, | |
oldKey, | |
null, | |
newKey | |
) | |
) | |
User currentUser = componentManager.getJiraAuthenticationContext().getUser() | |
GenericValue updateLog = ChangeLogUtils.createChangeGroup( | |
currentUser, | |
originalIssueGV, | |
updatedIssueGV, | |
changeHolder.getChangeItems(), | |
false) | |
// store updated issue in a different thread | |
try { | |
int rowsAffected | |
def th = Thread.start { | |
sleep 50 | |
rowsAffected = delegator.store(updatedIssueGV) | |
indexManager.reIndex(updatedIssueGV) | |
if (dispatchEvent) { | |
Issue newIssue = issueManager.getIssueObject(issueId) | |
dispatchIssueMovedEvent(newIssue, updateLog, changeHolder, currentUser) | |
} | |
} | |
} catch(Exception e) { | |
// ... | |
} | |
} | |
private static GenericPK makeIssuePk(GenericDelegator delegator, Long id) { | |
Map<String, Object> map = new HashMap<String, Object>(); | |
map.put("id", id); | |
return delegator.makePK("Issue", map); | |
} | |
private static void moveAttachments(Long issueId, String newIssueKey, Project targetProject) { | |
def attachmentManager = componentManager.getAttachmentManager() | |
def attachmentPathManager = componentManager.getAttachmentPathManager() | |
Issue issue = issueManager.getIssueObject(issueId) | |
String fSep = System.getProperty("file.separator") | |
List<Attachment> attachments = attachmentManager.getAttachments(issue) | |
attachments.each{ | |
attachment -> | |
File attachmentFile = AttachmentUtils.getAttachmentFile(attachment) | |
String fileName = attachmentFile.getName() | |
String originalFilePath = attachmentFile.getAbsolutePath(); | |
String targetDirectoryPath = | |
attachmentPathManager.getAttachmentPath() + fSep + | |
targetProject.getKey() + fSep + | |
newIssueKey; | |
if (attachmentFile.exists()) { | |
File destDirectory = new File(targetDirectoryPath) | |
destDirectory.mkdirs() | |
attachmentFile.renameTo(new File(destDirectory, fileName)) | |
} else { | |
// ... | |
} | |
} | |
} | |
// generate "Issue Moved" event | |
private static void dispatchIssueMovedEvent(Issue newIssue, GenericValue updateLog, IssueChangeHolder issueChangeHolder, User currentUser) | |
throws GenericEntityException { | |
if ( updateLog != null && !issueChangeHolder.getChangeItems().isEmpty() ) { | |
Long eventTypeId = EventType.ISSUE_MOVED_ID | |
IssueEventDispatcher.dispatchEvent( | |
eventTypeId, | |
newIssue, | |
currentUser, | |
updateLog, | |
true, | |
issueChangeHolder.isSubtasksUpdated() | |
) | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hermann,
In searching answers.atlassian.com your name appeared often and I am hoping you can help me. I am new to JIRA and I have been tasked with modifying a workflow to move issues from one project to another. The goal is to have a capacity to move issues to a 'holding' project if a major delay is encountered. From what I have read I will need to setup a screen for a transition where the user will specify the new project then programmatically move the issue based on the information the user entered. Am I correct in this approach? After reading the various answers/discussions I am not sure if moving issues between projects is possible in the workflow. Is it possible to move issues between projects in the workflow? If it is possible can you give me some guidance on how best to implement this or direct me to resources that could help me? We are running version 6.3.15. Thank you for any help you can provide.
Peace,
Will