Developer Smackdown Musing #24 | TFS Team Build 2010#

In this version of The Smackdown, Clark and Mark introduce Team Foundation Server’s Team Build 2010.

Listen Here –> Play Now

Show Notes

We still have some Developer Smackdown stickers left.  If your interested in one send us a SASE.  See the following for more information: http://bit.ly/9XFaF7.

Great Sites:

Tips and Tricks

Debugger Step Through Attribute

When applied, this will tell the debugger to actually skip over even when you are trying to step into.

Get more information here: http://msdn.microsoft.com/en-us/library/system.diagnostics.debuggerstepthroughattribute.aspx

Visual Studio Tip of the Day Extension

This is a Visual Studio extension to have Visual Studio Tips and Tricks delivered right to your Start Page in Visual Studio. 

Get more information here: http://bit.ly/9iRJGJ

Thursday, May 13, 2010 3:12:57 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Blogging again????#

You know sometimes it’s just sad how fast time can go by.  Looking back it’s been well over a year maybe two since I last blogged.  WOW, that’s not cool.  So what the hell happened, well LIFE I guess.  Let’s see:

question-mark1a.jpg

  • I had my second child ( girl, Addison ).  We are blessed to have one of each and both healthy. 
  • I got to meet Bill Gates, Steve Ballmer and all of the rest of the Microsoft executives
  • Bought a Honda ( needed a 4 door with 2 kids )
  • This fiscal year I will have billed over 2300 hours which doesn’t account for my other job.  Can you say Year of the Death March!!!
  • Ran into Sieg from the Deadliest Catch at SeaTac
  • Learned how to make the perfect Margarita!

Regardless a lot has happened and it’s time to talk technology again.  I love it and really miss doing it. With all of the great stuff here upon us now, it’s time to start sharing. I was reading MSDN Magazine the other day when I ran across an article about MSBuild and best practices which really got me thinking.  There were two items that really stuck out for me:

  1. Compilation of large source trees.  I think it’s a must read but caution readers that “large” can mean many different things. 
  2. Reference Management

While both were explained pretty well, lets put #2 into practice.  *I’M LAZY* ( in a good way of course ). I would much rather write something once rather than screw with it time and time again, especially the stuff you have to do like build work. 

So lets talk assembly references….

Assembly references can be easy as you want it to be but sometimes a little prep work will go a long way. The .NET compilers and runtime both have a specific order in which they look for references.  If you look in your framework folder for Microsoft.Common.Targets you will find the following:

The SearchPaths property is set to find assemblies in the following order:  legos

  1. Files from current project - indicated by {CandidateAssemblyFiles}
  2. $(ReferencePath) - the reference path property, which comes from the .USER file.
  3. The hintpath from the referenced item itself, indicated by {HintPathFromItem}. 
  4. The directory of MSBuild's "target" runtime from GetFrameworkPath.  The "target" runtime folder is the folder of the runtime that MSBuild is a part of.
  5. Registered assembly folders, indicated by {Registry:*,*,*}
  6. Legacy registered assembly folders, indicated by {AssemblyFolders}
  7. Look in the application's output folder (like bin\debug)
  8. Resolve to the GAC.
  9. Treat the reference's Include as if it were a real file name.

So what if your not one of those nine?!?!?

Since it’s all just angle brackets we can extend the “out of the box” search paths.  As it was explained in the article you can override the property AssemblySearchPaths.  Aaron had a great post on MSBuild Property Evaluation, it’s something you should read.  Overriding a property is as simple as importing your own target file into the stack and then resetting the property ( for most cases ).  You could also just add a the same property further down the stack in the same file.  Both are essentially the same. With MSBuild the *stack is always important*.  If you were to import your target file or override a property to early you might change the way the entire build system works.  There are a number of properties that work like:

This is a very common practice throughout MSBuild implementations.  As you can tell it’s just a way or protecting yourself from a change in behavior upstream. Remember MSBuild parses top down to you have no influence what might be done afterwards.  In our case what we want to do is import our targets file after the Microsoft.Common.Targets file in the csproj or vbproj file(s).

*NEW*

By doing so AssemblySearchPaths will be “” and initialize itself as expected.  So if we want to add to it it’s as simple as ( snip from MyTargets.Targets ):

....
   

     
          $(AssemblySearchPaths);
          C:\binaries\;
     

   
....

  1. Define a Property Group
  2. Define the Property ( AssemblySearchPaths )
  3. Set it to itself and add to itself

