CustomizableOutDir=true breaks MSTest.exe during Team Build - tfs

When using CustomizableOutDir, I'm having problems with TFS Team Build firing off MSTest.exe properly.
TFSBuild.rsp
/verbosity:diagnostic
/p:CustomizableOutDir=true
TFSBuild.proj (solutions to build snippet)
<!-- code -->
<SolutionToBuild Include="$(BuildProjectFolderPath)/../../foo.csproj">
<Properties>OutputPath=$(BinariesRoot)\WindowsServices\foo\</Properties>
</SolutionToBuild>
<!-- tests -->
<SolutionToBuild Include="$(BuildProjectFolderPath)/../../test/test.sln">
<Targets>t1;t2</Targets>
<Properties>OutputPath=$(BinariesRoot)\TestHarness\</Properties>
</SolutionToBuild>
With both <Properties>OutputPath=$(BinariesRoot)\TestHarness\</Properties> and <Properties></Properties>, I get the following error at the end of the build:
"C:\build\BuildType\TFSBuild.proj"
(TestConfiguration target) (1:12) ->
(CoreTestConfiguration target) ->
MSBUILD : warning MSB6003: The
specified task executable "MSTest.exe"
could not be run. The directory name
is invalid
After finding this article, I and then added the following:
<Target Name="AfterCompile">
<ItemGroup>
<SolutionOutputs Condition="'%(CompilationOutputs.Solution)' == '$(Solution)'" Include="%(RootDir)%(Directory)**\*.*" />
<ServiceOutputs Include="$(BinariesRoot)\WindowsServices\**\*.*" />
<TestHarnessOutputs Include="$(BinariesRoot)\TestHarness\*.*" />
</ItemGroup>
<Copy SourceFiles="#(SolutionOutputs)" DestinationFolder="$(TeamBuildOutDir)" />
<Copy SourceFiles="#(ServiceOutputs)" DestinationFolder="$(TeamBuildOutDir)" />
<Copy SourceFiles="#(TestHarnessOutputs)" DestinationFolder="$(TeamBuildOutDir)" />
</Target>
Which gave this:
(AfterCompile target) ->
C:\build\BuildType\TFSBuild.proj(289,5):
error MSB3023: No destination
specified for Copy. Please supply
either "DestinationFiles" or
"DestinationDirectory".
DestinationDirectory is not part of the schema http://schemas.microsoft.com/developer/msbuild/2003, but I figured I would try it anyway. So I changed all the DestinationFolder on the copy tasks to DestinationDirectory and as expected I got this:
(AfterCompile target) ->
C:\build\BuildType\TFSBuild.proj(288,44):
error MSB4064: The
"DestinationDirectory" parameter is
not supported by the "Copy" task.
Verify the parameter exists on the
task, and it is a settable public
instance property.
C:\build\BuildType\TFSBuild.proj(288,5):
error MSB4063: The "Copy" task could
not be initialized with its input
parameters.
Anybody out there have CustomizableOutDir and MSTest working together in harmony with their TFS Team Build?
EDIT:
I found this discussion and applied this change:
<Target Name="BeforeTest">
<!-- The tests won't run if the binaries directory does not exist -->
<MakeDir
Directories="$(BinariesRoot)\%(ConfigurationToBuild.FlavorToBuild)"
Condition="!Exists('$(BinariesRoot)\%(ConfigurationToBuild.FlavorToBuild)')" />
</Target>
Which resulted in this:
"C:\build\BuildType\TFSBuild.proj"
(RunTest target) (1:11) ->
"C:\build\BuildType\TFSBuild.proj"
(TestConfiguration target) (1:12) ->
(CoreTestConfiguration target) ->
MSBUILD : warning MSB6006:
"MSTest.exe" exited with code 1.

This made tfs/mstest/msbuild happy.
<Target Name="BeforeTest">
<!-- The tests won't run if the binaries directory does not exist -->
<MakeDir
Directories="$(BinariesRoot)\%(ConfigurationToBuild.FlavorToBuild)"
Condition="!Exists('$(BinariesRoot)\%(ConfigurationToBuild.FlavorToBuild)')" />
</Target>
Not getting any test results was a different problem with the deployment and test box configuration.

