P3.NET

Generating _PublishedWebsites in TFBuild

We have slowly been migrating our XAML builds to TFBuild. After having blogged about how we created custom build tasks we were finally ready to start transitions our builds. At our company we have basically 3 different kinds of builds – ASP.NET apps, console applications and REST APIs. Using XAML builds our deployment process was configured to look for the _PublishedWebsites directory for ASP.NET apps but that doesn’t get created in TFBuild. Hence I spent some time looking for a solution.

The first thing I did was go to Google. The majority of the answers I found said you had to trigger the web deployment process using MSBuild arguments. So that is what I did.

/p:OutDir=$(build.artifactStagingDireoctyr) /p:DeployOnBuild=True /p:WebPublishMethod=Package /p:PackageAsSingleFile=false /p:SkipInvalidConfigurations=true

This worked but it had several disadvantages. Firstly, I didn’t want a package. Yet using this approach you get a _Package folder in addition to your normal build output. The package folder contains a series of files including the optional single file you might have requested. All this is setting things up for using MSDeploy.

I could live with the extra folder since it did create the publish folder like I wanted but I figured I tried the alternative publish mode which is FileSystem. Alas this triggers a not supported error. Googling for this reveals this is a known limitation. So I updated all our web apps to use the above code and accepted the fact we’d have an extra folder. But then I started getting build errors on a couple of our projects.

Taking a look at the build log I found that I was exceeding the MAX_PATH limit. That’s odd because I thought that problem was resolved in the newest update but evidently MSBuild hasn’t been updated and there seems to be a lot of pushback on migrating things piecemeal. But that shouldn’t apply in my case as I make sure all our build paths are small. I looked further and found that the packaging process, for some reason, creates an Archive folder and then proceeds to copy all the files being packaged into it. Unto itself harmless, but it builds a directory structure that matches the FULL path to the files. So given a simple agent working directory of C:\agents\_work\Team1\Project1 it creates the folder structure of Archive\c\agents\_work\team1\project1. So you basically lose half of MAX_PATH because of this folder structure. So clearly package isn’t going to work for us after all.

At this point I was ready to create my own custom task. After all it isn’t too hard to build the task. Unfortunately, to get it right, you’d have to look at the build action for the files in the project to ensure you copy the ones that should be copied as content. So I reset the arguments to simply this.

/p:OutDir=$(build.artifactStagingDirectory)

And viola! I still got the _PublishedWebsites folder and contents. Evidentially you don’t need to create the deployment at all to get the build to trigger this output directory. This simple MSBuild argument is sufficient to trigger the creation of the directory. I have since updated all our web apps to use this argument and I haven’t run into any issues. Hopefully MS can update their documentation to include this useful bit of information instead of everyone having to google for the answer.