Important point, Reference Paths are folders not files.  So now if you compile from the cmd line or from VS you will have your paths in the stack. The easiest way to see what is going in is to simply run msbuild.exe /t:rebuild /v:diag on your sln file.  That will dump everything that took place during the execution from MSBuild. Even the order of folders it searched for.  You will actually be able to see the reference pats listed that it couldn't find.

But we are not done yet.  We have a hardcoded path and remember, I’m lazy. How about we bootstrap ourselves into the build process and read the file system building the search paths based on a “root” folder you specify?  Then any machine should work without any change.



    
        $(SolutionDir)..\MyBinaries\**\*.*
    

    
   
    
      
    
    
    

  
      
        $(AssemblySearchPaths);
        @(binariesFound->'%(RootDir)%(Directory)');        
      
    
  

Important points:

  1. InitialTargets was set. This gives us the ability to run *first*.  Why? Well we want to read the file system and build the list of folders.
  2. We create an item during the execution of the target rather than statically.
  3. We later transform that target just adding the folder rather than the whole file path.

Team Build has a similar concept but much easier.  At the bottom of any tfsbuild.proj fiile there is a commented collection called AdditionalReferencePath. It works the same it’s just that the Team Build process does it all for you already.

Friday, May 22, 2009 8:56:03 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Build Status TFS Policy, Part II#

Since my post yesterday I just decided to update the code and also include Buck's comments.  I even added a simple installer as a bonus since that last post was just useless.  Here is the new version and this time in a zip ;)

Microsoft.Services.TfsPolicies-installer.zip (159.25 KB)

Microsoft.Services.TfsPolicies-source.zip (37.17 KB)
Friday, October 27, 2006 12:56:05 PM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Stop, the build is broken!!#

It's late, your tired and yet somehow you got stuck fixing the build because junior engineer bob just fired off a check-in and took off.  It looks like the build is now broken because junior hasn't done a get latest in a month.  In the meantime 10 other people check-in and just end up compounding the problem.

Unfortunately things like this happen.  One day I just got so frustrated, I just wrote a custom TFS check-in policy which gets the last build status and validates a particular build type was actually passing before you check-in.  I started with Jeff Atwood and James Manning posts where they have done a great job explaining how to write a simple custom check-in policies.

Let's Code!!

There are two things you have to do for any check-in policy, define the policy and configure it.  This sample isn't much different than the code comment examples. 

First lets look at the policy definition. The real work is in the Evaluate method.  This is where we call TFS and find out what state the build is in. This sample could further be updated and remove the requirement to configure the TfsServer.  You can actually get that info from the workspace IPendingCheckin supplied in Initialize() (_pendingCheckin.PendingChanges.Workspace).  From the Workspace object, it’s workspace.VersionControlServer.TeamFoundationServer.

using System;
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.TeamFoundation.VersionControl.Client;

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Build.Proxy;
using System.Text;

namespace Microsoft.Services.TfsPolicies
{
    [Serializable]
    public class BuildStatusPolicy : PolicyBase
    {
        string _tfsServer = @"http://TFSServer:8080";
        string _tfsProject = "TfsProject";
        string _buildType = "BuildType";

        [NonSerialized]
        protected bool _disposed = false;
        [NonSerialized]
        protected IPendingCheckin _pendingCheckin;

        //public virtual event PolicyStateChangedHandler PolicyStateChanged;

        #region IPolicyDefinition

        public override string Description
        {
            get { return Strings.PolicyDescription; }
        }

        // This string is a description of the type of our policy.  It will be displayed to the
        // user when they select our policy type in the list of policies installed on the system
        // as mentioned above.
        public override string TypeDescription
        {
            get { return Strings.PolicyTypeDescriptions; }
        }

        // This string is the type of our policy.  It will be displayed to the user in a list
        // of all installed policy types when they are creating a new policy.
        public override string Type
        {
            get { return Strings.PolicyType; }
        }

        // This is a string that is stored with the policy definition on the source
        // control server.  If a user does not have our policy plugin installed, this string
        // will be displayed.  We can use this as an opportunity to explain to the user
        // how they might go about installing our policy plugin.
        public override string InstallationInstructions
        {
            get { return Strings.PolicyInstallInstructions; }
        }

        public override bool CanEdit
        {
            //TODO maybe check the role of the user trying to change?
            get { return true; }
        }

        #endregion //IPolicyDefinition

        #region IPolicyDefinition

