Where should I store common targets for team builds? - tfs

I am trying to set up a common.targets file with some common msbuild targets I want to use in my team builds and therefore import into my TFSBuild.proj files. I am wondering what is the best way to achieve this? Do I need to store common.targets right next to each TFSBuild.proj file and therefore having duplicates of the targets file for each team build or is there another way? I would rather not put the targets file on each of the build machines.

Put it in a common location that you like in source control. Prior to using the targets, do a get from your TFSBuild.proj file like this:
<PropertyGroup>
<!--Path to the TFS Command Line (used for checkin and out)-->
<TxTf>"C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\tf"</TxTf>
<WorkingDirectory>C:\YourPathHere<WorkingDirectory>
<CustomProjTFSDir>"$/YourProj/YourCustomProjPath"</CustomProjTFSDir>
</PropertyGroup>
<Exec WorkingDirectory="$(WorkingDirectory)"
Command="$(TxTf) get $(CustomProjTFSDir)"/>
The key to this working is to setup a Workspace for your build agent user that points to your custom stuff. This directory should NOT be in the same space as your normal builds.
Vaccano

Team Build has a bootstrapper phase before the TFSBuild.proj is invoked in which only the TFSBuild.proj and other files in the same directory is downloaded from source control.
So if you want your targets file to be under source control, you need to put it at the same location as the TFSBuild.proj
More details in this answer
I have never tried it, but you might be able to put the targets file on a network share, and import it using a unc share. Something like
<Import Project="\\anothermachine\share\something.targets"/>
But that would require that the build account and all people running desktop builds have access to that network share.

The goal of a common .targets file is to reduce duplication of your scripts. If you have multiple copies of this file under source control, what happens when you need to change them (to update a .exe path maybe)? Personally, I prefer a separate location for common files that any/all other build scripts can reference. The only downside to this is you will likely be hard-coding the path to this file.

You could store them alongside the MS targets in $Volume\Program Files\MSBuild. The advantage of doing this is that you can create a relative path using the built in know metadata "$(MSBuildExtensionsPath)\Path\To\Your\Targets"

Related

TFS - Workspace to build definition with only required files

In our project we are building project with TFS build definition feature.In TFS build definition there is one option like "workspace" where we mention all require folders which contains file which used to build project successfully. We have separate folders as per requirements which contain different units. this units are in large numbers hence when we build project and mention any folder in workspace then it extract all files in that particular folder. actually we require only few of them for project build because we used different files per project but that files under same roof.
could any one help us that how we build our project with only require files in workspace rather than whole folder?
Status =Active Source control folder =$/Artiion/ADO/LibForms/Loginf.pas: Build agent Folder=$(SourceDir)\LibForms\Loginf.pas
above example works fine
There is no reasonable way to do this. When you tell TFS Build what source folders to use, that is what you are telling it: get these folders. In theory I suppose you could modify or write your own process template and provide custom fields in which you could provide data to the build process about what files you need for that build, and then create some custom action to call out that would then replace the standard TFS Get function in the process template. But what would be the purpose? If you have certain files that are to be included in the solution build, then simply have separate solutions or projects which would include the appropriate files. Then build the specific solution based on which subcomponents you need, and then only those files will be built and copied to the drop location. Sure, they would still have been retrieved in the build agent's workspace, but they would not have been used in the actual build or placed in the drop location. If that's not good enough, and you need to actually Get different groups of files per build, then you should rearrange your files so that the necessary files are in the appropriate subfolders.

TFS Build Queries for Non .NET supported files

