Web Deployment Builds in TFS 2010 - Part 2

by Aaron 29. December 2010 23:00

I've been patting myself on the back for a few days now because of our QA builds.  The next step in creating our automated builds is creating the release builds.

For our release builds, we don't want to automatically deploy the code.  Sounds simple, right?  I thought so too, but I found that the build doesn't apply the web.config transformations.  I accept the challenge!

After a bunch of trial and error, and staring at the targets files "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" and "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets", I finally found the answer in the former targets file:

  <!--
 ============================================================
 _CopyWebApplication

 This target will copy the build outputs along with the
 content files into a _PublishedWebsites folder.
 
 This Task is only necessary when $(OutDir) has been redirected
 to a folder other than ~\bin such as is the case with Team Build.
 
  The original _CopyWebApplication is now a Legacy, you can still use it by setting $(UseWPP_CopyWebApplication) to true.
  By default, it now change to use _WPPCopyWebApplication target in Microsoft.Web.Publish.targets.   It allow to leverage the web.config trsnaformation.
 ============================================================
 -->

So, I set the UseWPP_CopyWebApplication to True in the MSBuild arguments.  I then got this error:

C:\Program Files\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets (868): These two Properties are not compatable: $(UseWPP_CopyWebApplication) and $(PipelineDependsOnBuild) both are True. Please correct the problem by either set $(Disable_CopyWebApplication) to true or set $(PipelineDependsOnBuild) to false to break the circular build dependency. Detail: $(UseWPP_CopyWebApplication) make the publsih pipeline (WPP) to be Part of the build and $(PipelineDependsOnBuild) make the WPP depend on build thus cause the build circular build dependency.

I took the advice of the error message and set PipelineDependsOnBuild to False.

My MSBuild Arguments for a simple release build that applies the web.config transformations are now

  • /p:UseWPP_CopyWebApplication=True
  • /p:PipelineDependsOnBuild=False

I can then get the web application from the drop folder under the _PublishedWebsites folder.

Tags: , , , ,

Web Deployment Builds in TFS 2010

by Aaron 26. December 2010 02:01

This has been a great Christmas!  Not because I finally got the pony I've always wanted, and certainly not because I finally got my two front teeth.  It's because I got to see the new Doctor Who Christmas special, and I now know that it's only a few more months until the new season starts.  It feels like it's been forever since the last season ended, and based on the Christmas special, it seems like Matt Smith might really be starting to own the role.

Oh yeah!  It's also because I finally started working with the TFS 2010 build service!  I also have a couple of working builds that do automated deployments too.  Fantastic!  But it wasn't easy for me.

Background

Now, I know that I should have done this a long time ago.  Anytime you go through the steps of a completely repeatable process more than one or twice, you should see how to automate it.  I've been busy, and I've also been analyzing my process to see what I do for these builds.

My other issue is more personal.  I've been feeling like a constant failure.  My clients want quality work done.  But, they want it done right now.  I put a lot of pressure on myself to get my work done, but as a result, my quality has gone down.  When I start taking the time to put the pieces in place to increase the quality, my productivity goes down.  I'm constantly trying to find that balance, and I feel like I'm failing miserably.

Now I have several projects in flight that I'm leading the efforts on.  I have a junior developer that I'm trying to mentor and assign work to that will challenge him and help him get better.  I need to review his work from time to time to help pick out areas of improvement.  I have multiple developers on a couple of the projects and more than that on another one.  They're constantly making changes that need to be deployed for QA.  I have a QA resource that asks me for deployments on a regular basis.  My response time to his requests isn't fast enough.  I have client requests that I need to turn-around answers to quickly.  I have-  ENOUGH!

I have a lot of excuses.  I don't have enough solutions.  At least, I haven't done enough to solve my problems.  That's where we enter with automated builds.  There are lots of benefits, but I won't get into all of those.  You can find those elsewhere.  This is where I tell you about my experience in automating the builds.

Getting Started

We're using TFS 2010.  We have multiple project collections.  Natively, TFS 2010 only allows you to set up a single build service per machine, and each build service can support a single project collection.  That's great if you have multiple servers that you can set up as build machines, and/or you're a larger organization that you really need multiple servers like that.  We don't fit either of those categories, so I found a hack (courtesy of Jim Lamb) where I can support multiple build services on a single box.  I followed the instructions here to actually implement the hack because there were pictures (courtesy of Mark Nichols).

Once I got the second build service running, I created a new controller and an agent.

Web.Config Transformation

I had already performed this step a week or two prior, but I'm going to talk about it as if this was the next thing I did.

