No Free Time

Because my therapist says I need to let things out

Archive for the ‘infrastructure’ Category

The right way to install SQL Server 2005

without comments

When you install SQL 2005 DO NOT choose to start the SQL Server and SQL Agent services. If these are running when you install the service pack you will have to reboot (or manually shut them down yourself – save yourself the bother).

SQL Server 2005 Service Pack 2 is cumulative – meaning you do not have to install SP1.

Written by tad

April 8th, 2008 at 2:33 am

Posted in infrastructure

MSTest still doesn’t assert array equality properly

with one comment

I ran into this issue today where asserting equality on two arrays always fails, even if the arrays really are equal:

Assert.Equals(new string[] {“value”}, new string[] {“value”}); // always fails

Evidently for arrays the Assert.Equals() method tests object identity, rather object equality, which is what you would expect. There is an Assert.AreSame() method which should test object identity, shouldn’t it?

I found this post from 2005 which notes the problem – I can’t believe they haven’t fixed it by now!

Written by tad

April 5th, 2008 at 9:49 pm

Posted in infrastructure

Tagged with ,

Vista SP 1 File Copy

without comments

Well, it’s the first thing I tried. And it’s much, much better. The truth is, I don’t actually care how accurate the estimates are, as long as I see SOMETHING happening.

Written by tad

March 26th, 2008 at 5:03 am

Posted in infrastructure

Tagged with

Change TFS Build Agent Build Location

with one comment

When you create a TFS 2008 build, there are three build locations you need to be aware of.

First is the location that the build agent ‘gets’ the source to for compilation. You can specify this when creating the Build Agent – just set the Working directory to the location you want the source to be downloaded to. Normally this will be set to the windows temp folder for the account the build service is running under.

The second location is where the build is compiled. This is defined within the Build Definition as the Workspace for the build. TFS copies the source files from the ‘working directory’ to the ‘workspace’ before compilation. It is compiled into a new sub-folder with the same name as the build definition.

Thirdly, you have the option of specifying a build drop location. Your compiled build will be copied here into a new sub-folder, datestamped and versioned by the build number. I haven’t worked out yet how to instruct the build script to deploy a compiled website to a static location. Would love to know if anyone can shed any light!

Written by tad

March 13th, 2008 at 2:49 am

Build Helpers

without comments

I’ve made a couple of build helper files which may come in handy. They cover compilation, testing and deployment, and hopefully can be reused between projects with minimal need to be rewritten. I’ll share the compilation one today.

Compilation Build Scripts

As background my folder structure looks like this:

/Solution/ClassLibrary1
/Solution/ClassLibrary2
/Solution/Website1
/Solution/Resources
/Solution/Build
/Solution/Build/bin
/Solution/Build/src
/Solution/Build/testlib
/Solution/Build/deploy

Resources is where everything like NAnt, MBUnit, log4net, NCover etc all reside. Various things happen within the Build folder: src is where all projects are copied into before being compiled, bin is where each compiled assembly is placed for easy reference for other assemblies (e.g: where ClassLibrary2 depends on ClassLibrary1), testlib is where all test assemblies are compiled and run, and deploy is where our final compilation will end up.

The reason each assembly is copied into the src folder prior to compilation is so that we can do tricky things like substituting *.config and AssemblyInfo.cs files, as you’ll see below.

The build file starts this way:

    1 <?xml version="1.0"?>
    2 <!--EXTERNAL_PROPERTIES: output.dir;AssemblyName;debug;assembly.label-->
    3 <project name="general compilation">
    4   <target name="clean" >
    5     <delete dir="${output.dir}"/>
    6   </target>
    7
    8   <target name="init" depends="clean" >
    9     <mkdir dir="${output.dir}" />
   10     <mkdir dir="${output.dir}/bin" />
   11   </target>

Straight forward. Note that the ${output.dir}, ${AssemblyName}, ${debug} and ${assembly.label} properties are expected to be set – these will be set from your calling build file. ${output.dir} can simply be “c:pathSolutionBuild”. ${AssemblyName} is just the name of the assembly you want to compile at that time.

