Saturday, June 14, 2008

Work Item Customization tidbits: state transitions (part 3 of X)

In the previous posts I talked about field definitions. Now it is time to handle work item status (state) definitions, and how the transitions between different states are defined.

The simplest definition of work item with single state will look as following:

<WORKFLOW>
    <STATES>
        <STATE value="Active"></STATE>
    </STATES>
    <TRANSITIONS>
        <TRANSITION from="" to="Active">
            <REASONS>
                <DEFAULTREASON value="New" />
                <REASON value="Duplicate" />
            </REASONS>
        </TRANSITION>
    </TRANSITIONS>
</WORKFLOW>

The definition consists of two parts – list of states available for work item, and list of transitions between states. In the example above, there is only one state defined, and there is single transition from “” to “Active” (where “” means no state and is applicable only to newly created work items). Another thing to note is the list of reasons defined for every transition. The reason field becomes enabled when user selects to state; then the list becomes relevant with DEFAULTREASON selected.

This simple example amply demonstrates how one can specify list of states available, transitions between them and reasons for the transition performed.

While that simple definition can get one by, how about more complicated scenarios – for example, making fields read-only depending on work item state, or setting default values upon transition? As it is, it can be solved by adding FIELDS section to STATE, TRANSITION or REASON elements.

The state-related FIELDS section is similar to FIELDS section describing the fields available in the work item (as we discussed earlier). However, since all fields were specified previously in WORKFLOW we only need to reference fields and provide desired behaviors. For example let’s look at some TRANSITION definitions from Bug WI template:

<TRANSITION from="Closed" to="Active">
 <REASONS>
  <DEFAULTREASON value="Regression" />
  <REASON value="Reactivated" />
 </REASONS>
 <FIELDS>
  <FIELD refname="Microsoft.VSTS.Common.ActivatedBy">
   <COPY from="currentuser" />
   <VALIDUSER />
   <REQUIRED />
  </FIELD>
  <FIELD refname="Microsoft.VSTS.Common.ActivatedDate">
   <SERVERDEFAULT from="clock" />
  </FIELD>
  <FIELD refname="System.AssignedTo">
   <COPY from="field" 
        field="Microsoft.VSTS.Common.ResolvedBy" />
   </FIELD>
 </FIELDS>
</TRANSITION>

We already understand the intent behind the REASONS section - it specifies that bug can be moved from “Closed” to “Active” either because of regression or as it is reactivated. Without concentrating too much on syntax details, the FIELDS section can be easily read: for Activated By field we want to make sure that it is set by default to the user who performed the transition, the field is mandatory and must be set to valid TFS user name. Activated Date field should be set to the time of the transition (since SERVERDEFAULT is performed when WI is saved), and Assigned To field should default to the value of Resolved By field (or in other words, to the person who resolved and closed the issue).

In a similar manner, FIELDS section may be specified for states or reasons (for example, you may want to make sure that certain field is mandatory only in specific state, or that setting specific reason in transition requires additional information [and thus makes certain fields mandatory]).

To round off the topic of WI states, let us talk about the security. The typical requirement for the task tracking system is limiting the users to certain actions. We have previously discussed how the FIELDS logic can be limited based on user groups; can the state transitions be limited in the similar fashion?

Indeed, we can specify optional for and not attributes in TRANSITION element, allowing (and/or denying) access to certain group to certain states. For example, the following snippet allows reopening of the bug only to testers (and explicitly disallows developers)

<TRANSITION from="Closed" to="Active" 
            for="[Project]\Testers" 
            not="[Project]\Developers">
    …
</TRANSITION>

As denial takes precedence, any tester who is also developer will not be able to move bug to “Active” state.

With this post we have rounded off (admittedly in very simplistic manner) most of the “behind-the-scene” logic of Work Item definition. Next I will discuss how the elements are exposed in User Interface using FORM section.

Related posts:
- Work Item Customization: conditional field behavior (part 2)
- Work Item Customization: fields definition (part 1)

2 comments:

msolcia said...

Hi,

with the transation keyword, may I restrict the possibility to insert a new bug for a certain group of users?
In our process we would like to avoid that any user except the test team can insert work item of type "bug".
I think that authorizations are not so granular so I'm thinking about another ways. Thanks for your opinion.

eugenez said...

There are couple of somewhat hacky ways (summed up nicely in the following post http://weblogs.asp.net/tspascoal/archive/2006/12/31/team-foundation-server-restricting-work-item-creation-based-on-a-role.aspx)