Click here to Skip to main content
15,867,686 members
Articles / Desktop Programming / XAML

Java / Ant Builds on TFS

Rate me:
Please Sign up or sign in to vote.
4.91/5 (3 votes)
8 Oct 2013CPOL6 min read 32.5K   8   9
An adventure in building Java software on a TFS build server

Introduction

Building Java software on a 2012 Team Foundation Server (TFS) build server might sound crazy at first, but it really works, and is relatively simple to get up and running. Unfortunately, there's a dearth of documentation available on how to configure your Ant builds in conjunction with Windows Workflow build template and project files. This article will bring everything together, and illustrate what it takes to build Java on TFS.

Background 

I've been building .NET software on TFS build servers for some time now, and have developed some level of expertise in doing so. When someone asked if I could build Java software on a TFS build server, I thought they were joking. This team is using TFS for source code control, and wanted to know if building in this environment was feasible. After a little research, I found out that it not only was possible, but appears to be in wide use. Emboldened by this new-found information, I set out to take an existing Java solution and get it to build on TFS using Ant. This article shares that experience and offers some ways to make Java builds a little easier to work with in the world of TFS.

Using the code  

The team being supported in this effort uses Eclipse as their IDE, and TFS as the source code repository. The team was also using Jenkins for the builds and Oracle WebLogic for deployments. The focus of this article will be on the build, not deployments. For the Eclipse IDE, the Team Explorer Everywhere add-on is required. This allows the developer/build manager to access to the source code, but more importantly, helps with the creation of build definitions. Another prerequisite for this environment is Apache Ant, "a Java library and command-line tool whose mission is to drive processes described in build files as targets and extension points dependent upon each other. The main known usage of Ant is the build of Java applications." Ant targets and tasks allow the builder to compile, assemble, test, and run Java applications. In most Java projects, there is a build folder which will contain a build.xml file. This build.xml file is what Ant uses to construct the targets specified in the build. Because a build server is being used, the Ant files will need to specify tasks and targets that will be available to the build. There may also be external properties files, which contain build-specific properties that are loaded into the Ant build process at run time. These property files will need to passed to the build server as an argument to the Ant command. More on this soon. 

Finally, there is the installation and configuration of the build server. http://msdn.microsoft.com/en-us/library/jj155784.aspx provides a how-to guide, and even steps the user through the creation of a build definition. Use those steps to configure your build server and create your first build definition. 

The output of these steps is the creation of a file that TFS needs to perform the build: TFSBuild.proj. This project file contains the Ant directives that will construct the software. In its generated form, it's a very simplistic MSBuild project file that works in conjunction with the TFS UpgradeTemplate.xaml file, which is the Windows Workflow file that guides the build process. In order to make the build definition more flexible, some editing of both the TFSBuild.proj and the UpgradeTemplate.xaml file will need to be performed.

Without customization, the TFSBuild.proj contains an <ItemGroup> entry that looks like this: 

XML
<ItemGroup>
    <!-- Ant Call Configuration.
         The build file called should be included in the workspace of the build definition.
    -->
    <AntBuildFile Include="$/MyProject/web/website/build/build.xml">
      <Targets></Targets>
      <Properties>BinariesRoot=$(BinariesRoot);BuildDefinitionName=$(BuildDefinitionName);
        BuildDefinitionUri=$(BuildDefinitionUri);BuildDirectory=$(BuildDirectory);
        BuildNumber=$(BuildNumber);DropLocation=$(DropLocation);LogLocation=$(LogLocation);
        SourceGetVersion=$(SourceGetVersion);TestResultsRoot=$(TestResultsRoot);
        TeamProject=$(TeamProject);WorkspaceName=$(WorkspaceName);WorkspaceOwner=$(WorkspaceOwner)</Properties>
      <Lib></Lib>
    </AntBuildFile>

    <!-- JUnit XML Results files should be created using the XML formatter
         and be located in the following path
    -->
    <JUnitLogFiles Include="$(BinariesRoot)\**\TEST-*.xml" />
</ItemGroup>

Note that the AntBuildFile tag has an include parameter for the build.xml file that was specified during the construction of the build definition. There's a <Targets> tag, too - this is where a build target can be passed to the project file, but it's empty by default. Obviously, this isn't very flexible in this form. The build manager would need to edit and check in the TFSBuild.proj file every time a different build was desired. Since there can be only one TFSBuild.proj file, this creates a real problem. Let's look at making three variable inputs to this process (along with some defaults) that will ease the build manager's pain. Let's break down the following code segment, which is a replacement for the code segment we just examined above: 

