TFS, Team Build and a Build Confirmation 0

We recently wanted to add a manual verification to our TFS builds. We didn’t want someone accidentally clicking the build to production when they meant to build to development. They are right next to one another and look very similar.

I didn’t want to spend a lot of time on it, so I came up with this. It’ll work for now and ensure we manually interact with the queue build dialog.

<Target Name="BeforeEndToEndIteration" Condition="'$(C***)' != 'suck'" >
    <Error Text=
"You did not state your feelings for the C***. Please state this by submitting
 the parameter /p:C***='suck' in the queue build dialog."/>
</Target>

The parameter name realy isn’t “C***”, but I didn’t want to offend any followers of the team with the longest championship drought of any professional sports team. Actually, I bet it is safe to extend that to individual performers too.

Update on Beyond Compare inside Team Build and why I’m starting to hate TFS 7

In the past few days, and nights, I’ve learned a few things. Most are bummers, but there is light at the end of the tunnel. This is what I feel our build process was like for the past few days, but I think we’re doing much better now and things are actually working. (Cross your fingers)

I’ve tried a few approaches yesterday and here is what I’ve found.

Deploying via Ftp

Initially, I tried to deploy to our servers via FTP. This appears to work well, but the timestamps are all adjusted by the GMT offset. In our case, the files end up on the server looking like they were edited 6 hours in the future. This makes every single file appear different on the next sync since none of the time stamps match. Apparently this is by design from Microsoft. What a bummer. Running the development server on GMT will cause the timestamps in the database on that server to also be off. This option is out.

Deploying via file share

Again, this appears to work well. The first time everything goes. We change a single file and the log sees that only one file has changed, but doesn’t move it. Doh! They come out of TFS as read-only, and copying to a file share will carry over those file attributes. No problem.  

attrib -r \\myServer\myShare\myApp\*.*

Nope! You can’t run attrib on a network share. It has to be a physical disk.

OK. Well I’ll just attrib -r the source files in the build’s working directory. Great! That worked. Let’s try it again. Doh!

Unable to perform the get operation because it is writable.

Miedo

You’re kidding me! Grr…OK! Fine! I’ll attrib +r after I push. Nope! Not every file in the source directory is suppose to be read only and some of them cannot be read only. AHHH!

Oh yes! Beyond Compare has an attrib -r command in the scripting reference.

ATTRIB
Usage: attrib (+|-) [(+|-) <...>]

Sets (+) or clears (-) the DOS file attributes in the current selection. An attribute set can include archive (a), system (s), hidden (h), and read only (r) attributes. Windows only implementation: Linux version will not recognize ATTRIB.

Sound great right?….that doesn’t work. Even on simple unit test this doesn’t work. I’m at my wit’s end now. There is one more thing to try. There is one more command in the Beyond Compare script reference that might be able to help.

OPTION
Usage:
option stop-on-error
option confirm:(prompt|yes-to-all|no-to-all)

Adjusts script processing options.
· stop-on-error makes the script watch for various error conditions, including file operation errors, and, when one occurs, prompts the user before continuing.
· confirm can use prompt, yes-to-all, or no-to-all to handle confirmation dialogs that occur due to file operations. By default, prompt is used.

Let’s hope this works. I’ll put it right before the sync, cross our fingers and run it through some tests.

It WORKS! Or it appears to so far. Hopefully.

The files on the server still carry the read only flag. That’s not ideal for us, but it will have to do for now.

TFS, Team Build, and Beyond Compare as a lighter XCopy 5

We’re using TFS 2008 and Team Build to compile and build a website mixed with ASP.Net and classic ASP. It works fine, but the only problem is the site is huge. It’s over over 2500 files and over 400 megs. That’s HUGE! We could XCopy that to our server, but pushing 400 megs every time feels like a little bit of overkill, especially when the majority of the changes are copy updates. We could also use a content management system for this, but we thought we would give try it with TFS.

First, it took forever to pull 400 megs out of source control every time we did a build. We can fix that.

<PropertyGroup>
    <IncrementalGet>true</IncrementalGet>
<PropertyGroup>

Done. Now the build will only pull down the files that changed. It’ll leave the files from previous build laying around on the server, but that’s OK.

Next, it takes forever to copy the 400 megs to the drop folder. We don’t even need to do it in the first place since we are going to xcopy the _PublishedWebsites contents elsewhere when we’re done. We can fix this problem with ease too.

<PropertyGroup>
    <SkipDropBuild>true</SkipDropBuild>
<PropertyGroup>

Now we won’t copy the build to the drop server.

So finally the XCopy. That was a little more tricky. We need to figure out only the files that change and transfer them, via FTP in out case. Luckily, Beyond Compare not only has a scripting interface that will let us work it into the build script, it also has the example script of how to do exactly what we want to do in the documentation. Win for us!

We can just tweak it a bit and we’re off to the races. Let’s make a script file called deploy.to.server.script and put it in the same folder as the TFSBuild.proj.

# %1 is source of the build to copy to the new server
# %2 is the outdir where the log should be written

#log the script actions
log verbose "%2\deployment.log.txt"

#set the comparison criteria
criteria timestamp size

#load source and target
# you could also use a UNC share
load "%1" "ftp://user:password@oursite.com"

# Move everything
filter "*.*"

#Sync the local files to the web site, creating empty folders
sync create-empty mirror:lt->rt

Next, invoke it in the build script.

<Exec
 Command="&quot;c:\Program Files\Beyond Compare 3\bcompare.exe"
 &quot;@$(MSBuildProjectDirectory)\deploy.to.server.script&quot;
&quot;$(SolutionRoot)\MyWebsite" &quot;$(OutDir)&quot;  \silent \closescript" >

We’re done. It’ll only copy the stuff we’ve changed and we’ve taken our build time from 25 minutes down to less than one.

Update: If you want to keep an eye on what you’re moving, add the following steps in the Beyond Compare script.

#load source and target
# you could also use a UNC share
load "%1" "ftp://user:password@oursite.com"

expand all
folder-report &
    layout:side-by-side &
    options:display-mismatches &
    title:"Deployment Report" &
    output-to:"%2\deployment.summary.html" &
    output-options:html-color

Sorry about the funny syntax highlighting. There is not “BeyondCompare” language available.

You’ll get a nice HTML report.
ss-20090129092919

Another Update: It looks like Beyond Compare will not tell you if an error occurs during the script. This is a huge bummer. If you get something like this in your script, it’ll still return 0 for the ExitCode and you won’t know it failed.

1/29/2009 11:40:42 AM  Fatal Scripting Error: Unable to load base folder
1/29/2009 11:40:42 AM  Script completed in 0.01 seconds

Yet another update: There is some new news on using Beyond Compare with Team Build.

One more update: Here is a copy of the edit to the TFSBuild.proj file. This gets added at the end of the file before the closing <Project> tag.

 	<PropertyGroup>
		<IncrementalGet>true</IncrementalGet>
	</PropertyGroup>

	<!-- Since we are doing the source side by side we deploy before
		copying to the the builds folder. We might consider changing this
		to AfterDropBuild and copy from there if we are doing the precompiled
		websites -->
	<Target Name="BeforeDropBuild">
		<CallTarget Targets="Deploy"/>
	</Target>

	<Target Name="Deploy">
		<!-- Create a Custom Build Step -->
		<BuildStep
			TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
			BuildUri="$(BuildUri)"
			Name="BeyondCompareDeployStep"
			Message="Deploying to webserver">
			<Output
				TaskParameter="Id"
				PropertyName="BeyondCompareDeployStepID" />
		</BuildStep>

		<!-- We are deploying the source side by side with the pages instead of
			doing the precompiled website-->
		<Exec Command="&quot;c:\Program Files\Beyond Compare 3\bcompare.exe&quot; &quot;@$(MSBuildProjectDirectory)\deploy.to.server.script" &quot;$(SolutionRoot)\source&quot;  &quot;\\myWebserver\path\to\mysite&quot;  &quot;$(DropLocation)\$(BuildNumber)&quot;  \silent \closescript" >
			<Output
				TaskParameter="ExitCode"
				PropertyName="BeyondCompareExitCode" />
		</Exec>

		<!-- These tests don't work as BeyondCompare will ALWAYS exit with code 0 from script -->
		<BuildStep
			Condition="'$(BeyondCompareExitCode)' == '0'"
			TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
			BuildUri="$(BuildUri)"
			Id="$(BeyondCompareDeployStepID)"
			Status="Succeeded"/>
		<BuildStep
			Condition="'$(BeyondCompareExitCode)' != '0'"
			TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
			BuildUri="$(BuildUri)"
			Id="$(BeyondCompareDeployStepID)"
			Status="Failed"/>
		<Error
			Condition="'$(BeyondCompareExitCode)'!='0'"
			Text="Deployment Failed" />
	</Target>

The olny other file is the deploy.to.server.script file. This file sits aside the TFSBuild.proj file and looks like this.

# %1 is the solution root of the build
# %2 is the target location (ftp or share) to deploy
# %3 is the outdir where the log should be written

#log the script
log verbose "%3\deployment.log.txt"

#set the comparison criteria
criteria timestamp size

#load source and target
load "%1"  "%2"

expand all
folder-report &
    layout:side-by-side &
    options:display-mismatches &
    title:"Deployment Report" &
    output-to:"%3\deployment.summary.html" &
    output-options:html-color

filter "*.*"

# we want to override all the read-only files that exist
option confirm:yes-to-all

#Sync the local files to the web site, creating empty folders
sync create-empty mirror:lt->rt

Getting Started with Selenium 0

The past few days have been spent getting Selenium setup and running as part of our CI builds. We only have a few proof-of-concept tests right now, but the power and potential is apparent. We have no automated unit testing right now and very little code in our code behinds so functional testing is as good as we’re going to get. Also, with the amount of AJAX that is currently in our pages, and the additional amount we see in them in the near future, Selenium’s method of control the browser helps us make sure our pages do and continue to behave like we expect.

Getting setup with Selenium was incredibly simple. The Selenium IDE Firefox plugin makes creating your first Selenium test a snap. Download it and install it and you’re off. I’m not going to walk you through creating the tests, because the Selenium web site has a pretty decent movie that’ll take care of you.

The output of the test recorder are HTML files that contain the instructions, aka “Selenese”, to re-execute the tests through both the IDE and Selenium core. Selenese is very simple by design. While we could run the Selenese tests through the core in our Continuous Integration server, I’ve decided to use the IDE to export the C# source for the tests I create. This allows my to put the Selenium test into an NUnit test harness, refactor some of the common setup and config, and also run the tests via Selenium Remote Control(RC). I know the refactoring goes against the Selenese simplicity, but I want to run my tests locally and with different credentials without changing every test. Also, running in RC lets me run the tests without having to watch the pages in the browser fly by and, someone day, concurrently run all the browsers I care about.

Here’s an example of what one of those tests might look like 

using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using NUnit.Framework;
using Selenium;

namespace SeleniumTests{

   [TestFixture] public class NewTest {
	private ISelenium selenium;
	private StringBuilder verificationErrors;

	[SetUp] public void SetupTest() {
		selenium = new DefaultSelenium("localhost", 4444, "*chrome", "http://www.google.com/");
		selenium.Start();
		verificationErrors = new StringBuilder();
	}

	[TearDown] public void TeardownTest() {
		try {
			selenium.Stop();
		} catch (Exception) {
			// Ignore errors if unable to close the browser
		}
		Assert.AreEqual("", verificationErrors.ToString());
	}

	[Test] public void TheNewTest() {
		selenium.Open("/");
		selenium.Type("q", "fooberry");
		selenium.Click("btnG");
		selenium.WaitForPageToLoad("30000");
	      Assert.IsTrue(selenium.IsElementPresent("css=a[href=\"http://www.fooberry.com/\"]"));
	}
   }
}

Getting this to run in the Team Build is as easy as getting the regular NUnit tests running. First we would want to parameterize those tests a bit so we can pass different hosts, ports and credentials (if present). That’s not too hard and should be obvious.

We’re trying multiple CI builds. One build just compiles and runs the unit test code, which is currently this single test….baby steps.

[TestFixture] public class TheMostAwesomestUnitTestInTheWorld {
    [Test] public void ValidateOurCoreBeliefs() {
        Assert.That(true, Is.True);
    }
}

The other build compiles and runs both the unit tests and integration tests. We suspect this build will take a while and the sooner we could get feedback about the quality of the build, the better. We could push this build to a separate build agent too, but for right now they are all just backing up in the same queue.

The only missing piece of the puzzle so far is the Remote Control Server. The RC Server is a Java application that has to run on a machine with access to which ever browser you plan to test. Starting the server is simple enough. Just make sure Firefox.exe is in the path. If you forget, you’ll get a nice warning about it.

java -jar selenium-server.jar

It’s up an running and when you run the above unit test, you see the browser window fly by and the server log all the actions it’s performing on the browser.

Great! …if you want to stay logged into your server with the console open, but I didn’t. Luckily, creating a Windows service is pretty easy. There is a great tutorial out there that walks you through how to setup a similar Java application as a service. Just substitute the Selenium RC Server for the FitNesse server. Note that when I tried to install the Windows Server 2003 Resource Kit, on both Vista and Windows Server 2008, I got a compatibility warning. I ignored the warning since I was only using the two files and it worked great.

Now you can start and stop the Selenium RC Server via a Windows service, keep it running when you log out and start automatically when the server starts up.

Have fun.

Incentivizing Programmers 0

In most factories, especially those that pride themselves on their safety records, you’ll find a sign that says something like “600 days since our last lost time incident”. We should have the same for our automated build qualities, although I doubt they will ever reach 600 days of consecutive green builds. It would hopefully generate a sense of pride in the build. Imagine if you joined a team that had 60 days of green builds and that number was publicized for the entire organization to see. Wouldn’t you take extra care to make sure you don’t do something that flips it over to red, even for one build?

Gaining momentum behind doing automated build is something our organization is struggling with at the moment. For some reason the value isn’t immediately apparent or the schedules and budgets don’t allow for it at the moment. Both of those are topics for another post. Maybe a component to gaining that momentum is illustrating the elevation and longevity of the quality of the builds. I see two metrics being valuable.

  1. Days of consecutive green builds
  2. Change in the number of unit tests over time

Potentially a third being the number of customer reported defects.

The number of consecutive green builds is important, but if one team is doing nightly builds and another is doing continuous integration, does one team have a significant advantage in quality over another? I would say there is benefit there, but I wouldn’t categorize the advantage as significant. Also, looking at the change in the number of tests provides a better indication of progress than percentage change. Adding a hundred unit tests to a build that already has a thousand is substantially better than adding one unit test to a set of ten. I imagine you’re saying that is still rather subjective because you could have ten quality tests and a thousand horribly simple ones and that’s true, but maybe this isn’t the place to make those determinations. Let’s assume all unit tests are of roughly the same complexity and comprehension.

So here is my question. Would it be valid and beneficial to incentivize teams to improve these metrics or compete against other teams to improve the metrics? In the past we’ve given out $5 gift cards to Starbucks or iTunes when people did good jobs on something, just as a nice “thank you”. Would that work here? Could giving a $5 gift card to the each member of the team that has the longest stretch of green builds or added the most unit tests in the last month help motivate people? Now I don’t expect people to add hundreds unit tests every month to get their free fat free half caf soy carmel white chocolate mocha macchiato (I’m not even sure that drink exists or if would be less than $5 if it did). I’m not saying those are the metrics and the periodicity of the rewards that would work the best, just wondering if the spirit of it would work.

Recent posts by Ayende and Joel Spolsky seem to imply it would fail miserably.

I’m not sure something like $5 will lead teams to work the system just for the reward. Even without the monetary reward the principle behind taking pride in the build quality could established by making an aggregated build report public. Something really public. Maybe a screen when I get off the elevators, or a TV in the lobby that gives some metrics. Let me see who the people are who are writing the most unit test. I’m sure they can answer some of my questions or give me advice. Show me who isn’t building and we can get them the help they need to get it off the ground. There should be something we could do to help.

Automating the Build (Step 1 cont’d) 1

After the disappointing ending to my previous post, I now have much success to report. Once we had the correct path to the MSTest.exe on the build server, I was able to publish the results of my NUnit tests. There are a few things to note.

  1. You still need MSTest.exe on the build server. I guess that is OK since we, at our organization, want to allow for the ability to run MSTests as well. I’m not 100% sure that happens on the build server or the TFS server.
  2. As of now, if the NUnit tests fail, it will not run the MSTest. This is because we are executing the NUnit tests in the AfterCompile target as suggested in the NUnit for Team Build example. I’m not really sure why you would do both in the same solution, but if you do, you won’t see failures from both. Only one at a time. I’m looking into getting both to run, but that isn’t going to be much of a priority since we won’t need to run both in the same solution.

I am really excited that we have this running with such little effort. Thanks has to go to the NUnit for Team Build guys.

One to step two when time allows.

Automating the Build (Step 1) 2

We are starting to automate and standardize our build process. I think the idea that F5 is not a a build strategy is finally surfacing as a real problem. The first step in my mind is to come to some convention on the structure. Doing so would make configuration a lot simpler. We can default the convention and you can overwrite if you feel the need.

Microsoft has some guidance on the subject of how to structure the source when using TFS. I’m not really sure how the choice of source control factors into that decision, but we’ll just go with it. The structure I’m playing with now is very similar to their recommendation.

/Fooberry/
          1.0.0/  <-- the build file goes here
                docs/
                source/
                       application/ <-- the source for the ui
                       application.tests/ <-- the UI tests
                       core/
                       core.tests/
                       ...I'm not settled on how this level
                          will look. It isn't important for
                          now. I'm more concerned with the
                          files needed to build.
                libs/
                    my.company.build/
                    msbuild.community.tasks/
                    nunit/
                    nxslt/
                    nunit4teambuild/
                    n*...all shared libs and tools
               ...maybe some other dirs here eventually
          main/ <-- the trunk copy just like the 1.0.0 tree
/SomeOtherApp/

The main point here is that all the tools we use are inside the source control for every app and every branch of that app. It may seem like a waste of disk space, but what it allows is all configuration information to be relative to the build root. A specific branch can upgrade to a new NUnit and all the other builds don’t need to worry about backwards computability.

A folder that may look a little odd is my.company.build. I would like this folder to hold as much of the automated build extensions as possible. There are going to be a few additional steps that we need to add to the out of the box TFSBuild.proj. The plan is to put all the new targets in a my.company.build.targets file along with any custom tasks that we need to build. Once we have that, we can stick the following line into the TFSBuild.proj and we snap on all our custom steps.

<Import Project="$(SolutionRoot)\libs\my.company\my.company.build.targets"/>

Getting the import setup was a little bit of pain. Running locally, $(SolutionRoot) doesn’t map to the correct path. The path to the targets file was mapping someplace crazy. This has a really bad smell, but I was overjoyed that it worked remotely, so I didn’t care too much for now. It’s only day one. We will need to build locally eventually. That’s on the TODO list already.

I have a bit of a confession. I wish that was the manner in which I started this process, but I didn’t realize that we could externalize the build steps to my.company.build until after I started filling out the steps. This is is how, in my opinion, frameworks are most successfully built. We extract the code that could be made common instead of head out to write something that will solve everyone’s problem, even though you don’t know what their problem might be.

So to start on the first build step; running NUnit tests. After a quick Google search,
Nunit4TeamBuild on CodePlex outlined the steps we needed to take.

  1. Run Nunit-console and produce an XML log file
  2. Convert the Nunit XML output to an MSTest test results file (with a .trx extension)
  3. Use MSTest /publish to push merge the trx file with an existing build

Sounds pretty straight forward. There are a few more dependancies. It uses the MSBuild Community Tasks and nxslt2 (There is a new nxslt3 which uses .Net 3.5…not sure what that gains us though).

The documentation for Nunit4TeamBuild recommends adding an AfterCompile target to execute the NUnit tests. We can put this in our my.company.build.targets file. There are just a few housekeeping items first. The example proj file has hard coded paths to the MSBuild Commnuity Tasks, NUnit and NXslt. To make those relative, assign the….

<PropertyGroup>
   <MSBuildCommunityTasksPath>$(SolutionRoot)\libs\community.msbuild.tasks\</MSBuildCommunityTasksPath>
   <NUnitPath>$(SolutionRoot)\libs\nunit\</NUnitPath>
</PropertyGroup>

<Import Project="$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.Targets"/>

When we go to invoke the NUnit task, we need to be sure and give the ToolPath of $(NUnitPath).

<NUnit ContinueOnError   = "true'
        Assemblies       = "@(TestAssemblies)"
        OutputXmlFile    = "$(OutDir)nunit_results.xml"
        ToolPath         = "$(NUnitPath)">
   <Output TaskParameter = "ExitCode"
           PropertyName  = "NUnitResult" />
 </NUnit>

*Note: I’m playing with the formatting of the XML. I’m trying out this style for now.

So that takes care of the NUnit and the MSBuild Community Tasks. The next tool that needs a relative path is NXslt. The example project shows invoking the command line executable via the Exec task.

<Exec Command="C:\path\to\nxslt\nxslt2.exe &quot;$(OutDir)nunit_results.xml&quot; &quot;$(SolutionRoot)\nunit transform.xslt&quot; -o &quot;$(OutDir)nunit_results.trx&quot;"/>

While that works, NXslt comes bundled with an MSBuild task that can replace it with something more elegant. To use the task, add the Using

 <UsingTask AssemblyFile = "$(NXsltTaskAssembly)"
            TaskName     = "Nxslt" />

And replace that Exec with the following:

<Nxslt In    = "$(OutDir)nunit_results.xml"
         Style = "$(SolutionRoot)\libs\nunit4teambuild\nunit transform.xslt"
         Out   = "$(OutDir)nunit_results.trx" />

One more to go. MSTest.exe is invoked to publish the newly formatted results. This one might be more difficult to keep relative. Right now, this is pointing (or trying to point) to the MSTest.exe under Program Files. With all that said, I’m unable to find where MSTest is on the build server. Having no access to it makes it a little difficult. Unfortunately I cannot guarantee that the final step will actually work. I hope to have more news to report next week.