How to enforce a rule on Area/Iteration Path
Tuesday, February 17th, 2009Another pitfall I encountered while setting up our new team project was how to make sure people didn’t cop out and leave them at the default (root, aka useless) value. With Areas I may have been able to set up some weird non-inheriting permission scheme, but I needed to solve this problem for Iterations anyway, so I turned to the web.
Unfortunately, the standard answer from the product team didn’t work for me.
<FIELD type="Integer" name="AreaID" refname="System.AreaId"> <HELPTEXT>AreaID</HELPTEXT> </FIELD> <FIELD type="Integer" name="IterationID" refname="System.IterationId"> <HELPTEXT>IterationID</HELPTEXT> </FIELD> <FIELD type="String" name="Product Area - Validation" refname="Coatue.ProductAreaValidation"> <HELPTEXT>Hidden field used to validate Product Area</HELPTEXT> <WHEN field="System.AreaId" value="84"> <COPY from="value" value="Restricted" /> </WHEN> <PROHIBITEDVALUES> <LISTITEM value="Restricted" /> </PROHIBITEDVALUES> </FIELD> <FIELD type="String" name="Sprint or Release - Validation" refname="Coatue.SprintPathValidation"> <HELPTEXT>Hidden field used to validate Sprint or Release</HELPTEXT> <WHEN field="System.IterationId" value="84"> <COPY from="value" value="Restricted" /> </WHEN> <PROHIBITEDVALUES> <LISTITEM value="Restricted" /> </PROHIBITEDVALUES> </FIELD>
It successfully blocked work items that had Area/Iteration paths I didn’t want, but I’d continue to get validation errors after I changed the paths in the form to something else.
At this point I started to wonder whether the AreaId and AreaPath fields were as intricately tied as I thought they were. After all, I didn’t have any rules saying to update one when the other changed. (The documentation kinda implies this but doesn’t spell out the mechanism.) So I decided to test at the object model level: Get-TfsServer OM wrapper to the rescue!
PS C:\Users\rberg> $tfs = get-tfsserver njtfs –all
PS C:\Users\rberg> $bug = $tfs.wit.GetWorkItem(1333)
PS C:\Users\rberg> $bug.AreaId; $bug.IterationId
84
84
PS C:\workspaces\ws1> $bug.AreaPath; $bug.IterationPath
Test-ConchangoV2\test
Test-ConchangoV2\Release 1\Sprint 4
PS C:\Users\rberg> $bug.fields | where { $_.name.contains("Validation") } | select value
Value
-----
Restricted Restricted
PS C:\Users\rberg> $bug.AreaId = 104; $bug.IterationId = 91
PS C:\workspaces\ws1> $bug.AreaPath; $bug.IterationPath
Test-ConchangoV2\test
Test-ConchangoV2\Release 1\Sprint 4
PS C:\Users\rberg> $bug.fields | where { $_.name.contains("Validation") } | select value
Value
-----
Restricted
Restricted
Nope, not a synchronization issue between path on the form <–> underlying ID. Looks like I really do need to tweak Gregg’s advice. All you need is a corresponding WHENNOT rule to cancel out each WHEN rule as it’s no longer needed. Here’s what the hidden validator for Area looks like now:
<FIELD type="String" name="Product Area - Validation" refname="Coatue.ProductAreaValidation"> <HELPTEXT>Hidden field used to validate Product Area</HELPTEXT> <WHEN field="System.AreaId" value="84"> <COPY from="value" value="Restricted" /> </WHEN> <WHENNOT field="System.AreaId" value="84"> <COPY from="value" value="Ok" /> </WHENNOT> <PROHIBITEDVALUES> <LISTITEM value="Restricted" /> </PROHIBITEDVALUES> </FIELD>
Make the same change for Iteration and you’re golden.