What other options do I have to setWorkflowAction other than relying on WorkitemOperation?
commit(WorkItemWorkingCopy[] workingCopies, org.eclipse.core.runtime.IProgressMonitor monitor)
Commits the operation for the given working copies.
public class UpdateWorkItemStatus implements WorkitemResultProcessor {
private static Logger log = LoggerFactory
.getLogger(UpdateWorkItemStatus.class.getName());
String newaction ="";
IProgressMonitor monitor = null;
IProjectArea project_area = null;
public UpdateWorkItemStatus(IProjectArea pa,String statusaction,IProgressMonitor mon){
project_area = pa;
monitor = mon;
newaction = statusaction;
mon.subTask("Preparing to update");
}
public IProgressMonitor getMonitor() {
return monitor;
}
public String getNewaction() {
return newaction;
}
public void execute(IWorkItemHandle wh) throws RtcException {
StatusAssign chgstatus = new StatusAssign(newaction);
try {
log.trace("Creating StatusAssign object to update status");
chgstatus.run(wh,monitor);
} catch (TeamRepositoryException e) {
throw new RtcException("Problem setting status to '"+getNewaction()+"': "+e.getMessage());
}
}
class StatusAssign extends WorkItemOperation {
String newstatus_action = "";
public StatusAssign(String action) {
super("Updating workitem...", IWorkItem.FULL_PROFILE);
newstatus_action = action;
}
public StatusAssign(String name, ItemProfile profile) {
super(name, profile);
}
@Override
protected void execute(WorkItemWorkingCopy workingCopy,IProgressMonitor monitor) throws TeamRepositoryException {
String msg = String.format("Updating workitem %s: setting status to '%s'",workingCopy.getWorkItem().getId(),newstatus_action);
monitor.subTask(msg);
log.debug("Current workflow action is {}",workingCopy.getWorkflowAction());
// this workflow action does not stick
workingCopy.setWorkflowAction(newstatus_action);
// this part works
Timestamp testdate = new Timestamp(new Date().getTime());
workingCopy.getWorkItem().setDueDate(testdate);
// this part works, too
workingCopy.getWorkItem().setTarget(IterationHelper.getIteration(
(ITeamRepository) project_area.getOrigin(), (IProjectArea) project_area.getFullState()
, "HP MBE O 2013 11 04"));
}
}
}
Accepted answer
private static String changeStatus(ITeamRepository repo, Integer workItemId, Boolean buildStatus, String actionOK, String actionKO, IProgressMonitor monitor) throws TeamRepositoryException { IWorkItemClient workItemClient = (IWorkItemClient) repo .getClientLibrary(IWorkItemClient.class); IWorkItemCommon workItemCommon = (IWorkItemCommon) repo .getClientLibrary(IWorkItemCommon.class); IWorkItem wi = workItemClient.findWorkItemById(workItemId, IWorkItem.FULL_PROFILE, monitor); if (null == wi) { return ("work item " + workItemId + " cannot be found"); } IDetailedStatus status = null; String actionName = buildStatus ? actionOK : actionKO; IWorkItemWorkingCopyManager copyManager = workItemClient .getWorkItemWorkingCopyManager(); try { copyManager.connect(wi, IWorkItem.FULL_PROFILE, monitor); WorkItemWorkingCopy wc = copyManager.getWorkingCopy(wi); // wc.getWorkItem().getsetState2(arg0) IWorkflowInfo wfInfo = (IWorkflowInfo) workItemClient .findWorkflowInfo(wi, monitor); Identifier[] actionList = wfInfo.getActionIds(wi .getState2()); String actionId = null; for (int i = 0; i < actionList.length; i++) { Identifier action = actionList[i]; String name = wfInfo.getActionName(action); if (name != null) { if (name.equals(actionName)) { actionId = action.getStringIdentifier(); break; } } } if (null == actionId) { wc.setWorkflowAction(null); } else { wc.setWorkflowAction(actionId); // wc.setWorkflowAction(null); } status = wc.save(monitor); if (status.getCode() != org.eclipse.core.runtime.IStatus.OK) { return "Error: " + status.getDetails(); } } catch (Exception e) { return "Unexpected error: " + e.getMessage(); } finally { copyManager.disconnect(wi); } return null; }
Comments
Thanks, Ralph, will try that right now. On thing I've been wondering about (since setWorkflowAction(string) was not working for me), is the action name the simple/display name of the action or is it some other underlying stringified name of the action Identifier?
I would suggest to read https://rsjazz.wordpress.com/2012/11/26/manipulating-work-item-states/ to understand how that works and how to get the action.
Yes, I have that read but actually you can't tell from the article nor any other examples I've read what the literal action name is that's being passed.
As far as I can see from jumping through my blog entry it is the ID of the action. That is not necessarily the same as the display name (as usually) especially for the shipped templates. You would have to look into the process XML, unfortunately. Here an example screen shot:
I am not sure if I created the path helper you can download on the blog to accept the name instead. should be easy enough to to though. Please also note, the action will only work if you are in a state where this action is valid.
1 vote
If the last code snippet works, the operation should also work. The code below is (if you look at the WorkitemOpetration source code the same code essentially WorkItemOperation runs. The first example is, I believe, a work item operation that does exactly what you want. I think I created it as an example for exactly that purpose. If it does not work, there can be reasons as
- WorkflowAction not found (passed the name not the ID)
- WorkflowAction not applicable in this state
- Another operational behavior that prevents you from changing the state.
I would be surprised if there are other reasons why it should not work.
This is great, info, thank you. I guess this code works because of the looping done to associate the action name with the action identifier whereas in my original WorkItemOperation code, I was just passing the action name. I will try updating the WorkItemOperation code with the ID and see if it works.
Bahdaboom, that worked :) I'm going to file a documentation bug on this, that was a bit frustrating but thanks for your help!
Why would you? This is all over the place. You can never use the name of anything. You have to find the ID. Enumeration Literals https://rsjazz.wordpress.com/2012/08/20/manipulationg-work-item-enumeration-values/ attributes https://rsjazz.wordpress.com/2013/01/02/working-with-work-item-attributes/, wherever you look at.
One of the reasons is the API is the API used for developing the client or the server and they know the ID's and only display the display name for convenience.
I disagree, having the API reader assume a string argument is an ID, a name, a fully resolve classname, an alias, or whatever other string type is obvious is not a good practice for someone writing an API. It's a simple change and has already been made.
Well, you can create your enhancement request.
However, as far as I am aware, the API is not explicitely written as an API for an external user, it is the internal API exposed. And in that case display names, that can be in Chinese, or German or French, or any other language, and that can be changed by the user, are not a good, reliable identifier. Therefore other identifiers, that are more constant are used all over the place. There are other issues with identifiers that don't necessarily have to be unique as well.
3 other answers
If you want to change the state of the work item,you can provide the work item with a workflowAction ( .setWorkFlowAction). See http://rsjazz.wordpress.com/2012/11/26/manipulating-work-item-states/ for more details. There is a deprecated method .setState2() on IWorkItem that you could use to directly set a state. However, that is a bit unsafe, because you could trigger a state change that does not exist and it might also avoid all the behavior defined related to the workflow.
Comments
Yes, thanks, Ralph, I am using setWorkflowAction but unfortunately, it's not working and I can't figure out why. I'll have to try setState2.
Where do you use the setWorkflowAction in the operation? This code used to work for me:
private static class WorkItemSetWorkflowActionModification extends WorkItemOperation {private String fWorkFlowAtion; public WorkItemSetWorkflowActionModification(String workFlowAtion) { super("Modifying Work Item State", IWorkItem.FULL_PROFILE); fWorkFlowAtion = workFlowAtion; } @Override protected void execute(WorkItemWorkingCopy workingCopy, IProgressMonitor monitor) throws TeamRepositoryException { workingCopy.setWorkflowAction(fWorkFlowAtion); } public void setfWorkFlowAtion(String fWorkFlowAtion) { this.fWorkFlowAtion = fWorkFlowAtion; } }
I only implicitly use that API. On the client I usually use a WorkItemOperation that overwrites some method as described for example here: https://rsjazz.wordpress.com/2012/08/01/uploading-attachments-to-work-items/ or here https://jazz.net/wiki/bin/view/Main/ProgrammaticWorkItemCreation. I think that eventually uses the commit() method.
In the server API I use typically saveWorkItem2() or saveWorkItem3() as described in e.g. this blog: https://rsjazz.wordpress.com/2012/07/31/rtc-update-parent-duration-estimation-and-effort-participant/
@Override
protected void execute(WorkItemWorkingCopy workingCopy,IProgressMonitor monitor) throws TeamRepositoryException {
String msg = String.format("Updating workitem %s: setting status to '%s'",workingCopy.getWorkItem().getId(),newstatus_action);
monitor.subTask(msg);
log.debug("Current workflow action is {}",workingCopy.getWorkflowAction());
ITeamRepository repo = (ITeamRepository) workingCopy.getWorkItem().getOrigin();
IWorkItemClient client = (IWorkItemClient) repo.getClientLibrary(IWorkItemClient.class);
IWorkflowInfo wf = client.findWorkflowInfo(workingCopy.getWorkItem(), monitor);
Identifier<IWorkflowAction>[] actionList = wf.getActionIds(workingCopy.getWorkItem().getState2());
String actionId = null;
for (int i = 0; i < actionList.length; i++) {
Identifier<IWorkflowAction> action = actionList[i];
String action_name = wf.getActionName(action);
if (action_name != null) {
if (action_name.equals(newstatus_action)) {
actionId = action.getStringIdentifier();
break;
}
} else {
log.error("identifier for action {} was null",newstatus_action);
}
}
workingCopy.setWorkflowAction(actionId);
}
}
Comments
Aradhya K
JAZZ DEVELOPER Jan 08 '14, 12:29 a.m.How are you setting the value for the work item??
Andy Jewell
Jan 10 '14, 1:36 p.m.Sorry, I'm using the plain java API. I will add more details to the question.