        public override void Initialize(IPendingCheckin pendingCheckin)
        {
            if (_pendingCheckin != null)
            {
                throw new InvalidOperationException("Policy already initialized.");
            }

            if (_disposed)
            {
                throw new ObjectDisposedException(null);
            }

            _pendingCheckin = pendingCheckin;

            pendingCheckin.PendingChanges.CheckedPendingChangesChanged += new EventHandler(pendingCheckin_CheckedPendingChangesChanged);
        }

        // This method is invoked by the policy framework when the user creates a new checkin
        // policy or edits an existing checkin policy.  We can use this as an opportunity to
        // display UI specific to this policy type allowing the user to change the parameters
        // of the policy.
        public override bool Edit(IPolicyEditArgs policyEditArgs)
        {
            if (_pendingCheckin != null)
            {
                throw new ApplicationException("The policy can't be edited after it has been initialized for evaluation.");
            }

            using (BuildStatusPolicyConfiguration buildStatusPolicyConfiguration = new BuildStatusPolicyConfiguration(_tfsServer, _tfsProject, _buildType))
            {
                DialogResult formResult = buildStatusPolicyConfiguration.ShowDialog(policyEditArgs.Parent);

                if (formResult == DialogResult.OK)
                {
                    _buildType = buildStatusPolicyConfiguration.TfsBuildType;
                    _tfsProject = buildStatusPolicyConfiguration.TfsProject;
                    _tfsServer = buildStatusPolicyConfiguration.TfsServer;

                    return true;
                }
                return false;
            }
        }

        public override PolicyFailure[] Evaluate()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(null);
            }
            
            TeamFoundationServer teamFoundationServer = TeamFoundationServerFactory.GetServer(_tfsServer);
            BuildStore buildStore = teamFoundationServer.GetService(typeof(BuildStore)) as BuildStore;

            BuildData[] buildData = buildStore.GetListOfBuilds(_tfsProject, _buildType);

            BuildData lastBuild = this.getLastBuild(buildData);

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("Builds Returned: {0} \n", buildData.Length.ToString());
            sb.AppendFormat("Build Status: {0} \n", lastBuild.BuildStatus);
            sb.AppendFormat("Build Status ID: {0} \n", lastBuild.BuildStatusId);
            sb.AppendFormat("Finish Time: {0} \n", lastBuild.FinishTime);
            sb.AppendFormat("Build Number: {0} \n", lastBuild.BuildNumber);

            EventLog.WriteEntry("Microsoft.Services.TfsPolicies", sb.ToString());

            if (lastBuild.BuildStatus.Equals("Failed", StringComparison.OrdinalIgnoreCase))
            {
                return new PolicyFailure[] { new PolicyFailure(string.Format(Strings.PolicyPrompt, _buildType), this) };
            }
            else
            {
                return new PolicyFailure[0];
            }
        }

        // This method is called if the user double-clicks on a policy failure in the UI.
        // We can handle this as we please, potentially prompting the user to perform
        // some activity that would eliminate the policy failure.
        public override void Activate(PolicyFailure failure)
        {
            MessageBox.Show(string.Format(Strings.PolicyPrompt, _buildType), "How to fix your policy failure");
        }

        // This method is called if the user presses F1 when a policy failure is active in the UI.
        // We can handle this as we please, displaying help in whatever format is appropriate.
        // For this example, we'll just pop up a dialog.
        public override void DisplayHelp(PolicyFailure failure)
        {
            MessageBox.Show(string.Format(Strings.PolicyDisplayHelp, _buildType), "Prompt Policy Help");
        }

        #endregion IPolicyDefinition

        private void pendingCheckin_CheckedPendingChangesChanged(Object sender, EventArgs e)
        {
            if (!_disposed)
            {
                OnPolicyStateChanged(Evaluate());
            }
        }

        private BuildData getLastBuild(BuildData[] builds)
        {
            DateTime lastBuildDateTime = builds[0].FinishTime;

            int position = 0;

            for (int i = 0; i < builds.Length; i++)
            {
                if (builds[i].FinishTime > lastBuildDateTime)
                {
                    lastBuildDateTime = builds[i].FinishTime;
                    position = i;
                }
            }

            return builds[position];
        }
    }
}

 

