How to build multiple projects in a solution, each project with a different target? - tfs

I’m working with a VS2010 solution that has multiple projects (normal assemblies, an ASP.NET MVC project, a Windows Azure project, and a SQL project). I am trying to figure out how to set up a TFS build definition to deploy both the Windows Azure project and the SQL project.
I know how to do a Windows Azure deployment, and have a custom build task in the Windows Azure project file (.ccproj) that does the deployment. I can easily create a build definition that runs against the .ccproj file, passing in some MSBuild command line arguments as parameters, and works as expected.
I can create another build definition that runs against the SQL project (.sqlproj) file, passing to MSBuild the build targets and parameters needed to build and publish the SQL project. That works as expected.
As two distinct build definitions what I have works. Easy enough.
What I have yet to figure out is how to combine these two build definitions into one. Is that even possible (without a lot of work)? Ideally I’d be able to kick off a new build that will build the projects and deploy them both (just as they do as separate build definitions) as part of a single unit of work.
I have tried using the solution file as the item to build, and specifying the build targets as /t:<project>:<target>;<project>:<target>. But, apparently that syntax only works for targets in the base set and not any custom targets or those imported by other .targets files (or so that’s my understanding).
What is the best (simplest) way to accomplish what I’m looking to do?

Sure you can totally do this! Basically, you need to have a target in each project with the same name. Then you change the DependsOn list for each to include the project specific list of targets. Example:
Project 1:
<Target Name="MyBuild" DependsOnTargets="AzureTarget1,AzureTarget2" />
Project 2:
<Target Name="MyBuild" DependsOnTargets="SQLTarget1,SQLTarget2" />
Then you can tell the build definition to build the MyBuild target on each and it should invoke the appropriate DependsOn targets.
This is a very simple example of how to do this, but you can make this much more robust if you also use MSBuild Traversal projects and an MSBuild traversal task much like the method described in the following article under the "Building Large Source Trees" section:
http://msdn.microsoft.com/en-us/magazine/dd483291.aspx#id0100082

Related

TF Build definition with Publish target and running unit tests

I've created a build definition using TF Build. It is the nightly build for our project. It should run the defined Unit Tests and it should package the Azure Cloud Service projects.
This build has been running for some time without the packaging step. This resulted in a successful build that also ran the Unit Tests.
Based on the following guide I have added the packaging of the Cloud Services: https://azure.microsoft.com/en-us/documentation/articles/cloud-services-dotnet-continuous-delivery/. Basically it comes down to setting the target to Publish for msbuild (/target:Publish) in the Build definition.
The problem is that when a solution is build with a Publish target the Unit test projects are not build. MSBuild will return with the following message: Skipping unpublishable project. I have traced this back to the common MSBuild target file. A project will only build when Publishing is the project results in an exe, as can be seen here: http://referencesource.microsoft.com/#MSBuildFiles/C/ProgramFiles(x86)/MSBuild/14.0/bin_/amd64/Microsoft.Common.CurrentVersion.targets,217
What I have tried:
Forcing building of Unit Test projects in Publish builds.
I have added the following msbuild to the Unit Test csproj-files in order to override the default target on Publish:
<PropertyGroup>
<PublishDependsOn>
Build;
</PublishDependsOn>
</PropertyGroup>
Setting the output type of the Unit Test project to Console Application
In both cased MSBuild will give the The specified project reference metadata for the reference "..\..csproj" is missing or has an invalid value: Project for all projects that are referenced by the unit test project.
I feel like I'm not on the right track. Is there a way I can both build the Unit Test projects and build and publish the Cloud Service projects?
Okee, it was much simpler then I though.
The /target-arguments of MSBuild can take multiple targets that are built in turn. I change my build definition to have /target:Build;Publish as msbuild params. This fixed the issue.
I got an error (no entry point specified for cloud service) doing /t:Build;Publish with my service. So I did 2 separate actions, one with Build and one with Publish and that worked.

Ant - Ignore/Skip Missing Target?

$ ant clean compile notexist install
Here I get BUILD FAILED because notexist doesn't exist as a target, which is expected. But is there anyway to just ignore or skip unknown targets? Or maybe map unknown targets to a known target (which would be a no-op for me)?
Background
We are using Atlassian Bamboo for our CI server, and whenever we want to add an ant target to our build, we run the risk of breaking older branches of code. This is because if we run an old build through our CI, it may not contain the target and therefore fail. Thus we are reduced to editing the build.xml file, and either use depends or <ant>, but this doesn't give us the flexibility we desire.
Example
Today we have:
ant clean selenium.tests
We want to add a new target to test our REST services. Target is rest.tests. Thus, I want my command to be
ant clean selenium.tests rest.tests
But for old branches, rest.tests doesn't exist yet. Our solution up to now has been to add rest.tests as a dependency of selenium-tests (since our build.xml is under version control), but this means we can't run selenium.tests by itself.
In hindsight, we should have just created a proxy target, such as integration.tests (we already use test for unit tests) which would delegate to both of these two targets. But unless there is a solution to my original question, we can't even add integration.tests to the CI.
You may have to invoke ant programmatically. Discussed here in Running ANT Programmatically Through Java
The org.apache.tools.ant.Project provides list of targets and way to invoke it
I don't think there is a way to test that a target (rather than a file) exists as you call it. My suggestions are:
How often do you build old versions which have missing targets? If it sufficiently infrequent that you can take the pain of manually commenting out those calls in the CI config?
Can you limit your CI calls to a tidy set which will generally be there: clean, build, test, dist etc?
Do you need to split the CI config into multiple jobs? If you really need targets which aren't there in some versions maybe you have radically different versions of your product that merit separation into different CI jobs. Then it won't make sense to build the job for which the target doesn't exist.

