I am trying to create a script in a post-function that will move the issue to a different project. I first tried to just set the project object on the issue to the new project, but that just changed it's project, but did not change the Issue Key to match the Project Key.
Can anyone help me get an issue moved to a new project?
Here is the meat of the code that i have so far which moves the issue and sets the correct workflow and status. I will build more validation into it later for our uses, but this is just to get the bulk of it working first:
Map targetProjectMap = (Map)issue.getCustomFieldValue(targetProjectCF) log.debug("targetProject: " + targetProjectMap) log.debug("Keys: " + targetProjectMap.keySet()) log.debug("values: " + targetProjectMap.values()) String targetProjectName = (String)targetProjectMap.get("name") String targetProjectKey = (String)targetProjectMap.get("key") log.debug("targetProjectName: " + targetProjectName) Project targetProject = projectManager.getProjectObjByKey(targetProjectKey) Project sourceProj = issue.projectObject if (targetProject.name != sourceProj.name){ //Project destProj = projectManager.getProjectObjByName(targetProject) log.debug("Project: " + targetProject.name) mutableIssue.setProjectObject(targetProject) //Do i need to set workflow? IssueType issueType = issue.issueTypeObject log.debug("IssueType: " + issueType.name + " : " + issueType.id) String WFname = workflowSchemeManager.getWorkflowName(targetProject,issueType.id) log.debug("Workflow Name: " + WFname) workflowManager.migrateIssueToWorkflow(mutableIssue,workflowManager.getWorkflow(WFname),statusManager.getStatus("1")) }
Community moderators have prevented the ability to post new answers.
Problem Resolved (all version compactable ) look to the link below:
Thanks
~Sohil
I tried this together a while ago and came unstuck somewhere. Actually I can't even remember if I came unstuck but I presume I did otherwise I would have probably made it into a built-in script.
I normally hack some code together to prove the concept, and that's as far as I got. Perhaps it will help you. BTW the ctor arguments appear to be out of date for the latest version. The fact that this is not available in any @PublicApi should probably be enough to put you off, unless you have a taste for adventure.
https://gist.github.com/jamieechlin/5213550
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I'll look into this to see if i can figure out how to do this in a workflow post-function. It is a very specific use case for us, so i should be able to limit the possible problems since i will be controlling the specific projects, issue types, etc, that this script will activate on. I'll post more when i figure out more.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I tried your code as a script-runner post-function, Jamie. But I am getting a NullPointerExeption inside MoveIssueConfirm.doExecute():
java.lang.NullPointerException at com.atlassian.jira.web.action.issue.MoveIssueConfirm.moveIssueDetails(MoveIssueConfirm.java:361) at com.atlassian.jira.web.action.issue.MoveIssueConfirm.moveIssueInTxn(MoveIssueConfirm.java:301) at com.atlassian.jira.web.action.issue.MoveIssueConfirm.doExecute(MoveIssueConfirm.java:273)
This is JIRA 4.4.4.
For me it looks like the issue-type of the target issue is not set. But trying to set it using
moveIssueConfirm.getFieldValuesHolder().put(IssueFieldConstants.ISSUE_TYPE, targetIssueType)
before calling doExecute() does not help.
Any hints?
Greetings
Hermann
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
you can't move issues to another project using programatically, there is no api
check the following issue
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
It's not true that there's no API, otherwise you wouldn't be able to it in jira via the web UI. There may be no @PublicApi, but that's not the same.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I made a small class to reuse this as often as I need.
Make the usage of Moving issue from a project a another project pretty easy.
Thanks to all the other suggestion on the top. You helped a lot making it possible.
Works on JIRA 6.2.7 script console, but it doesn't work for Listeners, Post FUnction or Service. That is weird.
as a service and listeners, it throw a sun reflect error.
import com.atlassian.core.ofbiz.util.CoreTransactionUtil import com.atlassian.jira.bc.issue.comment.CommentService import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.config.ConstantsManager import com.atlassian.jira.config.StatusManager import com.atlassian.jira.config.properties.JiraSystemProperties import com.atlassian.jira.issue.AttachmentManager import com.atlassian.jira.issue.IssueFieldConstants import com.atlassian.jira.issue.MutableIssue import com.atlassian.jira.issue.issuetype.IssueType import com.atlassian.jira.issue.security.IssueSecurityHelper import com.atlassian.jira.project.Project import com.atlassian.jira.project.ProjectManager import com.atlassian.jira.web.SessionKeys import com.atlassian.jira.web.action.issue.MoveIssueConfirm import com.atlassian.jira.web.action.issue.MoveIssueUpdateFields import com.atlassian.jira.web.bean.MoveIssueBean import webwork.action.ActionContext import java.lang.reflect.Method import org.apache.log4j.Category class ProjectIssueMove { Category log = Category.getInstance(ProjectIssueMove.class) public void moveIssueToAnotherProject(String newProjectKey, String newIssueType, String newStatusName, MutableIssue targetIssue) { try { MoveIssueBean moveIssueBean = new MoveIssueBean(ComponentAccessor.getConstantsManager(), ComponentAccessor.getProjectManager()) moveIssueBean.getFieldValuesHolder().put(IssueFieldConstants.PROJECT, getProjectFromKey(newProjectKey).id) moveIssueBean.getFieldValuesHolder().put(IssueFieldConstants.ISSUE_TYPE, getTargetIssueType(newIssueType).id) moveIssueBean.setIssueId(targetIssue.getId()) moveIssueBean.setTargetStatusId(getStatusToSet(newStatusName).id) moveIssueBean.setSourceIssueKey(targetIssue.getKey()) moveIssueBean.setUpdatedIssue(targetIssue) ActionContext.getSession().put(SessionKeys.MOVEISSUEBEAN, moveIssueBean) MoveIssueUpdateFields moveIssueUpdateFields = new MoveIssueUpdateFields( ComponentAccessor.getSubTaskManager(), ComponentAccessor.getConstantsManager(), ComponentAccessor.getWorkflowManager(), ComponentAccessor.getFieldManager(), ComponentAccessor.getFieldLayoutManager(), ComponentAccessor.getIssueFactory(), ComponentAccessor.getFieldScreenRendererFactory(), ComponentAccessor.getComponentOfType(CommentService.class), ComponentAccessor.getComponentOfType(IssueSecurityHelper.class), ComponentAccessor.getUserUtil() ) MoveIssueConfirm moveIssueConfirm = new MoveIssueConfirm( ComponentAccessor.getSubTaskManager(), ComponentAccessor.getComponentOfType(AttachmentManager.class), ComponentAccessor.getConstantsManager(), ComponentAccessor.getWorkflowManager(), ComponentAccessor.getFieldManager(), ComponentAccessor.getFieldLayoutManager(), ComponentAccessor.getIssueFactory(), ComponentAccessor.getFieldScreenRendererFactory(), ComponentAccessor.getComponentOfType(CommentService.class), ComponentAccessor.getComponentOfType(IssueSecurityHelper.class), ComponentAccessor.getIssueManager(), ComponentAccessor.getUserUtil() ) JiraSystemProperties.getInstance() moveIssueUpdateFields.setId(targetIssue.getId()) Method privateUpdateFieldsDoExecute = MoveIssueUpdateFields.class.getDeclaredMethod("doExecute") privateUpdateFieldsDoExecute.setAccessible(true) privateUpdateFieldsDoExecute.invoke(moveIssueUpdateFields) moveIssueConfirm.setId(targetIssue.getId()) Method privateIssueConfirmDoExecute = MoveIssueConfirm.class.getDeclaredMethod("doExecute") privateIssueConfirmDoExecute.setAccessible(true) privateIssueConfirmDoExecute.invoke(moveIssueConfirm) CoreTransactionUtil.commit(true) } catch (Exception e) { log.error("move issue failed " + e.message) } } private Project getProjectFromKey(String projectKey) { //get the projectObject from a String key ProjectManager projectManager = ComponentAccessor.getProjectManager() return projectManager.getProjectObjByKeyIgnoreCase(projectKey) } def getStatusToSet(String statusName) { //find the status object from a status name StatusManager statusManager = ComponentAccessor.getComponentOfType(StatusManager.class) def statuses = statusManager.getStatuses() def iterator = statuses.iterator() while (iterator.hasNext()) { def status = iterator.next() if (status.getName() == statusName) { return status } } return null } def IssueType getTargetIssueType(String issueTypeName) { //Find the issue type object from a issue type name ConstantsManager constantsManager = ComponentAccessor.getConstantsManager() def issueTypes = constantsManager.getAllIssueTypeObjects() def issuetypeiterator = issueTypes.iterator() while (issuetypeiterator.hasNext()) { def issueType = issuetypeiterator.next() if (issueType.name.toLowerCase() == issueTypeName.toLowerCase()) { return issueType } } return null } }
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You can make that a bit simpler with: import webwork.util.injection.ObjectFactory def bulkMoveOperation = ObjectFactory.instantiate(MoveIssueUpdateFields.class) as MoveIssueUpdateFields Same for other one. Still quite liable to break between different instances though.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Sorry, I meant versions not instances.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Also looks like it would break if someone is using the rest API as there is no session.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You are right for the API. And Also I have a problem with the fact that running it in a PostFunction or a listener, it freeze the issue (turn around endlessly). A refresh of the issue is needed and the move is complete. can't make this working : def bulkMoveOperation = ObjectFactory.instantiate(MoveIssueUpdateFields.class) as MoveIssueUpdateFields Dunno what I am doing wrong. Should it look like this : def bulkMoveOperation = ObjectFactory.instantiate(MoveIssueUpdateFields.class) as MoveIssueUpdateFields bulkMoveOperation.doExecute() def bulkMoveConfirm = ObjectFactory.instantiate(MoveIssueConfirm.class) as MoveIssueConfirm bulkMoveConfirm.doExecute() I tried to put it in a thread, but since it's a webAction, it doesn't work in a different thread. Thats a shame. It would have been so perfect. If you have any ideas.. It would be really great. Thanks a lot for your time Jamie Michel
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I know it's a pretty old one, but it can't hurt to try :)
I use a similar code for the move issue post function and it works good but the issue screen is getting darker and the user need to refresh the page in order to see the updated issue (same as Michel mention)
Did anyone has an idea how it can be resolve?
thanks
Dar
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Yes :
replace
String msg = moveIssueUpdateFields.doExecute(); and msg = moveIssueConfirm.doExecute();
with
// use of java reflection to access protected method since Jira 6.2.7 Method privateUpdateFieldsDoExecute = MoveIssueUpdateFields.class.getDeclaredMethod("doExecute"); privateUpdateFieldsDoExecute.setAccessible(true); String msg = (String) privateUpdateFieldsDoExecute.invoke(moveIssueUpdateFields); // same thing for moveIssueConfirm Method privateIssueConfirmDoExecute = MoveIssueConfirm.class.getDeclaredMethod("doExecute"); privateIssueConfirmDoExecute.setAccessible(true); msg = (String) privateIssueConfirmDoExecute.invoke(moveIssueConfirm);
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you for that answer (Herman).
It helps me to do it, but for Jira 6.1.3 I had to modify a few things.
Here is my code for changing issue type and Status Id (keeping the same project) :
String EnAttenteStatusId = "1"; MoveIssueBean moveIssueBean = new MoveIssueBean(ComponentAccessor.getConstantsManager(), ComponentAccessor.getProjectManager()); moveIssueBean.getFieldValuesHolder().put(IssueFieldConstants.PROJECT, _targetIssue.getProjectId()); moveIssueBean.getFieldValuesHolder().put(IssueFieldConstants.ISSUE_TYPE, _issueTypeId); moveIssueBean.setIssueId(_targetIssue.getId()); moveIssueBean.setTargetStatusId(EnAttenteStatusId); moveIssueBean.setSourceIssueKey(_targetIssue.getKey()); moveIssueBean.setUpdatedIssue(_targetIssue); ActionContext.getSession().put(SessionKeys.MOVEISSUEBEAN, moveIssueBean); MoveIssueUpdateFields moveIssueUpdateFields = new MoveIssueUpdateFields( ComponentAccessor.getSubTaskManager(), ComponentAccessor.getConstantsManager(), ComponentAccessor.getWorkflowManager(), ComponentAccessor.getFieldManager(), ComponentAccessor.getFieldLayoutManager(), ComponentAccessor.getIssueFactory(), ComponentAccessor.getFieldScreenRendererFactory(), ComponentAccessor.getComponentOfType(CommentService.class), ComponentAccessor.getComponentOfType(IssueSecurityHelper.class), ComponentAccessor.getUserUtil() ); MoveIssueConfirm moveIssueConfirm = new MoveIssueConfirm( ComponentAccessor.getSubTaskManager(), ComponentAccessor.getComponentOfType(AttachmentManager.class), ComponentAccessor.getConstantsManager(), ComponentAccessor.getWorkflowManager(), ComponentAccessor.getFieldManager(), ComponentAccessor.getFieldLayoutManager(), ComponentAccessor.getIssueFactory(), ComponentAccessor.getFieldScreenRendererFactory(), ComponentAccessor.getComponentOfType(CommentService.class), ComponentAccessor.getComponentOfType(IssueSecurityHelper.class), ComponentAccessor.getIssueManager(), ComponentAccessor.getUserUtil() ); JiraSystemProperties.getInstance(); moveIssueUpdateFields.setId(_targetIssue.getId()); String msg = moveIssueUpdateFields.doExecute(); log.debug("moveIssueUpdateFields.doExecute() result = "+msg); moveIssueConfirm.setId(_targetIssue.getId()); msg = moveIssueConfirm.doExecute(); log.debug("moveIssueConfirm.doExecute() result = "+msg); return msg;
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Assuming that in your case there are no new required fields for the new issue type, right?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Right. If you have new required fields I think you need to use "moveIssueBean.setFieldValues(fieldValues)" but I have never tried it.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello
Using the code of Jamie (see https://answers.atlassian.com/questions/150179/how-to-move-an-issue-programatically-to-a-different-project/150547) I was able to move an issue programmatically!
But unfortunately not in a post-function or a listener. It only works if I am using a custom webwork plugin to add an action to the issue view. Everything happens inside the doExecute() function of the class I associate with that action:
/** * The current issue Id is passed to us because we defined * the <link> of out <web-item> as * <link linkId="...">/secure/MoveToSPAM.jspa?id=${issueId}</link> * in the atlassian-plugin.xml */ private String issueId = null; /** * This method is automatically discovered and called by JSP and Webwork * if the name matches the id of a parameter passed in an HTML form. */ public void setId(String value) { this.issueId = value; } public String getId() { return this.issueId; } protected String doExecute() throws Exception { Long issueId = 0L; try { String id = getId(); if (id != null) { issueId = Long.parseLong(id, 10); } else { return "Issue ID is null"; } } catch (Exception e) { log.warn("Issue ID is not a Long: "+ e); return "Issue ID is not a Long"; } // This is Jamies code with some small changes // Not necessary to make things work: //CoreTransactionUtil.begin(); log.debug("Starting to move Issue"); ComponentManager componentManager = ComponentManager.getInstance(); ProjectManager projectManager = componentManager.getProjectManager(); // I want to move it to a designated "SPAM"-Queue Project targetProject = projectManager.getProjectObjByKey("SPAM"); IssueManager issueManager = componentManager.getIssueManager(); MutableIssue targetIssue = issueManager.getIssueObject(issueId); MoveIssueBean moveIssueBean = new MoveIssueBean(componentManager.getConstantsManager(), projectManager); moveIssueBean.getFieldValuesHolder().put(IssueFieldConstants.PROJECT, targetProject.getId()); moveIssueBean.getFieldValuesHolder().put(IssueFieldConstants.ISSUE_TYPE, targetIssue.getIssueTypeObject().getId()); moveIssueBean.setIssueId(targetIssue.getId()); moveIssueBean.setTargetStatusId(targetIssue.getStatusObject().getId()); ActionContext.getSession().put(SessionKeys.MOVEISSUEBEAN, moveIssueBean); MoveIssueUpdateFields moveIssueUpdateFields = new MoveIssueUpdateFields( componentManager.getIssueLinkManager(), componentManager.getSubTaskManager(), componentManager.getConstantsManager(), componentManager.getWorkflowManager(), componentManager.getFieldManager(), componentManager.getFieldLayoutManager(), componentManager.getIssueFactory(), componentManager.getFieldScreenRendererFactory(), ComponentManager.getComponentInstanceOfType(CommentService.class), ComponentManager.getComponentInstanceOfType(IssueSecurityHelper.class) ); MoveIssueConfirm moveIssueConfirm = new MoveIssueConfirm( componentManager.getIssueLinkManager(), componentManager.getSubTaskManager(), ComponentManager.getComponentInstanceOfType(AttachmentManager.class), componentManager.getConstantsManager(), componentManager.getWorkflowManager(), componentManager.getFieldManager(), componentManager.getFieldLayoutManager(), componentManager.getIssueFactory(), componentManager.getFieldScreenRendererFactory(), ComponentManager.getComponentInstanceOfType(CommentService.class), ComponentManager.getComponentInstanceOfType(IssueSecurityHelper.class), issueManager, componentManager.getAttachmentPathManager() ); moveIssueUpdateFields.setId(targetIssue.getId()); moveIssueUpdateFields.doExecute(); moveIssueConfirm.setId(targetIssue.getId()); return moveIssueConfirm.doExecute(); }
So this answers your (and my) question only partially. Or it raises another question: Why does the same code not work in a post-function or a listener of a workflow step? As I said before the problem there is that the move seemsto work but gets reverted/rolled back/undone somehow somewhere later in the process of doing that workflow step!
Should I post a new question regarding this or can we discuss this here?
Greetings
Hermann
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I upgraded to Jira 6.2.7 and the doExecute() are now protected.
How are we suppose to do it now ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Well I found a different solution (that works inside a post-function or listener) that does not use MoveIssueConfirm et al. but GenericValue and GenericDelegator.
Maybe this works with 6.2.7 as well?
As we have a rather simple setup (one single workflow for all projects, just one issue-type asf), my solution may be of limited use...
Send me a personal mail to hermann.schwaerzler arobas uibk.ac.at if you want me to send you the code I am using.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Finally I did it using java reflection to call the protected methods doExecute().
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
yes exactly @Adam those classes are used differently through the web UI. i also failde in attempting the above class using a Listener plugin approach.. Any one have any other idea. I feel that i can be achieve with the aproach @jamie have tried.
Map targetProjectMap = (Map)issue.getCustomFieldValue(targetProjectCF) log.debug("targetProject: " + targetProjectMap) log.debug("Keys: " + targetProjectMap.keySet()) log.debug("values: " + targetProjectMap.values()) String targetProjectName = (String)targetProjectMap.get("name") String targetProjectKey = (String)targetProjectMap.get("key") log.debug("targetProjectName: " + targetProjectName) Project targetProject = projectManager.getProjectObjByKey(targetProjectKey) Project sourceProj = issue.projectObject if (targetProject.name != sourceProj.name){ //Project destProj = projectManager.getProjectObjByName(targetProject) log.debug("Project: " + targetProject.name) mutableIssue.setProjectObject(targetProject) //Do i need to set workflow? IssueType issueType = issue.issueTypeObject log.debug("IssueType: " + issueType.name + " : " + issueType.id) String WFname = workflowSchemeManager.getWorkflowName(targetProject,issueType.id) log.debug("Workflow Name: " + WFname) workflowManager.migrateIssueToWorkflow(mutableIssue,workflowManager.getWorkflow(WFname),statusManager.getStatus("1"))
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Yep..........
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I am able to import those classes into my script via Idea. However, don't those need to be used differently from the normal classes since they are web actions? I've never used one of those before that i know of, does anyone have any examples of using other web actions that i can reference to help determine how to use these? Thanks.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
i tried that too. i have the latest verstion of installation. is it working for you?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Add all the jars and classes that ship with jira...
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
True @Jamie Echlin.
I am too working on the same function. just now i am able to see the com.atlassian.jira.web.action.issue.MoveIssue.
but one issue in it is it is not getting loaded into the Idea IDE :( please can you find some way
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I would take a look at com.atlassian.jira.web.action.issue.MoveIssueUpdateFields and com.atlassian.jira.web.action.issue.MoveIssueConfirm. Agree with Anton's comment though in https://jira.atlassian.com/browse/JRA-16494
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Community moderators have prevented the ability to post new answers.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.