Assembly compilation:

   13 <target name="general.compile.assembly" description="compiles a satellite assembly">
   14     <echo message="*******************************" />
   15     <echo message="***COMPILING ${AssemblyName}" />
   16     <echo message="***TO ${AssemblyOutputFolder}" />
   17     <echo message="*******************************" />
   18
   19     <delete dir="${output.dir}src${AssemblyName}" />
   20
   21     <copy todir="${output.dir}src" flatten="false">
   22       <fileset>
   23         <include name="${AssemblyName}***.*" />
   24         <exclude name="${AssemblyName}bin" />
   25         <exclude name="${AssemblyName}config" />
   26         <exclude name="${AssemblyName}**AssemblyInfo.cs" />
   27       </fileset>
   28     </copy>
   29
   30     <call target="general.labelassembly" />
   31
   32     <csc target="library" output="${output.dir}bin${AssemblyName}.dll" debug="${debug}">
   33     <sources>
   34       <include name="${output.dir}src${AssemblyName}/**/*.cs" />
   35     </sources>
   36     <references refid="assembly.resources" />
   37     </csc>
   38     <copy file="${output.dir}bin${AssemblyName}.dll" tofile="${AssemblyOutputFolder}${AssemblyName}.dll" />
   39   </target>

As the description says, this target compiles a satellite assembly, or class library. It first deletes the src folder (/Solution/Build/src/AssemblyName) before copying the latest source into it. Then it calls the “general.labelassembly” target, which we’ll see shortly. Finally it compiles all .cs files into a dll.

Note line 36, where the references tag uses assembly.resources. This is because you should call the target like this:

    5     <!-- Class Library 1 -->
    6     <property name="AssemblyName" value="ClassLibrary1" />
    7     <assemblyfileset id="assembly.resources">
    8       <include name="${resources.dir}/log4net.dll" />
    9     </assemblyfileset>
   10     <call target="general.compile.assembly" />

This way you only specify exactly what you need to in order to build the assembly.

Now, websites. First we need to prepare a few things:

   41 <target name="prepare.web" >
   42     <mkdir dir="${output.dir}src${website.name}" />
   43     <echo message="*******************************" />
   44     <echo message="***COMPILING ${website.name}" />
   45     <echo message="*******************************" />
   46
   47     <copy todir="${output.dir}src" flatten="false">
   48       <fileset>
   49         <include name="${website.name}***.*" />
   50         <exclude name="${website.name}config" /> <!-- this are where we put environment-specific config files -->
   51         <exclude name="${website.name}bin*.*" />
   52         <exclude name="${website.name}web.config" />
   53       </fileset>
   54     </copy>
   55     <copy todir="${output.dir}src${website.name}bin" flatten="true">
   56       <fileset>
   57         <include name="${output.dir}bin*.*" />
   58       </fileset>
   59     </copy>
   60     <copy todir="${output.dir}src${website.name}bin" flatten="true">
   61       <fileset refid="website.resources" />
   62     </copy>
   63   </target>

Then we can compile the site itself. Note that we don’t copy the web.config over with the website. This is because I have a seperate target to copy a config file, replacing environment specific variables as it copies. I’ll come to that in a bit.

The next target is straightforward – compile the website to the /Build/Deploy/WebsiteName folder.

   65 <target name="general.compile.website" description="compiles a website" depends="prepare.web">
   66     <mkdir dir="${output.dir}Deploy${website.name}" />
   67     <exec program="aspnet_compiler.exe"
   68         basedir="C:WINDOWSMicrosoft.NETFrameworkv2.0.50727"
   69         workingdir="${output.dir}"
   70         commandline="-u -v /${website.name} -p ${output.dir}src${website.name} ${output.dir}Deploy${website.name}"  />
   71   </target>

Here’s a target used to copy a config file.

   73 <target name="general.compile.website.copyconfig" description="Copies an XML file to the website's web.config, replacing tokens as specific in fileset">
   74     <copy file="${template.sourcefilename}" tofile="${output.dir}Deploy${website.name}web.config">
   75       <filterchain refid="config.settings" />
   76     </copy>
   77   </target>

And finally the target to label the assembly.

   79   <target name="general.labelassembly">
   80     <asminfo output="${output.dir}src${AssemblyName}AssemblyInfo.cs" language="CSharp">
   81       <imports>
   82         <import namespace="System.EnterpriseServices" />
   83         <import namespace="System.Reflection" />
   84         <import namespace="System.Runtime.CompilerServices" />
   85       </imports>
   86       <attributes>
   87         <attribute type="AssemblyVersionAttribute" value=""${assembly.label}"" asis="true" />
   88         <attribute type="AssemblyTitleAttribute" value=""Canon Create"" asis="true" />
   89         <attribute type="AssemblyDescriptionAttribute" value=""assembly for Canon Create"" asis="true" />
   90         <attribute type="AssemblyCopyrightAttribute" value=""Copyright (c) 2008"" asis="true" />
   91         <attribute type="ApplicationNameAttribute" value=""${AssemblyName}"" asis="true" />
   92       </attributes>
   93       <references>
   94         <include name="log4net.dll" />
   95       </references>
   96     </asminfo>
   97   </target>

