Microsoft Tfs build variable gets lost - tfs

I am running build with next targets:
<Target Name="BeforeCompile">
<Message Text="Build no: $(BuildNumber)" />
</Target>
Then in between I run build (using nmake). After that I want to deploy firmware:
<Target Name="AfterCompile">
<MSBuild Projects="$(MSBuildProjectFile)" Targets="CustomDeployMagicFirmware" Properties="Id=1" />
</Target>
<Target Name="CustomDeployMagicFirmware">
<Message Text="...Deploying bootloader files to build machine - folder: $(BuildNumber)" />
<Exec Command='xcopy "$(SolutionRoot)\Repository\bootloader\*.axf" \\machine\bootloader\$(BuildNumber) /y /q'/>
<Exec Command='xcopy "$(SolutionRoot)\Repository\bootloader\*.hex" \\machine\bootloader\$(BuildNumber) /y /q'/ -->
</Target>
The problem is that in target "BeforeCompile" I get properly message output for $(BuildNumber). But later I have Message Test output like:
...Deploying bootloader files to build machine - folder:
There looks like variable $(BuildNumber) is not set anymore. Also command xcopy copies files to folder bootloader and not to folder bootloader\$(BuildNumber).
What do I do wrong? Which things can influence variable contents?

The error is in this line
<MSBuild Projects="$(MSBuildProjectFile)" Targets="CustomDeployMagicFirmware" Properties="Id=1" />
The MSBuild task spawns a new MSBuild.exe process and you are not passing the property $(BuildNumber) to the new process. Change it like below and this would work
<MSBuild Projects="$(MSBuildProjectFile)" Targets="CustomDeployMagicFirmware" Properties="Id=1;BuildNumber=$(BuildNumber)" />

Use <CallTarget> instead of <MSBuild> to invoke your CustomDeployMagicFirmware target.

Related

Msbuild ignores continueonerror?

I am trying to invoke MSbuild for a couple of projects twice. First time without any clean, but if this fails I will invoke a clean followed by a new build. (The reasoning is that I want my build to be fast but if that fails fall back to clean, restore nuget packages build etcetera). This works but the build will still fail if the first call failed (it has continueonerror set to true so I dont want it to fail...). Here are the relevant parts of the build file:
<ItemGroup>
<ProjectsToPublish Include="X.sln" />
</ItemGroup>
<Target Name="RestoreAllPackages">
<Message Text="#(ProjectsToPublish)" />
<Exec Command='"$(MSBuildProjectDirectory)\.nuget\nuget.exe" restore "$(MSBuildProjectDirectory)\%(ProjectsToPublish.Identity)"'
/>
</Target>
<Target Name="Build" >
<MSBuild Projects="#(ProjectsToPublish)" Properties="SkipRestore=True;RunCodeAnalysis=False;Retries=10;RetryDelayMilliseconds=50"
BuildInParallel="true" ContinueOnError="WarnAndContinue" />
<!-- MSBuildLastTaskResult outcome of previous task-->
<PropertyGroup>
<FastBuildFailed>false</FastBuildFailed>
<FastBuildFailed Condition="'$(MSBuildLastTaskResult)' == 'false'" >true</FastBuildFailed>
</PropertyGroup>
<Message Importance="high" Text="Initial build failed? $(FastBuildFailed)" />
<Message Importance="high" Text="Initial build failed will retry" Condition="'$(FastBuildFailed)'" />
<CallTarget Targets="FullBuild" Condition="'$(FastBuildFailed)'" />
</Target>
<Target Name="FullBuild" DependsOnTargets="RestoreAllPackages">
<!--Fake property below to reexecute build exact same properties prevents the build lform re-->
<MSBuild Projects="#(ProjectsToPublish)" Properties="SkipRestore=True;RunCodeAnalysis=False;FakeProperty=one" BuildInParallel="true" />
</Target>
<Target Name="RestoreAllPackages">
<Message Text="#(ProjectsToPublish)" />
<Exec Command='"$(MSBuildProjectDirectory)\.nuget\nuget.exe" restore "$(MSBuildProjectDirectory)\%(ProjectsToPublish.Identity)"'
/>
</Target>
For anyone with this rather exotic error. It seems that when a build is run inside of a TFS build server, the build server parses log output and will fail a build even with a ContinueOnError setting. My workaround ended up being <Exec Command="$(MSBuildBinPath)\msbuild.exe #(ProjectsToPublish) /noconlog " ContinueOnError="true" />
Basically spawning a new MSBuild using Exec and making sure that it did not output anything using /noconlog
Rather than using <OnError..., you can assign ContinueOnError the value 'WarnAndContinue', and then use a condition to check the $(MSBuildLastTaskResult) property.
Generic example:
<Error ContinueOnError="WarnAndContinue" />
<Message Importance="High" Text ="$(MSBuildLastTaskResult)" />
<!-- (Returns false) -->
(I believe both "WarnAndContinue" and $(MSBuildLastTaskResult) were introduced in MSBuild 4.0; they should be available on your TFS 2012 build server.)

