Wednesday 19 December 2012

Build Status Notification Lamp - TFS2010


Web Mail Notifier Sillyness


We have a dedicated build wall which is pretty efficient in displaying the build information. It really is!

BUT, ever since I moved my desk away from the big screen TV's that display the build notifications, it makes it difficult to tell what's the status of the builds at our morning stand-up.

This was until a couple of days ago a friend got me hooked on to the "USB Web Mail Notifier" available here. (Although, I bought mine off some random dude on EBay (from the UK).

All I really needed was to know if our Nightly Builds that run our Unit and Integrations Tests failed.

Now I know that there are heaps of other ways to get this information but the one I went with appealed to my inner nerd :)

By using a simple powershell script I am able to query our Team Foundation Server (TFS-2010) to see if the latest Nightly Build has been successful.

The powershell script and the binaries required to use the USB light are available here at http://tiny.cc/BuildNotification.

You need to customise the powershell script by entering your details in the  "Set user variables" section of the script:



This is what it looks like.

When developers have been naughty (and not run integration tests locally before checking in) ...



But after you fix it, all is good ..



Thursday 6 December 2012

Find Overlapping Date Ranges



I recently had to implement a "DateRange" validator to check for any overlaps in the date ranges.

Here is my approach to it :

I started with a custom DateRange class.
 
public class DateRange
{
    public int SortOrder { get; set; }
    public DateTime Start { get; set; }
    public DateTime End { get; set; }

    public DateRange() {}

    public DateRange(DateTime sTime, DateTime eTime)
    {
        Start = sTime;
        End = eTime;
    }
} 

Then I call the "HasOverlap" method on my validator to check for overlaps.
 
/*
* LOGIC:
* 
* 1. Take a List of date ranges. Example:
            [Tuple A]         --------         [Sort Order 1]
            [Tuple B]--------                  [Sort Order 2]
            [Tuple C]     --------             [Sort Order 3]
            [Tuple D]     --------             [Sort Order 4]
            [Tuple E]             --------     [Sort Order 5]
            [Tuple F]     ----------           [Sort Order 6]
         
* 2. Now sort the range by start + End Dates. This results in:
            [Tuple B]--------                  [Sort Order 1]
            [Tuple C]     --------             [Sort Order 2]
            [Tuple D]     --------             [Sort Order 3]
            [Tuple F]     ----------           [Sort Order 4]
            [Tuple A]         --------         [Sort Order 5]
            [Tuple E]             --------     [Sort Order 6]    
         
* 3. The Logic is that there will be an overlap IF EVEN ONE of 
*    the 2 base conditions are met:
*      (a) After sorting the list, a given tuple (TUPLE X) 
*          will be deemed overlapping 
*              if the END-DATE of (TUPLE X) is GREATER THAN the START-DATE 
*              of ANY tuple WHERE the sort order is GREATER THAN that of (TUPLE X)
*          
*      --- OR ---
*      
*      (b) After sorting the list, a given tuple (TUPLE X) 
*          will be deemed overlapping 
*              if the START-DATE and END-DATE of (TUPLE X) MATCHES 
*              the START-DATE and END-DATE of ANY tuple 
*              WHERE the sort order is GREATER THAN that of (TUPLE X)
*/
private bool HasOverlap(IList<DateRange> ranges)
{
    // 1. Sort Dates based on Start & End Dates
    var sortedRange = ranges
                        .OrderBy(p => p.Start)
                        .ThenBy(p => p.End)
                        .ToList();

    var sortCounter = 0;
    sortedRange.ForEach(e =>
    {
        e.SortOrder = sortCounter;
        sortCounter++;
    });


    // 2. Check if the end dates are > any start dates except the same one 
    return sortedRange
        .Any(tuple => (from innerLoop in sortedRange
                        where (
                                tuple.End > innerLoop.Start &&
                                innerLoop.SortOrder > tuple.SortOrder
                                ) ||
                                (
                                tuple.End == innerLoop.End &&
                                tuple.Start == innerLoop.Start &&
                                innerLoop.SortOrder > tuple.SortOrder
                                )
                        select innerLoop).Any());
}

Additionally I also pass my DateRanges through a sanity check to ensure that the start < end dates.