Related

Build error on Jenkins calling F# compiler with --targetprofile parameter

We are building an Azure solution on Jenkins. This contains several F# projects, a Azure Cloud deployment project, and a C# Azure worker role.
On developer boxes it builds fine. When building on Jenkins we get:
"C:\Program Files (x86)\Jenkins\jobs\REDACTED.sln" (Clean;Build target) (1) ->
"C:\Program Files (x86)\Jenkins\jobs\REDACTED QA\workspace\REDACTED\REDACTED.csproj" (default target) (5:4) ->
"C:\Program Files (x86)\Jenkins\jobs\REDACTED QA\workspace\REDACTED.FSharp.AWS.S3\REDACTED.FSharp.AWS.S3.fsproj" (default target) (6:6) ->
(CoreCompile target) ->
FSC : error FS1052: Invalid value 'Qa' for '--targetprofile', valid values are 'mscorlib' or 'netcore'. [C:\Program Files (x86)\Jenkins\jobs\REDACTED QA\workspace\REDACTED.FSharp.AWS.S3\REDACTED.FSharp.AWS.S3.fsproj]
The problem seems to be something to do with an MSBuild parameter called 'TargetProfile' we need for the Azure aspects to specify which configuration to use (e.g. UAT or QA) and an undocumented F# parameter called --targetprofile which expects the values mscorlib or netcore.
We'd probably like a workaround which decouples these two usages of 'targetprofile'. Ideally we'd like not to have to fiddle with things like F#'s targets file as obviously we'd have to remember to apply this in all the places we might build now and in the future.
Blah, collision between MSBuild property names.
Maybe you can work around by defining a target in your project that runs directly before the F# compile target, and sets the F# TargetProfile to mscorlib, then also define a target that runs directly after F# compile that swaps the value back to whatever it was before.
From a quick test this seems to work ok.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<!-- assume TP has Azure-specific value -->
<TargetProfile>QA</TargetProfile>
</PropertyGroup>
<Target Name="BeforeFSharpCompile" BeforeTargets="CoreCompile">
<PropertyGroup>
<TempTargetProfile>$(TargetProfile)</TempTargetProfile>
<TargetProfile>mscorlib</TargetProfile>
</PropertyGroup>
<Message Text="Swapped from $(TempTargetProfile) to $(TargetProfile)" />
</Target>
<Target Name="AfterFSharpCompile" AfterTargets="CoreCompile">
<PropertyGroup>
<TargetProfile>$(TempTargetProfile)</TargetProfile>
</PropertyGroup>
<Message Text="Swapped back to $(TargetProfile)" />
</Target>
</Project>

Having issues creating a report.xml file for QUnit + PhantomJS + Jenkins