XML
<PropertyGroup>
    <!-- Set a default value for BuildEnv if not passed -->
    <BuildEnv  Condition=" '$(BuildTarget)'  == '' ">build-install-jroth</BuildEnv>
    <MyProps Condition=" '$(MyProps)' == '' ">build.jroth-gr.properties</MyProps>
    <MyBuild Condition=" '$(MyBuild)' == '' ">build.xml</MyBuild>
  </PropertyGroup>
  <ItemGroup>
    <!--  Ant Call Configuration.  
      The build file called should be included in the workspace of the build definition.
    -->
    <AntBuildFile Include="$(MyBuild)">
      <Targets>$(BuildTarget)</Targets>
      <Properties>BinariesRoot=$(BinariesRoot);BuildDefinitionName=$(BuildDefinitionName);
        BuildDefinitionUri=$(BuildDefinitionUri);BuildDirectory=$(BuildDirectory);
        BuildNumber=$(BuildNumber);DropLocation=$(DropLocation);LogLocation=$(LogLocation);
        SourceGetVersion=$(SourceGetVersion);TestResultsRoot=$(TestResultsRoot);
        TeamProject=$(TeamProject);WorkspaceName=$(WorkspaceName);
        WorkspaceOwner=$(WorkspaceOwner)</Properties>
      <Lib></Lib>
      <PropertyFile>$(BuildDirectory)$(MyProps)</PropertyFile>
    </AntBuildFile>
    <!-- JUnit XML Results files should be created using the XML formatter
         and be located in the following path
    -->
    <JUnitLogFiles Include="$(BinariesRoot)\**\TEST-*.xml" />
</ItemGroup>

Note that a <PropertyGroup> has been created above the <ItemGroup> from the previous example. Three conditional properties have been defined for the build target <Targets>, a new property, the external build property file <PropertyFile>, and the build.xml file <AntBuildFile Include="$(MyBuild)">, respectively. In the <ItemGroup>, the arguments for the build file, the properties file, and the and build target are specified using $(MyBuild), $(MyProps), and $(BuildTarget), respectively. But this begs the question: where did these arguments get defined? How are they passed into this this project file? This is where the UpgradeTemplate.xaml file comes into play.

In Visual Studio 2012, double-click on the Upgrade.Template.xaml file, which will open the scary-looking workflow editor. Don't worry - it's not as bad as it looks. At the bottom left of that screen, click on "Arguments." Use the line with "Create Argument" to type in the first of the three arguments above. Repeat for the next 2, until you have three entries: BuildTarget, MyProps, and MyBuild:

 Image 1

Next, click the odd icon on the right side of the Metadata line, and add the three arguments to this dialog. Provide helpful Display Names for each parameter:

Image 2

Use the same category for all three. When the build definition is rendered, it will group these arguments under that category header.  

Click again on "Arguments" to dismiss that list. Now, find the "Run TfsBuild for Configuration" activity in the workflow, and right-click on it and select Properties.

Image 3 

In the properties dialog for that activity, locate the CommandLineArguments. Click on the ellipsis to open the Expression Editor and construct the following line:

"/p:BuildTarget=" + BuildTarget + ";MyProps=" + 
          MyProps + ";MyBuild=" + MyBuild + " " + MSBuildArguments

Click OK to save this dialog, then save the template and check it in.  Open the build definition, then open the Process tab. Click on "Show details" in the upper right, select the build template, and click the "Refresh" button. Under the new category "Custom" should be the 3 arguments. Provide values for these arguments, and they will be passed into the build process. 

Image 4

These minor changes have now provided a flexible build definition template that can be used to create separate build definitions, one per target. They can also be changed at runtime to use whatever target, build file, or property file desired. 

Points of Interest

This only solves the problem of having a single TFSBuild.proj file, which is a great step forward. There are still the issues of structuring the Java builds for the TFS Build server. If there's not a high level of software build maturity, there's likely some work in ensuring the builds are structured properly for building on a remote server.

History 

  • Original article: 10/8/13

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Epsilon
United States United States
Sr. Director at Epsilon, a leader in marketing technology.

Comments and Discussions

 
QuestionProperty Default Values with VS2013 and TFS 2013 Pin
Andrew Moreno25-Apr-15 7:06
Andrew Moreno25-Apr-15 7:06 
AnswerRe: Property Default Values with VS2013 and TFS 2013 Pin
Jim Roth11-May-15 11:33
Jim Roth11-May-15 11:33 
Questionright on the money Pin
Member 1101516815-Aug-14 6:00
Member 1101516815-Aug-14 6:00 
Thanks for the detail description of the process. it is really helpful.
QuestionMultiple Java Versions between Projects? Pin
Jeff Murr18-Dec-13 8:47
Jeff Murr18-Dec-13 8:47 
AnswerRe: Multiple Java Versions between Projects? Pin
Jim Roth21-Jan-14 6:57
Jim Roth21-Jan-14 6:57 
QuestionWhy not TFS SDK for Java? Pin
Giulio Vian11-Oct-13 23:20
Giulio Vian11-Oct-13 23:20 
AnswerRe: Why not TFS SDK for Java? Pin
Jim Roth13-Oct-13 6:12
Jim Roth13-Oct-13 6:12 
GeneralRe: Why not TFS SDK for Java? Pin
Giulio Vian6-Nov-13 6:48
Giulio Vian6-Nov-13 6:48 
GeneralRe: Why not TFS SDK for Java? Pin
Jim Roth6-Nov-13 8:24
Jim Roth6-Nov-13 8:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.