I needed to set up the web.config files for transformation.  I only needed the debug and release transformations, but you can set up as many as you need (Integration/Debug, QA, UAT, Production/Release, etc).  I have really simple transformations where I just replace some key value settings in the appSettings section, and a couple of connection strings.  Setting these up for your web application (web site?) is a necessary step if you want the deployment to be completely hands off.

Need more information on web.config transformations?  Go here.

Creating the Build

The next step was relatively easy.  I created a new build.  I pointed the build to my solution file.  I specified some things like whether or not to run the unit tests.  I even specified where to copy the build assets to.  That part was a "gotcha".

There were two reasons it was a "gotcha".  The first reason is that it doesn't copy over what you think it would copy over.  I don't remember the details, but it essentially copies over the binary assemblies, then a package folder with the web application in it as a subfolder.  The root folder itself is named after the build.  Not what I was hoping for.  So I decided to tell it not to copy the files to the drop folder.  I unchecked the box and tried again.  That was the second reason it was a "gotcha".

Apparently, the standard build template requires it even though it's an option.  There's a second configuration entry for whether or not to copy the build results to the drop folder.  That one is for the actually build assets.  But the process still needs a place to put the log files for the build process.  I ended up specifying a generic location for the builds to go.  Now on to the web application deployment.

Web Deployment

For the sake of brevity, I'm going to cut out a significant amount of the details of all of the things that happened to get me to a successful build.  Let's just say, 30-some failed builds to get me to this point.  Also, keep in mind that the server I deploy to is internal only.  It's not public-facing, nor does it have any hope of ever being public.

To set up the web server:

  1. Enable WMSvc on the web server.
  2. Install the Web Deployment Tool on the web server.  You may have to update the installation after installing it the first time to enable the "Management Service Delegation" in IIS.
  3. Make sure the Web Management Service (WMSvc.exe) is running.
  4. Make sure the Web Deployment Agent Service (MsDepSvc.exe) is running.
  5. Set up Management Service to use either just Windows Credentials if you'll be deploying with a Windows account, or also allow IIS Manager Credentials if using an IIS Manage User like I am.
  6. Allow at least an IP address, maybe even a range, in the IIS Management Service configuration.  I allowed all IP addresses on a specific subnet.
  7. In Management Service Delegation, add a rule for "Deploy Applications with Content".  I also had to add a rule with "createApp" and "setAcl" because I used an IIS Manager User.
  8. Make sure that the account the Web Management Service is running as has full access to the file system for the web site that is being deployed.
  9. In the web site, under "IIS Manager Permissions", allow the user you're using for deployment.  In my case, I have my "webdeployment" IIS Manager User that I allowed on the individual web sites.

I think that's it for the web server.  I may have forgotten something, but one of the places I got good troubleshooting info was the 4th post down on this page.

Now for the build.  There are a series of arguments that I added to the "MSBuild Arguments" in the advanced section of the process area of the build definition.  I started with the info from this page on Johan Danforth's blog, and updated them to their final settings as follows:

  1. /p:DeployOnBuild=True
  2. /p:DeployTarget=MsDeployPublish
  3. /p:MSDeployPublishMethod=WMSVC
    I'm deploying to a remote server using Web Management Service.
  4. /p:CreatePackageOnPublish=True
  5. /p:DeployIisAppPath=WebSiteNameinIIS
  6. /p:MsDeployServiceUrl=WebServerNameerver
  7. /p:AllowUntrustedCertificate=True
    Web Management Service created an SSL certificate but prefixed the server name with "wmsvc-", so the certificate wasn't valid.  This argument tells MSDeploy to ignore it.  Safe for internal use, but probably risky for a public-facing server.
  8. /p:UserName=DavidHasselhoff
    This is my IIS Manager User, but even when I was using Windows credentials, I had to specify the domain\username because the credentials didn't carry forward to the server.
  9. /p:Password=ForPresident
    Again, this is for my IIS Manager User, but even when using the Windows credentials, I had to specify the password because the credentials didn't carry forward to the server.
  10. /p:SkipExtraFilesOnServer=True
    This prevents the deployment process from deleting everything first.  If you have extra files that the site instance uses that aren't part of the deployment, they'll get deleted unless you use specify this argument.

 These arguments work for me and for my scenario.  This may not be the best configuration for deployments to a production server, but it works for us on our internal server.

Also, you should note that the MSBuild arguments for MSDeploy are not well documented, if they're documented at all.  I had to dig through the targets file located (for me) at "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets".

Now, that I'm automating our builds, and I have a template to work from, I can move on to other areas that are in desperate need of attention.

Tags: , , , ,