Running a build against multiple projects with different build arguments

I have a series of projects that need to be compiled and published, deployed to separate directories with separate MSBuild arguments. As it stands, I have separate builds for each. For example, project 1:
MSBuild Arguments: /target:myTarget /property:PublishDir=\\1.1.1.1\PublishDir1
and project 2:
MSBuild Arguments: /target:myTarget /property:PublishDir=\\1.1.1.2\PublishDir2
However I'd like to merge them into a single build. The problem I have is that although TFS will allow me to specify multiple projects in the build, the MSBuild arguments apply to all projects. Is there a quick way I can force a distinct set of build arguments per project, or do I need to create a new build template to do this?
I am afraid, you need new build template to pass additional arguments to the template.
But if you are trying to Publish the build output to different directory based on different Project, you can achieve it by setting up same publish profile for each project. Add publish profile for each Project with same name. you can use File system Publish Method to Publish the output to different directories for each project. Just call the Publish profile in the MsBuild Argument.
/p:DeployOnBuild=true;PublishProfile=Dev
I suggest, that you create an MSBuild .proj file to execute the builds, i.e.:
<Project ToolsVersion="4.0" DefaultTargets="Rebuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Rebuild" >
<!--Execute proj1-->
<MSBuild Projects="Proj1.csproj" Properties="Configuration=Debug;PublishDir=\\1.1.1.2\PublishDir1;></MSBuild>
<!--Execute proj2-->
<MSBuild Projects="Proj2.csproj" Properties="Configuration=Debug;PublishDir=\\1.1.1.2\PublishDir2;></MSBuild>
</Target>
</Project>
Just point your tfs to this custom .proj file.

TFS Build Error While Invoking custom build file via TFS Build definition

I use TFS 2010, VS 2010.
I wrote a custom msbuild proj file which I use locally to build my solution. I use MSBUILD.exe TFSBuild.proj and it does everything in my local machine. (I have a taregt called 'DoMyBuild' which kicks off the build and does everything.)
I have used this in the DefaultTargets attribute as below:
<Project DefaultTargets="DoMyBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
I am trying hard to configure this to use my build server with a build definition. In the build definition, under Process - I configured 'Upgrade Template' and in the build process paramters, have given the path to this TFSBuild.Proj file.
Ideally. TFS should start 'DoMyBuild' target as I read. But it gives a error looking for 'EndToEndIteration' not defined. So, I believe it is still doing a DesktopBuild which I dont want. I want to use my custom target to kick start. Is this possible ?
Any help is very much appreciated.
Thanks, Mani
You problem is discussed here.
Make sure you have at least an EndToEndIteration target defined in your MSBuild project.
<Target Name="EndToEndIteration"
Condition=" '$(IsDesktopBuild)'!='true' "
DependsOnTargets="$(EndToEndIterationDependsOn)" />

Building along with Project Dependencies in Ant

I have a Java project that is dependent on other Java projects that are siblings and there is a chain of dependencies. Each individual project has a build script written in Ant. For clarity find below a sample of the same.
EARProject depends on WebProject and EJBProject: The war file that is generated by the WebProject build and jar file that is generated by the EJBProject are needed to build the EARProject.
WebProject depends on ComponentOneProject: The jar file that is generated by the ComponentOneProject build is needed to build WebProject.
EJBProject depends on ComponentTwoProject: The jar file that is generated by the ComponentTwoProject build is needed to build EJBProject.
So, when I build the EARProject build, if the dependent war and jar have not been built yet, then it should kick-off the WebProject build and EJBProject build and if the ComponentOneProject is yet to be built, the build of ComponentOneProject needs to be kicked-off and so on.
Can someone suggest a clean method by which we can accomplish this?
Facing the same problem we at our company wrote a custom Groovy script that explores the full dependency tree ant generates the Ant build scripts based on all the .project, .classpath, .settings/* files. This wasn't as difficult as it might seem as first. This way we can build our products without (My)Eclipse on a clean CVS+JDK+Groovy virtual machine. Hope it helps..

Resources