Now lets configure it.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Microsoft.Services.TfsPolicies
{
    public partial class BuildStatusPolicyConfiguration : Form
    {
        public BuildStatusPolicyConfiguration(string TfsServer, string TfsProject, string TfsBuildType  )
        {
            InitializeComponent();

            txtTfsUrl.Text = TfsServer;
            txtTfsProject.Text = TfsProject;
            txtTfsBuildType.Text = TfsBuildType;

            this.txtTfsBuildType_TextChanged(null, null);
            this.txtTfsProject_TextChanged(null, null);
            this.txtTfsUrl_TextChanged(null, null);
        }

        public string TfsServer
        {
            get { return this.txtTfsUrl.Text; }
        }

        public string TfsProject
        {
            get { return this.txtTfsProject.Text; }
        }

        public string TfsBuildType
        {
            get { return this.txtTfsBuildType.Text; }
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.OK;
            Close();
        }

        private void txtTfsUrl_TextChanged(object sender, EventArgs e)
        {
            btnOK.Enabled = txtTfsUrl.Text != string.Empty;
        }

        private void txtTfsProject_TextChanged(object sender, EventArgs e)
        {
            btnOK.Enabled = txtTfsProject.Text != string.Empty;
        }

        private void txtTfsBuildType_TextChanged(object sender, EventArgs e)
        {
            btnOK.Enabled = txtTfsBuildType.Text != string.Empty;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            Close();
        }
    }
}

Lastly I dropped the strings into their own struct.

using System;
using System.Collections.Generic;
using System.Text;

namespace Microsoft.Services.TfsPolicies
{
    internal struct Strings
    {
        internal const string PolicyDescription = "Stop users from checking in when the configured BuildType is in a 'Failed' status.";
        internal const string PolicyTypeDescriptions = "This policy will prompt the user to decide whether or not they should be allowed to check in based on the build status.";
        internal const string PolicyType = "Check for passing build";
        internal const string PolicyInstallInstructions = "Please install the package Microsoft.Services.TfsPolicies.Setup.msi.";
        internal const string PolicyPrompt = "Please wait to check-in until the {0} build is passing";
        internal const string PolicyDisplayHelp = "This validates the {0} build status is not in failure";
    }
}

One thing to note, be aware of performance.  This just does the mechanics and is not optimized.  During the course of a check-in this will actually call the web service a number of different times.  On top of that the web service endpoint only returns all build results for a build type rather than just the last one.  So depending on your team size etc. you've now been warned.  Sometimes a performance hit is worth the productivity gained.

Thursday, October 26, 2006 9:26:45 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

Microsoft.SDC.Tasks, New Version Released#

If you are doing anything with .Net 2.0 chances are you have a set of MSBuild files supporting your application.  That means you already know MSBuild just rocks.  What better than MSBuild? MSBuild with a sweet task library to support it of course!  That task library would be the Enterprise Solutions Build Framework or Microsoft.SDC.Tasks as I like to call it.

Well they just released a new version!  The biggest change was the introduction of BizTalk 2006 tasks.  If BizTalk isn't your fancy then you will be pleased to also know there are some new TFS tasks also.

To find out more information visit http://www.gotdotnet.com/codegallery/codegallery.aspx?id=b4d6499f-0020-4771-a305-c156498db75e

These guys do a stellar job!  I have been using this library for about a year now and it goes everywhere I go.

Wednesday, July 12, 2006 8:32:38 AM (Central Daylight Time, UTC-05:00) #    Comments [0]  | 

 