Jenkins Phing Plugin - Resource Temporarily Unavailable

I have just started getting Jenkins setup with Phing as the build tool. Although I have used Jenkins before, I'm new to Phing.
I have a project setup in Jenkins that has a Mercurial Repository setup and a Phing Build step.
The build.xml file simply archives the existing file, deletes them and copies the new files from the repository.
I have run phing from the terminal and everything works as planned. However, when running from within Jenkins, I'm getting the following in the Console Output:
[workspace] $ /usr/local/pear/bin/phing -buildfile /Users/Shared/Jenkins/Home/jobs/Project/workspace/build.xml "-Dwebroot=/Volumes/Websites/Project/ -Dcheckoutroot=/Users/Shared/Jenkins/Home/jobs/Project/workspace -Drevision=5" -logger phing.listener.DefaultLogger
/usr/local/pear/bin/phing: fork: Resource temporarily unavailable
Build step 'Invoke Phing targets' marked build as failure
My first thought was that it was permission related, but I've changed Jenkins to run as the same user that I ran Phing manually as and it still got the same issue.
Does anybody have any thoughts as to what might be causing the problem?
I can't find anything related to this error anywhere that isn't related to Cygwin...
The system is running on OS X 10.7.5 with Jenkins 1.518 and Phing 2.5.1
The build.xml file looks like:
<?xml version="1.0" encoding="UTF-8"?>
<project name="Project" default="dist">
<property name="revision" value="old" />
<property name="webroot" value="/Volumes/Websites/${phing.project.name}" />
<property name="checkoutroot" value="./" />
<target name="clean">
<echo msg="Backing up old site to ${phing.project.name}-${revision}..." />
<tar destfile="${webroot}/../${phing.project.name}-${revision}.tar.gz" basedir="${webroot}" compression="gzip" />
<echo msg="Deleting site from ${webroot}..." />
<delete>
<fileset dir="${webroot}" />
</delete>
</target>
<target name="dist" depends="clean">
<echo msg="Copying files to website at ${webroot}..." />
<copy todir="${webroot}">
<fileset dir="${checkoutroot}/Website">
<exclude name="**/.hg/**" />
</fileset>
</copy>
</target>
</project>
I've managed to resolve this issue by removing all of the path details in the Phing configuration section within Jenkins.
This makes absolutely no sense to me as to why it's working without these details as I definitely only have one Phing install, so it's not as if it was picking up the wrong one or something.
However, by not specifying anything in the Phing section of the Jenkins project config so it picks up the default path, default build target etc. and this is working flawlessly now!

Avoid Printing Build Successful after ant exits a target