I've been trying to get Jenkins to display a JUnit report of a sample js project which i am testing with QUnit. I have literally scoured the internet for bits and pieces and so far, Running QUnit tests with Jenkins and Apache Ant? is the most helpful post that i have found.
I can confirm that:
The user has sufficient privileges to write to disk
PhantomJS works headless from the shell when i write something along the lines of:
[user#myserver PhantomJS]$ phantomjs phantomjs-runner/runner.js web/index.html
And shows:
Took 8ms to run 6 tests. 6 passed, 0 failed.
Qunit does work and provides test results when executed in a browser
Still i cannot get the report.xml to generate in order to feed it into Jenkins. Below is the target i have added to my build.xml file:
<target name="qunit" description="runs QUnit tests using PhantomJS">
<!-- QUnit Javascript Unit Tests -->
<echo message="Executing QUnit Javascript Unit Tests..."/>
<apply executable="/usr/local/CI/phantomjs/bin/phantomjs" >
<arg value="/usr/local/CI/phantomjs-runner/runner.js" />
<arg line="--qunit /usr/local/CI/jenkins/workspace/PhantomJS/web/js/qunit-1.17.1.js --tests /usr/local/CI/jenkins/workspace/PhantomJS/web/index.html --junit /usr/local/CI/jenkins/workspace/PhantomJS/test-results/report.xml" />
<fileset dir="${basedir}/web/" includes="/js/prettydate.js" />
<srcfile/>
</apply>
<echo message="Tests complete..."/>
</target>
Compiling the project in Jenkins gives me the following output:
? PhantomJS/result.xml
? PhantomJS/test-results
Using locally configured password for connection to :pserver:user#server:/cvsroot
cvs rlog -S -d18 Feb 2015 15:49:54 +0000<18 Feb 2015 15:51:40 +0000 QUnit_Jenkins
[PhantomJS] $ /usr/local/CI/ant/bin/ant qunit
Buildfile: /usr/local/CI/jenkins/workspace/PhantomJS/build.xml
qunit:
[echo] Executing QUnit Javascript Unit Tests...
[echo] Tests complete...
BUILD SUCCESSFUL Total time: 0 seconds Recording test results Test
reports were found but none of them are new. Did tests run? For
example,
/usr/local/CI/jenkins/workspace/PhantomJS/test-results/report.xml is 4
hr 18 min old
Build step 'Publish JUnit test result report' changed build result to
FAILURE Finished: FAILURE
As you may notice, jenkins can't find an updated report.xml file because there simply isn't one getting generated.
Can you observe any mistakes in my build.xml? If not, any ideas, hints that would assist me in getting the result.xml file generated?
I have found a solution to my answer by taking the following steps:
1) added <script src="js/qunit-reporter-junit.js"></script> as it is required to generate the report. Ensure you also have the qunit.js library included also. I used qunit-1.17.1.js
2) I placed the following code in the html file that tests my js code:
<script>
QUnit.jUnitReport = function(report) {
console.log(report.xml)
};
</script>
3) I added the Ant code in my build.xml file:
<target name="build" description="runs QUnit tests using PhantomJS">
<!-- Clean up output directory -->
<delete dir="./build/qunit"/>
<mkdir dir="./build/qunit"/>
<!-- QUnit Javascript Unit Tests -->
<echo message="Executing QUnit Javascript Unit Tests..."/>
<exec executable="/usr/local/CI/phantomjs/bin/phantomjs" output="./build/qunit/qunit-results.xml">
<arg value="/usr/local/CI/phantomjs-runner/runner-muted.js"/>
<arg value="./web/index.html"/>
</exec>
</target>
You will observe that i changed the name of runner.js to runner-muted.js This is so, because i have made changes to runner.js to not include its output to the xml file, as this makes it unreadable by jenkins. To do so:
cp /usr/local/CI/phantomjs-runner/runner.js /usr/local/CI/phantomjs-runner/runner-muted.js
Find and comment out console.log occurrences found under QUnit.done and QUnit.testDone to mute the runner from displaying its own test run results.
Ensure that in Jenkins you have selected the correct path to the generated xml file.
I hope this helps any of you trying to get it to work

TFS MSBuild copy command

The is my copy command:
<ItemGroup>
<SwfFiles Include="$(MSBuildProjectDirectory)\bin-release\**\*.*"/>
</ItemGroup>
<CallTarget Targets="CopyFilesToDropLocation"/>
<Target Name="CopyFilesToDropLocation">
<Copy
SourceFiles="#(SwfFiles)"
DestinationFiles="#(SwfFiles->'$(OutDir)_PublishedWebsites\PrismWeb\% (RecursiveDir)%(Filename)%(Extension)')"/>
</Target>
I dont anything being copied to the destinaton. Any idea what am I doing wrong?
IS this space for hiding values ?
DestinationFiles="#(SwfFiles->'$(OutDir)_PublishedWebsites\PrismWeb\% [here] (RecursiveDir)%(Filename)%(Extension)')"/>
I tested this with some of my code
<Copy SourceFiles="#(SourceAllFiles)" DestinationFiles="% (RecursiveDir)%(Filename)%(Extension)'" />
This space will produce a copy that works, but it tries to copy the source to this destination:
% [nbSpaces](RecursiveDir)[this part of the metadata woks]
You should use the latest build template in TFS 2013.4. It has defined locations for executing PowerShell, one of which is post-build. Using Powershell is both easyer to debug and more future proof.

Ant conditional target not running