We are using TFS for maintain file versions of our database.
We do not have any .NET application in our Source Control; only HTML and supported CSS files only.
Is it possible through TFS Build Automation process to create Zip package and Deploy the package to drop location?
Note: We Do not have any .NET project or solutions only need to deploy folder(with HTML and supported files) in zip format.
I somewhere read that TFS build definition compulsorily needs .SLN files to have build project.
We don't want to build anything or test anything
Just want to create zip and deploy same to drop location.
I have tried some tweaking of Build Definition.
But in New Build definition in process tab it asks me for Items to build, where my selection is restricted to .NET supported files only.
You will need to create a custom MSBuild project file (.proj) to perform the work that you need. You can test this file locally in the command line and then when it is ready, you can point the Build process at it.
This is a good starting point for you http://www.developerfusion.com/article/84411/customising-your-build-process-with-msbuild/
The MSBuild Community Tasks (https://github.com/loresoft/msbuildtasks) contains a Zip task which should make the job a lot easier.
Judging by your description, you are using 2010 or later. What I would do is to create a custom build template that does all of what you are looking for. If you start with default template obviously you would want to remove all of the compile and test activities and replace it with the zip and copy it to the binaries directory (From there it will be moved to the drop). You could do 1 of two things for the solution file requirement, create a fake solution file in the workspace and use that knowing it won't be compiled. Or you could, in the template, remove the Argument BuildSettings which is the object that contains the solution file and configurations.

TFS Continous build custom Drop folder template

I am trying to implement continous build process, if i look at the XAML in the sequence Drop Folder I want to specify a custom template
that is I do not want all the files to be dropped in one folder,
I have to create a folder structure like Folder1, Folder2, inside root folder.
Based on file extension files have to be dropped to particular foldder
any point how to achieve this,
If you're happy modifying the TFS build templates then Torbjörn's answer is definatly the way to go. Customising the build template will give you complete control of the output. However this can be overkill, especially if you're not familiar with WF and the internals of Team Build. An alternative is to write some msbuild which will run as part fo the build.
To do this create a file called "DropTidy.proj" and edit the file so that it looks something like this
<Project DefaultTargets="CopySQLReleaseFiles" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<Target Name="CopySQLReleaseFiles">
<ItemGroup>
<SqlBuildOutput Include="$(OutDir)\*.sql" />
</ItemGroup>
<Copy SourceFiles="#(SqlBuildOutput)" DestinationFolder="$(OutDir)\SQL" />
</Target>
</Project>
The example above will copy all files with an extensions of "sql" in to a folder called "SQL". $(OutDir) is the working folder used by team build that relelates to the "Binaries" folder in the build workspace on your build agent
Check the file in to TFS and then add it to your "Items to Build" list in the Team Build Definition. Make sure that it's the last "Solution" in the list so that it runs after the other solutions in your build. Also make sure that the folder you checked the proj file in to is part of your builds workspace.
Run your build and you should see a new folder called SQL in your drop location.
If you're using the default build process template (or a derivative of), the actions for copying to DropFolder are inside Finally block of Try Compile, Test and Associate Changesets and Work Items. You will have to replace that single Copy to Drop Location action with your custom sequence. The FindMatchingFiles can be used to select a set of files based on a search criterium.
One problem will arise when trying to copy single items; TFS build activities does not have an action for that; only for CopyDirectory. You can set up a InvokeProcess, alternatively add Community TFS Build Extensions from where you'll get Robocopy and Powershell actions to support such tasks.
If you're using the basic DefaultTemplate, I'd strongly advise you to make your changes in a copy of it and use that for your builds.

TeamBuild - Is it possible to choose what projects to compile at build-time?

I am automating my build process using TeamFoundation and I need to choose what projects to compile according to the .proj file from the build. Here is the full scenario:
I have a .proj file which uses a .sln file in order to compile a solution which contains 2 websites. The .sln file is configured to compile both websites in Release configuration.
My goal is to compile only 1 website per build type, namely I want the BuildType1 to compile website 1 and BuildType2 to compile the website 2.
Is is possible to "modify" the .sln in such a way that I can unmark one of the websites to compile? Since it is an automated process, I can't change the .sln manually every time I want to compile only one website.
Look at the SolutionToBuild section in the TFSBuild.proj file.
<SolutionToBuild Include="$(BuildProjectFolderPath)/path/MySolution.sln">
<Targets>MyCustomTarget1;MyCustomTarget2</Targets>
<Properties> Configuration=Release</Properties>
</SolutionToBuild>
There are two main ways you can control the build:
create a separate Build Type in your Team Explorer. This will have its own completely independent TFSBuild.proj file, so it can build the same code-base in a completely different way. Set the SolutionToBuild up to build just what you want (as described in the accepted answer).
Use one Build Type, and set its TFSBuild.proj up to use a property to control what is built (this requires more in depth understanding od MSBuild scripts). In the Queue New Build dialog you can then use the /p: command line flag to set the property as you need it. e.g. "/p:IncrementalGet=false;IncrementalBuild=false;ForceGet=true" will force a normally incremental build to do a full rebuild. This is useful for occasoinal situations, but not a good idea for day to day builds as you have to set the parameters by hand every time.

What's the best way to get TFS to output each project to its own directory?

I'm putting a large codebase into Team Foundation Server. I would like the build process to create a "ready to deploy" build of our projects.
The normal way we've been doing this is to have each project's output be in its own folder. So, for example, we wind up with something like
C:\project1\
assembly1.dll
assembly2.dll
project1.exe
project1.exe.config
C:\project2\
assembly2.dll
assembly3.dll
project2.exe
project2.exe.config
C:\project3\
assembly1.dll
assembly3.dll
project3.exe
project3.exe.config
Which is the way we like it.
TFS, though, seems to want to stick everything in the same directory.
C:\output\
assembly1.dll
assembly2.dll
assembly3.dll
project1.exe
project1.exe.config
project2.exe
project2.exe.config
project3.exe
project3.exe.config
which, although it saves some amount of disk space (the assemblies are only there one time each) is not how we want it.
What's the best way to specify where TFS/MSBuild should put the output files? Do I need to edit sln/csproj files individually to achieve this or can I do it in the TFSBuild.proj file? (i.e., in a MSBuild-specific file)
I just blogged another method here:
http://mikehadlow.blogspot.com/2009/06/tfs-build-publishedwebsites-for-exe-and.html
but if you can't be bothered to follow the link, here it is in full:
It’s generally good practice to collect all the code under your team’s control in a single uber-solution as described in this Patterns and Practices PDF, Team Development with TFS Guide. If you then configure the TFS build server to build this solution, it’s default behaviour is to place the build output into a single folder, ‘Release’.
Any web application projects in your solution will also be output to a folder called _PublishedWebsites\. This is very nice because it means that you can simply robocopy deploy the web application.
Unfortunately there’s no similar default behaviour for other project types such as WinForms, console or library. It would be very nice if we could have a _PublishedApplications\ sub folder with the output of any selected project(s). Fortunately it’s not that hard to do.
The way _PublishedWebsites works is pretty simple. If you look at the project file of your web application you’ll notice an import near the bottom:
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />
On my machine the MSBuildExtensionsPath property evaluates to C:\Program Files\MSBuild, if we open the Microsoft.WebApplication.targets file we can see that it’s a pretty simple MSBuild file that recognises when the build is not a desktop build, i.e. it’s a TFS build, and copies the output to:
$(OutDir)_PublishedWebsites\$(MSBuildProjectName)
I simply copied the Micrsoft.WebApplication.targets file, put it under source control with a relative path from my project files and changed _PublishedWebsites to _PublishedApplications and renamed the file CI.exe.targets. For each project that I want to output to _PublishedApplications, I simply added this import at the bottom of the project file:
<Import Project="<your relative path>\CI.exe.targets" />
You can edit CI.exe.targets (or whatever you want to call it) to do your bidding. In my case, the only change so far is to add a couple of lines to copy the App.config file:
<Copy SourceFiles="$(OutDir)$(TargetFileName).config" DestinationFolder="$(WebProjectOutputDir)\bin" SkipUnchangedFiles="true" />
There’s a lot of stuff in Microsoft.WebApplication.targets that’s only relevant to web applications and can be stripped out for other project types, but I’ll leave that as an exercise for the reader.
TFS 2012+
I like this solution...
Edit your build definition. Under Process section, set MSBuild arguments to
/p:GenerateProjectSpecificOutputFolder=true
Like this:
By default each project file (*.csproj, *.vbproj, etc.) specifies a default output directory (which is usually bin\Debug, bin\Release, etc.). Team Build actually overrides this so that you're not at the whim of what properties the developer sets in the project file but also so that Team Build can make assumptions about where the outputs are located.
The easiest way to override this behaviour is to set CustomizableOutDir to true in the SolutionToBuild item group as shown here:
<ItemGroup>
<SolutionToBuild Include="$(BuildProjectFolderPath)\path\MySolution.sln" />
<Properties>CustomizableOutDir=true</Properties>
</SolutionToBuild>
</ItemGroup>
This will make the drop folder structure roughly match what you would get locally if you built the solution.
This method is definitely preferable to overriding the Core* targets which can cause upgrade issues.
For each SolutionToBuild node, set the property OutDir to $(OutDir)\SubFolder
For example:
<ItemGroup>
<SolutionToBuild Include="Project1.sln" >
<Properties>OutDir=$(OutDir)\Project1\</Properties>
</SolutionToBuild>
<SolutionToBuild Include="Project2.sln" >
<Properties>OutDir=$(OutDir)\Project2\</Properties>
</SolutionToBuild>
<SolutionToBuild Include="Project3.sln" >
<Properties>OutDir=$(OutDir)\Project3\</Properties>
</SolutionToBuild>
<ItemGroup>
(This works in TF2008, but not TF2005.)
I'm a bit late to the party answering this question but there is a very simple way to implement Mike Hadlows answer. Someone has written a nuget package that does exactly what Mike talks about. You can find it here: http://www.nuget.org/packages/PublishedApplications
Update for TFS 2010 (and upcoming TFS 2012). Jason Stangroome has written a nice blog post outlining how to do this.
https://blog.stangroome.com/2012/02/03/override-the-tfs-team-build-outdir-property/
Override the TFS Team Build OutDir property
Update: with .NET 4.5 there is an easier way.
A very common complaint from users of Team Foundation Server’s build system is that it changes the folder structure of the project outputs. By default Visual Studio puts all the files in each project’s respective /bin/ or /bin// folder but Team Build just uses a flat folder structure putting all the files in the drop folder root or, again, a // subfolder in the drop folder, with all project outputs mixed together.
Additionally because Team Build achieves this by setting the OutDir property via the MSBuild.exe command-line combined with MSBuild’s property precedence this value cannot easily be changed from within MSBuild itself and the popular solution is to edit the Build Process Template *.xaml file to use a different property name. But I prefer not to touch the Workflow unless absolutely necessary.
Instead, I use both the Solution Before Target and the Inline Task features of MSBuild v4 to override the default implementation of the MSBuild Task used to build the individual projects in the solution. In my alternative implementation, I prevent the OutDir property from being passed through and I pass through a property called PreferredOutDir instead which individual projects can use if desired.
The first part, substituting the OutDir property for the PreferredOutDir property at the solution level is achieved simply by adding a new file to the directory your solution file resides in. This new file should be named following the pattern “before..sln.targets”, eg for a solution file called “Foo.sln” then new file would be “before.Foo.sln.targets”. The contents of this new file should look like this. Make sure this new file gets checked-in to source control.
The second part, letting each project control its output folder structure, is simply a matter of adding a line to the project’s *.csproj or *.vbproj file (depending on the language). Locate the first element inside the project file that doesn’t have a Condition attribute specified, and the locate the corresponding closing tag for this element. Immediately above the closing tag add a line something like this:
<OutDir Condition=" '$(PreferredOutDir)' != '' ">$(PreferredOutDir)$(MSBuildProjectName)\</OutDir>
In this example the project will output to the Team Build drop folder under a subfolder named the same as the project file (without the .csproj extension). You might choose a different pattern. Also, Web projects usually create their own output folder under a _PublishedWebSites subfolder of the Team Build drop folder, to maintain this behaviour just set the OutDir property to equal the PreferredOutDir property exactly.
You can verify if your changes have worked on your local machine before checking in simply by running MSBuild from the command-line and specifying the OutDir property just like Team Build does, eg:
msbuild Foo.sln /p:OutDir=c:\TestDropFolder\
You could have one buildscript per project, that would do exactly what you want.
Just create a new TFSBuild file, add the projects you want to have built to the itemgroup(in the order you want them built), set where you want the output to be. This is done by overriding the - property in your TFSBuild file.
But I also agree with the previous poster - why don't you just run with a single build script, and add a zip-task at the end? Maintaining a buildscript per project does add maintenance overhead...
Sling this in a propertygroup:
<CustomizableOutDir>true</CustomizableOutDir>
It'll override the global 'CustomizableOutDir' property which, by default, is set to False. Setting this in the SolutionToBuild's properties will not work.
You achieve this by overriding the default CoreDropBuild target implementation.
In your TFSBuild.proj file (by default stored under TeamBuildTypes/<Build Type>) add the following target:
<!-- Override default implementation -->
<Target
Name="CoreDropBuild"
Condition=" '$(SkipDropBuild)'!='true' and '$(IsDesktopBuild)'!='true' "
DependsOnTargets="$(CoreDropBuildDependsOn)">
...
</Target>
Within this target you can manipulate the output as you want it. The default is to just copy everything from $(BinariesRoot)\$(BuildType) to $(DropLocation)\$(BuildNumber).
I normally use the Microsoft.Sdc.Tasks project for file copying capabilities.
Simple Solution:
Replace all <SolutionToBuild> nodes with <SolutionToPublish>. This will of course only work for publishable projects (e.g. Web projects and applications), not for library projects.
As simple as that :)

Resources