Using the build scripts

You can invoke the website compiler like so:

   13 <!-- build the frontendwebsite website -->
   14     <property name="website.name" value="FrontEndWebsite" />
   15
   16     <assemblyfileset id="website.resources">
   17       <include name="${resources.dir}/DynamicPDF.Generator.Server.dll" />
   18       <include name="${resources.dir}/DynamicPDF.Merger.Server.dll" />
   19       <include name="${resources.dir}/NetSpell.SpellChecker.dll" />
   20       <include name="${resources.dir}/FreeTextBox.dll" />
   21       <include name="${resources.dir}/log4net.dll" />
   22     </assemblyfileset>
   23     <!-- compile the site -->
   24     <call target="general.compile.website" />

And to copy config settings:

   26     <!-- copy the frontendwebsite web.config with replacing tokens -->
   27     <filterchain id="config.settings">
   28       <replacetokens>
   29         <token key="token.defaultConnectionString" value="server=engelbart;database=CANON_CREATE_V6;uid=sa;pwd="/>
   30         <token key="token.smtpserver" value="10.111.1.55" />
   31         <token key="token.baseSiteUrl" value="http://localhost:4870" />
   32         <token key="token.XHTMLTemplateUploadPath" value="C:Inetpubvirtual2005ProjectsCanonCanonCreate2005FrontEndWebsitexhtmltemplateuploads" />
   33         <token key="token.ConfigurationFilesDirectory" value="C:Inetpubvirtual2005ProjectsCanonCanonCreate2005ConfigurationFiles" />
   34       </replacetokens>
   35     </filterchain>
   36
   37     <!-- copy the frontendwebsite.config.template.xml file to /frontendwebsite/web.config with tokens replaced -->
   38     <property name="template.sourcefilename" value="template.config.FrontEndWebsite.xml" />
   39     <call target="general.compile.website.copyconfig" />

Here’s how I’m labelling my build. Generally I just want to use the CCNetLabel variable passed through from CCNet, but for added flexibility The target expects the ${assembly.label} variable. I simply check for CCNetLabel and copy it to the new variable.

   68 <!-- label the assembly -->
   69     <ifnot propertyexists="CCNetLabel">
   70       <fail message="CCNetLabel property not set, so can't create labelled distribution files" />
   71     </ifnot>
   72     <trycatch>
   73       <try>
   74         <echo message="build number ${CCNetLabel}" />
   75         <property name="assembly.label" value="${CCNetLabel}" />
   76       </try>
   77       <catch>
   78         <property name="assembly.label" value="1.0.0.1" />
   79       </catch>
   80     </trycatch>

Written by tad

February 26th, 2008 at 8:08 am

Small NAnt Gotcha

without comments

Say I have two XML build files. The first is intended to call a target in the second.

Example1.xml:

.cf { font-family: Courier New; font-size: 8pt; color: black; background: white; } .cl { margin: 0px; } .cln { color: #2b91af; } .cb1 { color: blue; } .cb2 { color: #a31515; } .cb3 { color: red; }

    1 <?xml version="1.0"?>
    2 <project name="Master build file" default="build" basedir=".">
    3
    4   <echo message="first" />
    5
    6   <include buildfile="example2.xml" />
    7
    8   <target name="build" description="Main target">
    9     <echo message="second" />
   10     <call target="secondary.target" />
   11   </target>
   12 </project>

Example2.xml:

.cf { font-family: Courier New; font-size: 8pt; color: black; background: white; } .cl { margin: 0px; } .cln { color: #2b91af; } .cb1 { color: blue; } .cb2 { color: #a31515; } .cb3 { color: red; }

    1 <?xml version="1.0"?>
    2
    3 <target name="secondary.target">
    4   <echo message="third" />
    5 </target>

I had expect that the secondary.target target would not be called until after the build target was called. Instead:

.cf { font-family: Courier New; font-size: 8pt; color: black; background: white; } .cl { margin: 0px; }

NAnt 0.85 (Build 0.85.2478.0; release; 14/10/2006)
Copyright (C) 2001-2006 Gerry Shaw
http://nant.sourceforge.net

Buildfile: file:///C:/Inetpub/virtual2005/Projects/Canon/CanonCreate2005/example1.xml
Target framework: Microsoft .NET Framework 2.0
Target(s) specified: build

[echo] first
[echo] third

build:

[echo] second

BUILD FAILED

Target 'secondary.target' does not exist in this project.

Total time: 0 seconds.

Huh? Why did the output go “first”, “third”, then “second”? And why does it say secondary.target doesn’t exist?

The documentation for the <include> task states:

Any global (project level) tasks in the included build file are executed when this task is executed. Tasks in target elements are only executed if that target is executed.

Which means my build file should be executing correctly. It’s in a target, isn’t it?

So I tried wrapping the secondary target in a project tag, and lo and behold:

.cf { font-family: Courier New; font-size: 8pt; color: black; background: white; } .cl { margin: 0px; }

NAnt 0.85 (Build 0.85.2478.0; release; 14/10/2006)
Copyright (C) 2001-2006 Gerry Shaw
http://nant.sourceforge.net

Buildfile: file:///C:/Inetpub/virtual2005/Projects/Canon/CanonCreate2005/example1.xml
Target framework: Microsoft .NET Framework 2.0
Target(s) specified: build

[echo] first

build:

[echo] second

secondary.target:

[echo] third

BUILD SUCCEEDED

Total time: 0 seconds.

So the NAnt docs aren’t entirely complete, are they. So I suppose the tag <project> is really a way of saying “this is build script which I want to control the execution for, instead of just processing the whole file as NAnt reads it”.

Written by tad

February 7th, 2008 at 12:34 pm

Some TFS, Continuous Integration Related Links

without comments

Beginning to look into some of my notes from the weekend with a bit more depth. Starting with Continuous Integration, especially regarding TFS.

Some links:

Continuous Integration Using Team Foundation Build – MSDN
Provides an example project on your TFS server which provides a simple CI interface. Source not available unfortunately!

TFSBuildLab

My thoughts, shares … with .Net and Microsoft
Not sure who maintains this blog yet but it’s .Net and TFS 2008 related.

Continuous Integration in Team Build for OrcasTips for upgrading from TFS 2005 to 2008 – Grant Holiday

TFS 2008: A basic guide to Team Build 2008

Why and How to build a Continuous Integration Environment for the .NET platform

Continuous Integration with Cruise Control.NET and Draco.NET by Justin Gehtland

Continuous Integration by Martin Fowler

Boy, this is tough… as soon as I look at one resource I find a dozen more. I’ll never get through my notes at this rate.

Written by tad

February 4th, 2008 at 9:54 pm

Posted in infrastructure

Tagged with

MVC Not Ready For TFS?

with one comment

High expectations this year. I want to have at least a couple of commercial MVC website under my belt by 2009, and I want to be using Team Foundation 2008. Part of this will be to make use of Web Deployment Projects combined with Team Builds. What would be great is if I could have the team server spitting out nicely labelled development, staging and production builds of our sites, and if I could configure the config file changes using web deployment projects. Also I would like it to produce metrics around unit tests, integration test and interface tests, and anything else that would be useful (code metrics? haven’t explored this fully yet). I want our projects managers/testers to be able to know what build they’re looking at and easily get a summary of the changesets involved in that build.

So that’s the plan. We are currently running TFS 2005, but the documentation says that VSTS 2008 and TFS 2005 are compatible, so what I’m going to do first is set up a ‘Sandbox’ MVC project in it’s own Team Project space, for us to play with and try things out.

So started by creating a new Team Project, then a new ASP.Net MVC Web Application and Test project (makes sense – want to try out the built in unit testing functionality).

Then I choose the project in TFS I want to use as the repository.

At this stage everything is created and ready to check in, so I perform a solution check-in. All looks good, I can see padlocks next to all my files. But if I close and re-open the solution, I get the message:

The project ‘MvcApplicationTest’ is under source control. This version of Visual Studio .NET does not support source controlled projects. Any changes that you make to this project will not be propagated to source control.

Strange! And now the test project is no longer source-controlled. If I create a build to run these tests on the build server it won’t have any of the project files to compile and run.

To clarify, I’m using Visual Studio Team System 2008 RTM. Anyway, I’ve tried a couple of things, like deleting the test project and adding a new test project. Trouble is I can’t write tests against the MVC controllers due to some weird issue – I can’t add a reference to the version of System.Web.Extensions.dll referenced by the MVC project (3.6.0.0) to the test project. It’s in the GAC, but doesn’t appear in the components list (I see 3.5.0.0, the version that ships with VS 2008). So I can’t even create my own test projects.

Bit of a worry and I hope it gets addressed when MVC goes into full release…

Written by tad

January 9th, 2008 at 4:55 am

Posted in .net,infrastructure

Tagged with , ,