It's all about the answers!

Ask a question

Restrict parent-child links between work items?


Jorge Gabriel Pereira (814) | asked Mar 14 '16, 9:28 a.m.
 Hi team.

Example: My use model says that the hierarchy should be:
Epic -> Story -> Task -> Defect

But in some cases where the user forgets to link the work items or are linking wrong.
Example: Epic -> Defect

They already have created templates, but are very useful just when I start a new dev project.

What I need:
Restrict only the links defined in my use model to be created.

Defects can only be children of Task.
Tasks can only be children of Story.
Story can only be children of Epic.

Tks
JG

Comments
Jorge Gabriel Pereira commented Mar 14 '16, 11:58 a.m. | edited Mar 14 '16, 4:06 p.m.

Ralph and Nate, tks a lot.


I understood that there is no built-in option.
I will study and adapt Nate solution.

Ralph, by chance, I am also reading your blog today to another problem: Deliver on the wrong workitem. Tks again.
:-)
Restrict Delivery of Changesets Associated to Wrong Work Item Types Advisor

Accepted answer


permanent link
Nate Decker (37813058) | answered Mar 14 '16, 10:37 a.m.

I implemented something very similar to this in our environment. We had a certain usage model for how we expected work items to be linked to one another in a plan. If users didn't conform to this usage model, our earned value reports wouldn't display correctly. To try and teach people the correct usage model, we implemented a precondition that throws warnings (not errors) if a user violates the expected link relationships. Here's my code:

package com.smxg.opex.clm;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.links.common.IReference;
import com.ibm.team.process.common.IProcessConfigurationElement;
import com.ibm.team.process.common.advice.AdvisableOperation;
import com.ibm.team.process.common.advice.IAdvisorInfo;
import com.ibm.team.process.common.advice.IAdvisorInfoCollector;
import com.ibm.team.process.common.advice.runtime.IOperationAdvisor;
import com.ibm.team.repository.common.IAuditable;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.repository.service.AbstractService;
import com.ibm.team.workitem.common.IAuditableCommon;
import com.ibm.team.workitem.common.ISaveParameter;
import com.ibm.team.workitem.common.internal.workflow.WorkflowManager;
import com.ibm.team.workitem.common.model.IWorkItem;
import com.ibm.team.workitem.common.model.IWorkItemHandle;
import com.ibm.team.workitem.common.model.WorkItemEndPoints;
import com.ibm.team.workitem.common.workflow.IWorkflowInfo;
import com.ibm.team.workitem.service.IWorkItemServer;