I have an ant script which calls a target from another script. When this target is fully executed, the second script exits with a "Build Successful" message, which is a bit confusing to the users. I dont want the second ant script to echo "Build Successful" on its exit.
My code is
<target name="startRemoteJboss" description="Starts Remote Instance of Jboss">
<echo message="starting Remote Jboss" />
<sshexec output="remoteJboss.txt" trust="true" host="${jboss.remote.host}" username="${jboss.remote.username}" password="${jboss.remote.password}" command="ant -f build.xml startJboss" port="${jboss.remote.port}" failonerror="no"/>
</target>
The second build file target looks like
<target name="startJboss" description="Starts Jboss">
<echo message="starting Jboss" />
<exec executable="${jboss.home}/bin/run.sh" spawn="true">
<arg line="-b 0.0.0.0 -c default" />
</exec>
<sleep seconds="150" />
<echo message="Jboss is UP" />
</target>
When the startJboss completes it execution, i would like it to not print "Build Successful"
[sshexec] BUILD SUCCESSFUL
[sshexec] Total time: 10 seconds
Since you're capturing the output to a file (<sshexec output="remoteJboss.txt" ...), then you should be able to strip these lines from it, e.g.:
<concat>
<fileset dir="." includes="remoteJboss.txt" />
<filterchain>
<linecontains negate="true">
<contains value="[sshexec] BUILD SUCCESSFUL"/>
</linecontains>
<linecontains negate="true">
<contains value="[sshexec] Total time:"/>
</linecontains>
</filterchain>
</concat>
To printout to the user (assuming you're using concat already), or use the destFile attribute to specify a copy of the output file where these lines are stripped out:
<concat destfile="remoteJboss_short.txt" >
Best practice is to use macrodef for sharing functionality, means make a macrodef of your startJboss target instead of starting another ant instance with new project scope.
This will also avoid the BUILD SUCCESSFUL output.
EDIT
The "BUILD SUCCESSFUL" string comes from ant's DefaultLogger#getBuildSuccessfulMessage(). You may write your own logger that returns an empty string or any other string instead, see ant manual listeners and loggers for details.

Build multiple environments with a single target and single command(Anding -D and property file)

I have to create a single command to create multiple(dev|qa|uat) war/ear.
Something like :
ant -f build.xml -Denv=dev|qa|uat -propertyfile= devProp|qaProp|uatProp
-Dstage.dir=devdir|qadir|uatdir
I already have different properties file, different staging, deploying target for each environment. I also have different .cmd files to build each of them separately.
What I am stuck at is: How do I build them all in one go?
You can use the <subant /> instruction in your target.
Write down a new ant script (namely master.xml), assuming that your original build is in script build.xml, you can have something like:
<target name="build-all">
<subant target="build-prod">
<fileset dir="." includes="build.xml"/>
<propertyset ......../> <!-- properties for the prod build -->
</subant>
<subant target="build-dev">
<fileset dir="." includes="build.xml"/>
<propertyset ......../> <!-- properties for the dev build -->
</subant>
</target>

running specific target in different ant scripts in different directories

We have a large amount of apps. They all have a build.xml file located in the projects base directory. I am trying to create an ant script that will go through and call a specific target on each of the build.xml files in all the projects.
Here are the issues:
Some of the projects are in deeper directories than others.
Only some of the projects need to be built at a time.
I was trying to use subant + antfile and defining a CSV of file paths in a properties file, but this did not work. Below is what i have and the error i am getting.
If there is a better way to do this or you know what my problem is, please let me know! Thanks!
This is the property defined in a property file. I am wanting the person running the script to add the file paths in here that are relative to the current location of the script they are running.
projects.to.build=
This is the subant task i am trying to use in the main build script.
<filelist
id="projectNames"
dir="${basedir}"
files="${projects.to.build}"
/>
<target name="debugAll" description="Builds all the projects listed in the projectNames.properties file.">
<subant target="debug" antfile="${projects.to.build}">
</subant>
</target>
Here is the error i get when i try to run the build script when there are projects defined in the properties file. I am using the relative path. For example: ..\Apps\AnApp1\build.xml,..\Apps\AnApp2\build.xml,..\OtherApps\foo\AnotherApp1\build.xml
"No Build Path Specified" (at my subant task)
You specified the antfile attribute, so ANT was expecting to a single build.xml file.
The subant documentation describes how you can use a fileset as child parameter.
Here's an example:
<project name="Subant demo" default="run-debug-target">
<target name="run-debug-target">
<subant target="debug">
<fileset dir="." includes="**/build.xml" excludes="build.xml"/>
</subant>
</target>
</project>
Update
Alternatively a filelist could be used:
<project name="Dry run" default="run">
<target name="run">
<subant target="test">
<filelist dir="projects" files="one/build.xml,two/build.xml,three/build.xml,four/build.xml"/>
</subant>
</target>
</project>
Processing the following build files:
projects/one/build.xml
projects/two/build.xml
projects/three/build.xml
projects/four/build.xml
Is it possible to run the target in the all the build files concurrently ?
E.g.
<project name="Dry run" default="run">
<target name="run">
<subant target="test">
<filelist dir="projects" files="one/build.xml,two/build.xml,three/build.xml,four/build.xml"/>
</subant>
</target>
</project>
In this example, is there any way to run target "test" present in all the build files (one/build.xml,two/build.xml,three/build.xml,four/build.xml) concurrently ?

Resources