I have the following ant file:
<project name="admin" default="dirCheck" basedir=".">
<property name="directory" location="node_modules" />
<target name="run.npm.install" depends="dirCheck" unless="${dirExists}">
<echo>${directory} does not exist. Running 'npm install'</echo>
<exec executable="npm">
<arg value="install" />
</exec>
</target>
<target name="run.npm.update" depends="dirCheck" if="${dirExists}">
<echo>${directory} exists. Running 'npm update'</echo>
<exec executable="npm">
<arg value="update" />
</exec>
</target>
<target name="node_modules.check">
<condition property="dirExists">
<available file="${directory}" type="dir"/>
</condition>
</target>
<target name="dirCheck" depends="node_modules.check">
<echo>Checking for ${directory}. Exists? ${dirExists}</echo>
</target>
</project>
For some reason, neither runNPMInstall nor runNPMUpdate are ever run, regardless of whether the node_modules directory exists or not. Anyone have any idea what might be causing this? From all examples online at least one of the dependent tasks should be run.
EDIT: Changed:
<condition property="dirExists" value="true" else="false">
To:
<condition property="dirExists">
With the same result. Additional information is that I am using Ant 1.8.2. Thanks for anyone's help!
EDIT 2: Updated code to reflect my latest tests. Output from the build for new code above is:
Buildfile: /ws_html/app/client/build.xml
node_modules.check:
dirCheck:
[echo] Checking for /ws_html/app/client/node_modules. Exists? true
BUILD SUCCESSFUL
Total time: 0 seconds
Edit 3: Output when running ant -debug -f build.xml:
jjung-m2:client-dir jjung$ ant -debug -f build.xml
Apache Ant(TM) version 1.8.2 compiled on June 16 2012
Buildfile: /ws_html/client-dir/app/client-dir/build.xml
Adding reference: ant.PropertyHelper
Detected Java version: 1.7 in: /Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home/jre
Detected OS: Mac OS X
Adding reference: ant.ComponentHelper
Setting ro project property: ant.file -> /ws_html/client-dir/app/client-dir/build.xml
Setting ro project property: ant.file.type -> file
Adding reference: ant.projectHelper
Adding reference: ant.parsing.context
Adding reference: ant.targets
parsing buildfile /ws_html/client-dir/app/client-dir/build.xml with URI = file:/ws_html/client-dir/app/client-dir/build.xml
Setting ro project property: ant.project.name -> ClientApp
Adding reference: ClientApp
Setting ro project property: ant.project.default-target -> dirCheck
Setting ro project property: ant.file.ClientApp -> /ws_html/client-dir/app/client-dir/build.xml
Setting ro project property: ant.file.type.ClientApp -> file
Project base dir set to: /ws_html/client-dir/app/client-dir
+Target:
+Target: run.npm.install
+Target: run.npm.update
+Target: node_modules.check
+Target: dirCheck
Adding reference: ant.LocalProperties
parsing buildfile jar:file:/usr/share/ant/lib/ant.jar!/org/apache/tools/ant/antlib.xml with URI = jar:file:/usr/share/ant/lib/ant.jar!/org/apache/tools/ant/antlib.xml from a zip file
Setting project property: directory -> /ws_html/client-dir/app/client-dir/node_modules
Setting ro project property: ant.project.invoked-targets -> dirCheck
Attempting to create object of type org.apache.tools.ant.helper.DefaultExecutor
Adding reference: ant.executor
Build sequence for target(s) `dirCheck' is [node_modules.check, dirCheck]
Complete build sequence is [node_modules.check, dirCheck, run.npm.update, run.npm.install, ]
node_modules.check:
[available] Found directory: node_modules
Condition true; setting dirExists to true
Setting project property: dirExists -> true
dirCheck:
[echo] Checking for /ws_html/client-dir/app/client-dir/node_modules. Exists? true
BUILD SUCCESSFUL
Total time: 0 seconds
Your runNPMInstall target will never run, because the dirExists property will always be set either true or false, because you used condition task with attribute else="false".
When using the old syntax (Ant Version < 1.8.0) , means just the plain propertyname if="propertyname" the target is only activated if the property is defined - independent of its actual value. On the contrary unless="propertyname" means the target is only activated if the property is not defined, but your property will always be set from condition task => true or false.
Since ant 1.8.0 you may use the new syntax if="${propertyname} means the target is only activated if the property holds true | yes | on, respectively unless="${propertyname}" means the target will only be activated if the property hold false | no | off, see ant manual if / unless
When using if / unless with ${propertyname} it should work as expected with Ant >= 1.8.0Alternatively use the condition task without the else attribute to make it work with the old syntax :
The value to set the property to if the condition evaluates to false. By default the property will remain unset.
Also value="true" is not needed, as :
The value to set the property to. Defaults to "true".
So that should be sufficient to make it work 'old style' :
<condition property="dirExists">
<available file="${directory}" type="dir"/>
</condition>
-- EDIT after comment --
When starting your ant file it will run the default target dir.check and nothing else happens. Use :<project name="admin" default="main" basedir=".">
and create a new target :<target name="main" depends="dir.check,runNPMInstall,runNPMUpdate"/>

Adding files to the bin directory at Build and Publish

I have two license files that I would like to include in my \bin directory both when I build and publish.
Both files are in the App_Data directory (their initial location doesn't matter, they just need to end up in the \bin) and have the following properties set:
Build Action = Content
Copy to Output Directory = Copy Always
They are in not the \bin when I build or publish.
What is wrong with my setup: the settings, the folders, the files, something else...?
UPDATE
I moved the files out of the App_Data directory and placed them in the project root and now they are copied to the \bin on build.
I've done this in a few projects by expanding my .csproject file slightly. The following code should be put directly beneath the Project node in your WebProject.csproj.
The AfterBuild target simply copies a set of files ("unreferenced DLLs" in this case) to the bin-folder when building normally from Visual Studio. The CustomCollectFiles basically do the same thing when deploying.
<PropertyGroup>
<UnreferencedDlls>..\lib\Unreferenced\**\*.dll</UnreferencedDlls>
</PropertyGroup>
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="AfterBuild">
<Message Text="Copying unreferenced DLLs to bin" Importance="High" />
<CreateItem Include="$(UnreferencedDlls)">
<Output TaskParameter="Include" ItemName="_UnReferencedDLLs" />
</CreateItem>
<Copy SourceFiles="#(_UnReferencedDLLs)" DestinationFolder="bin\%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>
<Target Name="CustomCollectFiles">
<Message Text="Publishing unreferenced DLLs" Importance="High" />
<ItemGroup>
<_CustomFiles Include="$(UnreferencedDlls)" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>bin\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
The part you need to modify is basically the UnreferencedDlls node to match your folder structure. The **\*.dll part simply means "every DLL file at any level beneath here".
If you're using Visual Studio:
Show your file properties (Click on your file or Right-click on it then choose Properties)
At the Copy to Output Directory property choose Copy always or Copy if newer.
At build time, the file is going to be copied at the bin directory: Debug or Release...
not necessarily a direct answer, but I highly suggest not using the baked in "publish" mechanism, but rather wire up a build script (probably in powershell) that will do everything you need. It's really easy to hook into MSBuild as well as nUnit and also copy files and move them around.
POWERSHELL (rough) example.
# Get Directory Location
$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
# Build the application using MSBuild
cmd /c C:\Windows\Microsoft.NET\Framework\$v4_net_version\msbuild.exe "$directorypath\MyProject.sln" /p:Configuration=Release
# Run the tests using nUnit
cmd /c $directorypath\build\nunit\nunit-console.exe $solutionPath\MyProject.Tests\bin\debug\MyProject.Tests.dll
# Copy the license to the appropriate directory
Copy-Item -LiteralPath "$directorypath\mylicensefile.txt" "$directorypath\bin\release" -Force
# NOTE: You are going to have to adjust this to match your solution and projects.
In this post on Microsoft Connect the answer is much simpler:
Referenced assemblies in Unit Test are not copied in TestResults/Out
So what I did was the following:
[TestClass]
[DeploymentItem("Some.dll")]
public class SomeTests
{
...
}
It works fine for me.
Hope it help.

Resources