public class EnforceEarnedValueUsageModel extends AbstractService implements IOperationAdvisor
{
 boolean Debug = false;
 @Override
 public void run(AdvisableOperation operation, IProcessConfigurationElement advisorConfiguration, IAdvisorInfoCollector collector, IProgressMonitor monitor) throws TeamRepositoryException
 {
  if(advisorConfiguration.getAttribute("description") != null) Debug = advisorConfiguration.getAttribute("description").contains("DEBUG");
  if(Debug) System.out.println("EnforceEarnedValueUsageModel advisor has been triggered.");
  
  Object data = operation.getOperationData(); 
  if (!(data instanceof ISaveParameter)) return;
  
  ISaveParameter saveParameter = (ISaveParameter) data;  
  IAuditable auditable = saveParameter.getNewState();
  if(!(auditable instanceof IWorkItem)) return;

  IAuditableCommon iac = saveParameter.getSaveOperationParameter().getAuditableCommon();
  IWorkItem workItem = (IWorkItem) auditable;
  
  //If there is no parent work item, we don't need to worry about any further validating. We can just exit.
  List<IReference> ParentReferenceList;
  if(saveParameter.getNewReferences().hasReferences(WorkItemEndPoints.PARENT_WORK_ITEM)) {
   ParentReferenceList = (ArrayList<IReference>) saveParameter.getNewReferences().getReferences(WorkItemEndPoints.PARENT_WORK_ITEM);
  } else {
   if(Debug) System.out.println("There is no parent work item. No rules will be verified.");
   return;
  }  
  
  //We're only interested in validating a few types of work items: Task, Task with Approval, Sub Task, Plan Item, Change Request
  String WI_TypeID = workItem.getWorkItemType();
  if(Debug) System.out.println("The work item type is: " + WI_TypeID);
  if(!WI_TypeID.equals("omr.309.mat.workitem.workItemType.plan_item") && !WI_TypeID.equals("omr.309.mat.workItemType.sub_task") && !WI_TypeID.equals("task") && !WI_TypeID.equals("omr.309.mat.workItemType.task_with_approval") && !WI_TypeID.equals("omr.309.mat.workItemType.change_request")) {
   if(Debug) System.out.println("No rules are verified for this work item type.");
   return;
  }
  
  //Let's figure out what this work item's parent is.
  IReference ParentRef = ParentReferenceList.get(0);
  IWorkItem ParentWI = iac.resolveAuditable((IWorkItemHandle)ParentRef.resolve(),IWorkItem.FULL_PROFILE, null);
  String ParentTypeID = ParentWI.getWorkItemType();
  
  //Verify that plan items (Change Request, and Plan Item) are not children of execution items
  if(WI_TypeID.equals("omr.309.mat.workitem.workItemType.plan_item") || WI_TypeID.equals("omr.309.mat.workItemType.change_request")) {
   if(!ParentTypeID.equals("omr.309.mat.workitem.workItemType.plan_item") && !ParentTypeID.equals("omr.309.mat.workItemType.change_request")) {
    IAdvisorInfo createProblemInfo = collector.createProblemInfo("Plan Items Must Be Children of Other Plan Items", "The work item you are trying to save is a type of \"plan item\", but the parent of this work item is an \"execution item\". Plan items should only be children of other plan items to ensure complexity roll-up functions correctly.", "error");
    collector.addInfo(createProblemInfo);
    return;
   }
  }
  //Check that the user isn't trying to save a Task as a child of another Task.
  if(WI_TypeID.equals("task") || WI_TypeID.equals("omr.309.mat.workItemType.task_with_approval")) {
   if(ParentTypeID.equals("task") || ParentTypeID.equals("omr.309.mat.workItemType.task_with_approval")) {
    IAdvisorInfo createProblemInfo = collector.createProblemInfo("Tasks Must Not Be Children of Other Tasks", "The earned value usage model, which must be adhered to for the CLM Earned Value report to work correctly, stipulates that Tasks cannot be children of other Tasks. Change the parent work item to a Plan Item and try again.", "error");
    collector.addInfo(createProblemInfo);
    return;
   }
  }
  //Check whether the user is trying to save a Sub Task below another Sub Task.
  if(WI_TypeID.equals("omr.309.mat.workItemType.sub_task") && ParentTypeID.equals("omr.309.mat.workItemType.sub_task")) {
   IAdvisorInfo createProblemInfo = collector.createProblemInfo("Sub Tasks Must Not be Children of Other Sub Tasks", "The earned value usage model, which must be adhered to for the CLM Earned Value report to work correctly, stipulates that Sub Tasks cannot be children of other Sub Tasks. Change the parent work item to a Task and try again.", "error");
   collector.addInfo(createProblemInfo);
   return;
  }
  if(WI_TypeID.equals("omr.309.mat.workItemType.sub_task") && (ParentTypeID.equals("omr.309.mat.workitem.workItemType.plan_item") || ParentTypeID.equals("omr.309.mat.workItemType.change_request"))) {
   IAdvisorInfo createProblemInfo = collector.createProblemInfo("Sub Tasks Must Not be Children of Planning Items", "The earned value usage model, which must be adhered to for the CLM Earned Value report to work correctly, stipulates that Sub Tasks cannot be direct children of Planning work item types. Use a Task work item type instead.", "error");
   collector.addInfo(createProblemInfo);
   return;
  }
 }
}

Ralph Schoon selected this answer as the correct answer

Comments
Ralph Schoon commented Mar 14 '16, 10:55 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER

Thanks for sharing Nate. I am tempted to use this and make it a little bit more configurable to be able to publish it. For now I linked back from my blogs interesting links page.

One other answer



permanent link
Ralph Schoon (60.9k33643) | answered Mar 14 '16, 9:39 a.m.
FORUM ADMINISTRATOR / FORUM MODERATOR / JAZZ DEVELOPER
You will have to create operational behavior (advisors) that check on work item save, if the rules are kept. There are potential issues with such a construct as well. E.g. you can change the type of a work item. This change can make links that where perfectly fine before illegal.

Start here to find out about extending RTC: https://rsjazz.wordpress.com/2015/09/30/learning-to-fly-getting-started-with-the-rtc-java-apis/

Your answer


Register or to post your answer.