VSTS Jumpstart, things you will end up asking for#
Internet Links
Visual Studio Team System Home
Getting Started with Team Foundation
MSDN Technical Forums
VSTS Downloads
Team System Rocks
How To Links
Visual Studio Team System Install Guide
TFS Warehouse Troubleshooting
Step-By-Step Guide to Converting Web Projects from Visual Studio .NET 2002/2003 to Visual Studio 2005
VSTS Backup and Restore Procedures
Team Foundation Server Permissions
Team Foundation Server Default Groups, Permissions, and Roles
TF.exe Command Line Reference
Books
Working with Microsoft Visual Studio 2005 Team System
Test-Driven Development in Microsoft .NET
Test Driven Development: By Example
Refactoring: Improving the Design of Existing Code
Refactoring to Patterns
Bloggers
Rob Caron
Rick LaPlante
Eric Jarvi
Buck Hodges
Jeff Beehler
Eric Lee
Nagaraju Palla
Khushboo
Gautam
Visual Studio Team System User Education
WebCasts
Introduction to Visual Studio Team System
How and Why Process Guidance Matters in Visual Studio 2005 Team System
Visual Studio 2005 Team System: Enterprise-Class Version Control
Managing Work with Visual Studio 2005 Team System
Test-Driven Development Using Visual Studio Team System
Accessing Visual Studio 2005 Team System Using the Teamprise Plug-In for Eclipse (Level 200)
Best of Launch: Visual Studio 2005 Team System (Level 200)
Load and Web Testing with Microsoft Visual Studio 2005 Team System (Level 200)
Migrating to Microsoft Visual Studio 2005 Team System (Level 200)
Shipping on Time and Under Budget with Visual Studio Team System (Level 200)
3rd Party Products
Teamprise
TeamLook
TeamPlain
VSTSEclipse 
VSTSPlugins
Tips and Tricks
  • When checking an item into source control you have the ability to associate a WI with that change set.  If you choose to do so there are two options, Resolve and Associate.  If you select Resolved the WI state will advance to the next state.
  • Fully process the TFS warehouse
  • Team Explorer blank ( missing server or lost network connection )
    • Delete the cache folder @
      • C:\Documents and Settings\<user>\Application Data\Microsoft\VisualStudio\8.0\Portfolio Explorer
      • C:\Documents and Settings\<user>\Local Settings\Application Data\Microsoft\Team Foundation\1.0
  • Tools to modify WIT
    • WitExport.exe, WitImport.exe, WitFields.exe
    • These are found @ c:\ProgramFiles\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies\
  • Change the TFS warehouse run interval
  • Secure a WIT transistion
    • <TRANSITION from="State 1" to="State 2"
         for="[global]\StateChangers"
         not="[global]\GroupThatsRestrictedStateChanges" >

  • Drivers required to create adhoc Excel reports against the TFS Analysis Services.  Install Microsoft Core XML Services (MSXML) 6.0 and Microsoft SQL Server 2005 Analysis Services 9.0 OLE DB Provider from the SQL Server 2005 Feature Pack

MSBuild & Team Build

Jomo Fisher on MSBuild

Robert McLaws MSBuild Compatibility Toolkit 1.0

Nagaraju Palla's Building binaries targeting .NET 1.1 and .NET 1.0 in TeamBuild

Khushboo's CI using Team Foundation Build 

 
.NET SDC Solution Build & Deployment Process & Tools
Downloads
Visual Studio 2005 Web Application Projects, ScottGu On Web Application Projects
Visual Studio 2005 Web Deployment Projects
SQL Server 2005 Feature Pack
Tools

FiddlerPopUp Forum Post

Test Driven .Net

BizUnit

.Net | MSBuild | TeamBuild | VSTS
Wednesday, February 08, 2006 11:32:17 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

VS 2002 / 2003 / 2005 Conversions and Building#
Friday, January 20, 2006 6:37:36 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Multiple Test Runs in one BuildType#

If you are using TeamBuild then this post is for you. 

In TeamExplorer when you create a new build type it will create a *.proj file.  During the creation of this build type, you will be asked which TestLists you would like executed in that build type.  Once completed if you open that proj file, you will see an item group that looks something like the following:

<ItemGroup>
  <MetaDataFile Include="$(SolutionRoot)\TestProject1\TestProject1.vsmdi">
    <TestList>TestList1;TestList2</TestList>
  </MetaDataFile>
</ItemGroup>

For this build type there are actually 2 different TestLists, TestList1 and TestList2.  These TestLists will get executed and reported on in the build.  With the out of box ItemGroup configuration both lists will actually roll up into one set of test results; but what if you wanted to to actually have multiple test runs for a given build. 

We can make a very slight modification to that generated code block and actually get a separate test run per test list.

<PropertyGroup>
  <VsmdiPath>$(SolutionRoot)\TestProject1\TestProject1.vsmdi</VsmdiPath>
</PropertyGroup>

<ItemGroup>
  <MetaDataFile Include="$(VsmdiPath)">
    <TestList>TestList1</TestList>
  </MetaDataFile>

  <MetaDataFile Include="$(VsmdiPath)">
    <TestList>TestList2</TestList>
  </MetaDataFile>
</ItemGroup>

More to come....

Tuesday, January 17, 2006 11:50:43 PM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

All content © 2010, Clark Sell
On this page
This site
Calendar
<September 2010>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
Archives
Sitemap
Blogroll OPML
Disclaimer

Powered by: newtelligence dasBlog 2.3.9074.18820

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Send mail to the author(s) E-mail

Theme design by Jelle Druyts


Pick a theme: