Archive for January, 2009

Resetting Team Build IncrementalGet Builds 0

After tinkering around with file attributes in our build’s working folder, I needed wipe the entire working directory and start with a fresh set of source. Just deleting the working directory isn’t good enough if you’re using incremental gets.

The build must store the most recent changeset it’s built and only get changesets that are greater than its current. If you try and just delete the working directory and build you’ll get the following error.

error MSB3202: The project file "…whatever.sln" was not found.

To tell the build not to do an incremental build on this one single build in the queue, add the following property to the Queue Build window.

image

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 around UAC 4

So I never used Vista, except for the 30 minutes between un-boxing my PC and upgrading to Windows XP, until my new position. It’s pretty and glossy, but I am starting to understand the UAC headache. So here is one way I’m working around the frustration.

Pretend you want to edit a file that needs elevated rights. Usually you won’t realize it until you’ve opened it, attempted to save it, and found it doesn’t allow you to so.  Then you open Notepad, browse to the file and then make the change.

I found this helpful article about how to customize the Send To menu in Vista. I followed that and added Notepad to that folder twice. One was a regular shortcut, but I renamed the other to “Notepad as Administrator”.

image

Then right click the Notepad as Administrator, click Properties, click Advanced, and then check Run as administrator.

image

Click OK out of all the dialogs. Now when you right click a file you have a few extra options.

image

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.

Rebasing Javascript via a MasterPage 1

I’ve been looking for a way to rebase the URL for the javascript we include in our master pages. We add a lot of javascript in the master pages such as the following.

    <link href="../css/ui-theme.css" rel="stylesheet" type="text/css" />
    <script language="javascript" type="text/javascript" src="../js/jquery-1.3.js" />

The problem is, as everyone probably knows, the relative path to the file is from the master page, not from the client page. For some reason, ASP.Net is kind enough to rebase the link tag’s href property, but not the javascript link.

After asking the Google, I saw a lot of examples to solve the problem like by using the ResolveClientUrl as follows:

    <script language="javascript" type="text/javascript"
        src='<%= ResolveClientUrl("~/js/jquery-1.3.js") %>' />
    <!-- or -->
    <script language="javascript" type="text/javascript"
        src='<%# ResolveClientUrl("~/js/jquery-1.3.js") %>' />

However, I saw no one suggest this, which I believe to be a little cleaner.

    <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
        <Scripts>
            <asp:ScriptReference Path="~/js/jquery-1.3.js" />
        </Scripts>
    </asp:ScriptManager>

Granted, this brings in some ASP.Net Ajax that may ugly things up, but it works for our own javascript files.

Firebug is great, but… 4

Firebug is the single most important piece of software I use when developing the layout of a web UI. For the longest time at my previous employer, installing Firebug and Firefox would also, after the evening big brother scan, install a nice e-mail in your inbox from the compliance nazis about your recent contraband software installation, and strongly suggest you rethink your decision. Recently however, they have seen the light and no longer send out that nasty little e-mail. But on to my only gripe about Firebug.

Let’s take this simple page and bring up Firebug.

Firebug.Original

Now, we can click into the style we want to change and use the up and down arrow keys to modify the numeric value. This is an awesome feature to position elements with paddings and margins. Imagine doing this with several elements via their class’s associated style and seeing the effect on the entire page. Pretty awesome!

Firebug.Modified

We can switch over to the CSS view and see our change.

Firebug.CssView

Great! Now let’s find a ways to pull out all those changes so we can paste them back into our real CSS file.
Firebug.CssWithoutChanges

Where are my changes? I realize it might not be able to recreate that CSS file from my changes because of elements Firebug couldn’t handle, but how can I get all my changes out at once? Even if I am viewing a local file, like I am in this case, there appears to be no way to export my modifications form Firebug in one bulk export.

jQuery Selectors and ASP.Net Controls 19

As I’ve already mentioned, this is the bane of jQuery within an ASP.Net application. Selecting the control based on its ID becomes difficult with ASP.net Controls and even worse with naming containers. There have been a few methods I’ve used to find the ASP.Net control in the dom.

Injecting the ClientID

$(“#<%= fooTextBox.ClientID %>”)

This is my least favorite, but the most precise. There are no additional elements or attributes to add and you’re guaranteed to get the exact control you’re after. Another bad side effect is the javascript has to be inside the ASPX page. That’s not ideal either, although you could argue that having a small script that just has variables for the control names isn’t that bad.

var fooTextBoxClientID = “<%= fooTextBox.ClientID %>”;

Still icky.

Add Custom Attribute

You could add a custom ID in the markup of the control.

<asp:TextBox runat=”server” id=”fooTextBox” myID=”foo” />

Then select on that custom ID.

$(“input[myID=’foo’]”)

This seems to make the code less DRY, but it works well.

Find With Ending

Since the name you give you .Net control is only prepended with its naming garbage, you can still find your names using the ends with selector.

$(“input[ID$=’fooTextBox’]")

This works well when the controls are assured to appear only once of the form; however, when inside a repeating control such as a ListView or a reusable control, this method falls apart.

Find With Class

I probably use this method more than any other since most of the time I have a parent frame of reference which limits the scope enough that makes my class name unique. That scope limiter also helps with the other methods, but using class names has worked the best for me.

$(“.inputTextBox")

Be careful not to use the CSS class like you would ID and create a CSS class for every element.

Wrap in HTML Elements

Also, you can wrap the control in an HTML element that will provide you full control over its ID.

<span id=”fooText”><asp:TextBox runat=”server” ID=”FooTextBox” /> </span>

Then select it using the child / ancestor selector.

$(“#fooText > input”)

You’re adding unneeded markup here, but you might already have it and just need to add the ID attribute, or select it using the class name.

I hope this helps with some headaches surrounding ASP.Net and jQuery.

Update: Since then, I’ve been using the following method more and more. The only change I’ve made is I’ve started to prefix my control name with the “_” to make sure I’m not picking up any control names that might carry similar ending names.

Like…

$(“input[ID$=’_PhoneTextBox’]")

and…

$(“input[ID$=’_CellPhoneTextBox’]")

Without the “_” both would match the following.

$(“input[ID$=’PhoneTextBox’]")

jQuery and UpdatePanels 6

While using a jQuery plugin to round corners, they started to disappear inside UpdatePanel’s after a partial post back. I found someone else on StackOverflow had the same problem. Luckily, the solution was right there as well.

$(document).ready(function() {
    doReady();

    var prm = Sys.WebForms.PageRequestManager.getInstance();
    prm.add_endRequest(function(s, e) {
        doReady();
    });
});

function doReady() {
    $('.roundedCorners').corners();
}

I’m interested in trying the livequery jQuery plugin, but will go with this for now.

jQuery and Event Delegation Example 0

I wanted to give some examples that actually run. The last post might have been a little abstract and brief.

First, don’t forget to link in the jQuery script.

<script src="jquery-1.2.6.js" type="text/javascript" charset="utf-8"></script>

Some CSS to pretty things up.

	.myContainer{
		width:300px;
		font-family:Arial;
	}

	.fooberry{
		margin:5px;
	}
	.summary{
		background-color:blue;
		color:white;
		padding:3px;
	}

	.details{
		background-color:green;
		color:white;
	}

	.toolbar-details{
		cursor: pointer;
	}

Some HTML to manipulate.

<div class="myContainer">
	<div class="fooberry">
		<div class="summary">
			<div class="summary-text">
				Just a little information.
			</div>
			<div class="toolbar">
				<span class="toolbar-details">details</span> |
				<span>date: 1/3/2009</span>
			</div>
		</div>
		<div class="details">
			More information....
		</div>
	</div>

	<div class="fooberry">
		<div class="summary">
			<div class="summary-text">
				Different information.
			</div>
			<div class="toolbar">
				<span class="toolbar-details">details</span> |
				<span>date: 1/4/2009</span>
			</div>
		</div>
		<div class="details">
			More information....
		</div>
	</div>

</div>

Finally the jQuery.

<script>
	$(document).ready(function(){
		$(".fooberry").click(function(e){
			if($(e.target).is(".toolbar-details")){
				$(this).find(".details").slideToggle(500);
			}
		});
	});
</script>

This layout could probably be adjusted so the problems I mentioned in the previous post aren’t a problem, but let’s just look at the event delegation.

The div with the class “fooberry” contain the physical layout for the items of our list. We use jQuery to attach a click event handler to each “fooberry” div and then use jQuery again to examine the arguments of the event, and yet again to find the div we want to toggle.

I am sure it is possible to attach the event to the “myContainer” div. We would need some additional jQuery since the following line would find all “details” divs.

$(this).find(".details").slideToggle(500);

This happens because the “this” in this statement will now be the “myContainer” div. We could probably write a query to find the parent of the “e.target” who’s class is “fooberry”, and then use that element in place of “this” in the previous statement. This would reduce the overhead of the redundant event handlers, and work with all additional “fooberry” divs added via Ajax.

I hope this is useful for you as it is for me.

Here is the entire HTML.

	<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
	   "http://www.w3.org/TR/html4/strict.dtd">

	<html lang="en">
	<head>

		<script src="jquery-1.2.6.js" type="text/javascript" charset="utf-8"></script>

		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<style>
			.myContainer{
				width:300px;
				font-family:Arial;
			}

			.fooberry{
				margin:5px;
			}
			.summary{
				background-color:#373999;
				color:white;
				padding:3px;
			}

			.details{
				background-color:#689980;
				color:white;
			}

			.toolbar-details{
				cursor: pointer;
			}
		</style>

		<script>
			$(document).ready(function(){

				$(".fooberry").click(function(e){
					if($(e.target).is(".toolbar-details")){
						$(this).find(".details").slideToggle(500);
					}
				});
			});
		</script>

	</head>
	<body>

		<div class="myContainer">
			<div class="fooberry">
				<div class="summary">
					<div class="summary-text">
						Just a little information.
					</div>
					<div class="toolbar">
						<span class="toolbar-details">details</span> |
						<span>date: 1/3/2009</span>
					</div>
				</div>
				<div class="details">
					More information....
				</div>
			</div>

			<div class="fooberry">
				<div class="summary">
					<div class="summary-text">
						Different information.
					</div>
					<div class="toolbar">
						<span class="toolbar-details">details</span> |
						<span>date: 1/4/2009</span>
					</div>
				</div>
				<div class="details">
					More information....
				</div>
			</div>

		</div>

	</body>
	</html>

Next Page »