2D Head with a clock as an eyeball.
 Friday, March 14, 2008

Hey y'all, long time no see. Life has thrown me a few curve balls which impeded my blogability, but rather than boring you with details lets just get into straight into it.

Recently I've had a few queries regarding a check in policy I eluded to in this post. Today I hope to clarify how one might go about implementing a check in policy which ensures that Option Strict is turned on for VB projects.

Rather than rehashing a perfectly good walk through, I suggest you read this article from MSDN to get the basics of Check In Policy creation.

Once we have our check in policy project and have derived a class from Microsoft.TeamFoundation.VersionControl.Client.PolicyBase it is time to start overriding the behaviour of the base rule.

Imports Microsoft.TeamFoundation.VersionControl.Client

<Serializable()> _
Public Class OptionStrictPolicy
    Inherits PolicyBase

Once we are over that little hurdle we want to:

* Get the set of pending changes that have been selected by the user to check in

* For each pending change determine the project file that the change belongs to

* For each VB project determine if Option Strict has been turned on

* For each project that hasn't got option strict turned on, create a policy warning.

For extra fun I'll do this all with VS2008 & VB9. I love my C# but to be honest VB9 kicks its ass when dealing with XML.

1: Get the set of pending changes that have been selected by the user to check in

Everything from here on out extends the Evaluate method of PolicyBase. Getting the set pending changes selected by the user is a cinch. I've filtered by vb code files, but you could just as easily go for more file types.

Public Overrides Function Evaluate() As PolicyFailure()

  Dim pendingChanges = PendingCheckin.PendingChanges.CheckedPendingChanges
  Dim vbCodeFiles = _
    From c In pendingChanges _
    Let extension = Path.GetExtension(c.FileName) _
    Where extension = _VBFileExtension OrElse extension = _VBProjectFileExtension _
    Select c.LocalOrServerFolder, c.FileName

2: For each pending change determine the project file that the change belongs to

This step is a little trickier and basically involves drilling up the folder structure until we find a project file, and then checking the project file for a compilation reference to the pending change. This seems like a good place to refactor into a recursive function...

*SIDE NOTE* Am thinking of starting a petition to all relevant Dictionary makers to make the word "Refactor" a real word. Whose with me?

I'm sure we are all capable of looking for .vbproj files recursively up the folder chain. However we do need to allow for the possibility that there may be two vbproj files in a folder and if so, is our pending change referenced by either of them? To do this I need to go through the project file looking for <Compile> tags that include my pending change. For example in C# we might do it like this

var doc = XDocument.Load(XmlReader.Create(projectFilename));
var compileItems = from e in doc.Descendants()
    where e.Name.LocalName == "Compile"
    select e;
    
    return (from c in compileItems
      where c.Attribute("Include") != null && c.Attribute("Include").Value.Contains(filename)
      select c).Any();

But since Im using VB today I can do it like this...

Dim doc = XDocument.Load(XmlReader.Create(projectFilename))
Return doc...<Compile>.@Include.Contains(filename)

Not bad...but for this to work I do need to import the namespace of the project file schema, since the syntax that allows for <Compile> is checking qualified names, not local names.

Imports <xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

3: For each VB project determine if Option Strict has been turned on

Once I have a list of projects that are loosely associated with a check in, I can easily check for the existence of OptionStrict tags in the vbproj file. OptionStrict still defaults to off, so a lack of OptionStrict tags implies the setting is OFF. However it is perfectly valid to have an OptionStrict tag that is set to OFF so I need to account for those.

Private Shared Function IsOptionStrictOn(ByVal project As XDocument) As Boolean
    Return project...<OptionStrict>.Value = "On"
End Function

 

4. For each project that hasn't got option strict turned on, create a policy warning.

Creating policy warnings is a breeze and you can return as many as you want, in this scenario I want to ensure that one is created for each project that is in violation of my rule. The final Evaluate function looks like this...

Public Overrides Function Evaluate() As Microsoft.TeamFoundation.VersionControl.Client.PolicyFailure()
  Dim pendingChanges = PendingCheckin.PendingChanges.CheckedPendingChanges

  Dim vbCodeFiles = From c In pendingChanges _
    Let extension = Path.GetExtension(c.FileName) _
    Where extension = _VBFileExtension OrElse extension = _VBProjectFileExtension _
    Select c.LocalOrServerFolder, c.FileName

  Dim vbProjects = From c In vbCodeFiles _
    Select GetProjectFile(c.LocalOrServerFolder, c.FileName)

  Dim strictOffprojects = From p In vbProjects _
    Where Not IsOptionStrictOn(p)

  Dim policyFailures = New List(Of PolicyFailure)
  Dim messageFormat = "Please turn option strict on in the project file: {0}"

  For Each s In strictOffprojects.Distinct
    policyFailures.Add(New PolicyFailure(String.Format(CultureInfo.InvariantCulture, messageFormat, s), Me))
  Next

  Return policyFailures.ToArray()
End Function

 

So there you have it, VB9 to make coding an Option Strict ON policy nice and easy. Seems appropriate doesn't it?


Filed under:  |  |  |  | 
© Copyright 2008 Jim Burger