I am trying to create a custom MSBuild task that will run my nUnit tests either locally or during a TFS2010 build. The script works great locally but I can't seem to find the test dlls on the TFS build server. I'm using a task in the MSBuild.ExtensionPack to run the unit tests (again this works fine locally).
The Assemblies list is always empty. TargetDir shows the path is "C:\Builds\2\Product1\ci.product1.acme.com\Binaries\" which looks right to me. I also tried to kick off my target after the CoreCompile target instead within the AfterBuild target with no change.
I've probably made some stupid mistake but I'm in kill me mode at this point. Please help.
<PropertyGroup>
<RunTFSBuild>false</RunTFSBuild>
<SolutionDirectory>$(MSBuildProjectDirectory)\..</SolutionDirectory>
<ExtensionTasksPath>$(SolutionDirectory)\_shared\MSBuild\</ExtensionTasksPath>
<TPath>$(ExtensionTasksPath)MSBuild.ExtensionPack.tasks</TPath>
<NUnitOutputFile>$(SolutionDirectory)\nUnitResults.xml</NUnitOutputFile>
<NUnitOutputFileAsMsTest>$(SolutionDirectory)\nUnitResultsAsMsTestResults.xml</NUnitOutputFileAsMsTest>
<ToolPath>$(SolutionDirectory)\_shared\MSBuild\nUnit_2.5.7</ToolPath>
</PropertyGroup>
<Import Project="$(TPath)" />
<Target Name="AfterBuild">
<CallTarget Condition="$(RunTFSBuild)!='true'" Targets="NUnitTestRunner" />
<CallTarget Condition="$(RunTFSBuild)=='true'" Targets="NUnitTestRunner;TFSNUnitTestRunner" />
</Target>
<Target Name="NUnitTestRunner">
<ItemGroup >
<Assemblies Include="$(SolutionDirectory)\**\bin\$(Configuration)\*.nUnit.Tests.dll" />
</ItemGroup>
<ItemGroup Condition="$(RunTFSBuild)=='true'">
<Assemblies Include="$(TargetDir)\**\*.nUnit.Tests.dll" />
</ItemGroup>
<Message Text="SolutionDirectory=$(SolutionDirectory)" />
<Message Text="ExtensionTasksPath=$(ExtensionTasksPath)" />
<Message Text="TargetDir=$(TargetDir)" />
<Message Text="TPath=$(TPath)" />
<Message Text="NUnitOutputFile=$(NUnitOutputFile)" />
<Message Text="Running nUnit tests from: $(Assemblies)" />
1) Try to change property RunTFSBuild
<RunTFSBuild Condition="'$(RunTFSBuild)'==''">false</RunTFSBuild>
2) Replace sections (it may be just cleaning of project, but it may be very important due to some limitations of CallTarget):
<Target Name="AfterBuild" DependsOnTargets="NUnitTestRunner;TFSNUnitTestRunner" />
<Target Name="TFSNUnitTestRunner"
Condition="$(RunTFSBuild)=='true'">
<!-- TFSNUnitTestRunner Body -->
</Target>
3) If 1) and 2) willn't be helpful try to set verbose of the build to diagnostic (msbuld key /v:diag). Find all calls of TFSNUnitTestRunner in the log and you will see what is actually happened on TFS.
EDIT: *Assemblies* is declared as ItemGroup. Use #(Assemblies) to access items:
<Message Text="Running nUnit tests from: #(Assemblies)" />
Property $(Assemblies) will always be empty in your case.
Related
I am trying to set up dependencies for a set of Delphi packages, such at if Application A uses Package 1 and Package 2, and Application B uses Package 1 only, then only Application A is rebuilt when Package 2 is changed.
At the moment, I am using a Group File, and each Package and Application is built (re-linked), even if it or one of it's dependencies is not changed.
UPDATE:
Unit1.pas is in Package 1
Unit2.pas is in Package 2
Application A uses Package 1 and Package 2
Application B use Package 2
What I want is that if I change Unit1.pas, then ONLY Package 1 and Application B is rebuilt. make will do this, but I can't work out how MSBUILD could be made to work.
My worked example uses a group file, which might be the underlying problem.
OK, I think I have sorted this out. Groupprojs will always rebuild / relink, so that is not what I want.
I have created a targets file, such that it defines the 4 projects and the dependencies of each. It has to be all the dependencies, both code and binary (i.e. the packages).
Msbuild has an attribute 'DependsOnTarget', but this doesn't achieve what I want, so I have added dependencies on both the code and packages. The final build.targets file looks like this ...
<Project ToolsVersion="3.5"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="Default">
<ItemGroup>
<Package1 Include=".\Package1\Package1.dproj"/>
<Package2 Include=".\Package2\Package2.dproj"/>
<App6 Include=".\App6\Project6.dproj"/>
<App7 Include=".\App7\Project7.dproj"/>
</ItemGroup>
<ItemGroup>
<Package1ExternalSourceFiles Include=".\Package1\*.pas" />
<Package2ExternalSourceFiles Include=".\Package2\*.pas" />
<App6ExternalSourceFiles Include=".\App6\*.pas" />
<App7ExternalSourceFiles Include=".\App7\*.pas" />
<Package1BinaryFiles Include=".\Package1\Win32\Release\Package1.bpl" />
<Package2BinaryFiles Include=".\Package2\Win32\Release\Package2.bpl" />
<App6BinaryFiles Include=".\App6\bin\Project6.exe" />
<App7BinaryFiles Include=".\App7\bin\Project7.exe" />
</ItemGroup>
<Target Name="App6" Inputs="#(App6ExternalSourceFiles);#(Package1BinaryFiles);#(Package2BinaryFiles)" Outputs="#(App6BinaryFiles)" DependsOnTargets="Package1;Package2">
<Message Text="App6" />
<MSBuild Projects="#(App6)"/>
</Target>
<Target Name="App7" Inputs="#(App7ExternalSourceFiles);#(Package1BinaryFiles)" Outputs="#(App7BinaryFiles)" DependsOnTargets="Package1">
<Message Text="App7" />
<MSBuild Projects="#(App7)"/>
</Target>
<Target Name="Package1" Inputs="#(Package1ExternalSourceFiles)" Outputs="#(Package1BinaryFiles)">
<Message Text="Package1" />
<MSBuild Projects="#(Package1)"/>
</Target>
<Target Name="Package2" Inputs="#(Package2ExternalSourceFiles)" Outputs="#(Package2BinaryFiles)">
<Message Text="Package2" />
<MSBuild Projects="#(Package2)"/>
</Target>
<Target Name="Build">
<CallTarget Targets="Package1;Package2;App6;App7"/>
</Target>
</Project>
Whether this is scalable I am not sure, we could potentially have a large number of projects and dependencies.
UPDATE: Actually the binary dependency on the Applications isn't needed, if they are shipped separate from the packages. Recompiling Package 1, without changing it's interface would mean that App6 and App7 are not rebuilt.
We are looking at migrating our build machine from FinalBuilder to Jenkins to fit in with the rest of our extended company.
One issue that I have noticed is that whereas Finalbuilder is able to extract the current library path from your current Delphi installs on the build machine, Jenkins relies on the information contained within the .dproj files.
Owing to known problems of the paths within the .dproj files being very specific to a users machine, we don't currently commit them to our repository, relying on Delphi to re-create them as required. This obviously doesn't play nice when the build machine is reliant on a full MSBUILD script being there in the first place.
We use a fair few third-party components (DevExpress suite alone having over 100 units), so including and maintaining all the .pas files with full paths in the .dpr isn't really an option for this.
Does anyone have a tried-and-tested solution for this?
My thoughts on options were:
setting the %PATH% for each build - adding the current Delphi library
for the relevant version (will this run into %PATH% length restrictions?)
Using a command-line parameter to pass the correct library path to MSBUILD (is this possible?)
Including the search path somehow in the source files with compiler directives (is this possible?)
Using a pre-compile step to create new .dproj files (something like http://delphi-divining.blogspot.co.uk/2012/10/dprojmaker-tool-to-create-delphi.html but it'll need to be command-line)
Edit: 5th idea:
Could we use dproj.local files for each project, stored in a separate repository (or in a separate path) and copied to the build machine pre-build? This would allow build machine paths to be stored safely away from clutzy commits.
You need to submit your .dproj file to source control.
You have a problem which is that your configuration is not complete. Any build system should be able to build your project using nothing but files in your source control, that is the ONLY way to ensure you are building the correct binary.
You have a number of options to make this work
You can use Environment variables in the Delphi IDE eg %ROOTFOLDER% could be set to C:\Development\MyDelphiProjects on one machine and C:\Dev on another and as long as everything is the same from that route it should be ok. Each dev and your build machine can set the required path. You may need vars for bpl paths also.
Enforce identical structures on client machines. Really how difficult is it to make all devs us C:\Development\Delphi as their root?
Make sure all search paths are relative. This can work, but there are always exceptions that cause problems so I have never managed to get this to work.
We used option 1 in a previous company and it worked very successfully, its a bit of a pain to set up but once setup you can be sure your build is correct.
I had the same problem when i choose Jenkins as a "build" environment. The solution is to use a MSBuild script with a build task inside. So in Jenkins instead of building the project directly, just build this script which gives you a lot more options, including the option to specify the paths for the project (you can to override the default IDE paths).
I'll post such a script tomorrow.
So in Jenkins when you configure MSBuild you have to specify the msbuild file, which will be Build.xml. For command line arguments i use only /v - verbosity and /t - target name.
The build script looks like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Target Name="Compile" DependsOnTargets="CompileApp" />
<PropertyGroup>
<ExeOutputName>App.exe</ExeOutputName>
<ExeOutputPath>x:\exe</ExeOutputPath>
<DcuOutputPath>x:\dcu</DcuOutputPath>
<ForConfig>Release</ForConfig>
<ForPlatform>Win32</ForPlatform>
</PropertyGroup>
<Target Name="ResolveOutputPath">
<MakeDir Directories="$(ExeOutputPath)" />
<MakeDir Directories="$(DcuOutputPath)" />
<Delete Files="$(ExeOutputPath)\$(ExeOutputName)" />
<Delete Files="$(DcuOutputPath)\*.*" />
</Target>
<ItemGroup>
<AppUnitSearchPathItem Include="$(BDS)\lib\$(ForPlatform)\$(ForConfig)" />
<AppUnitSearchPathItem Include="C:\Users\builder\Documents\tmssoftware\TMS Component Pack" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Dcu\$(ForPlatform)" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\CodeGen" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\DataSnap" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\ZLib" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\Synapse" />
<AppUnitSearchPathItem Include="C:\Program Files (x86)\Embarcadero\RAD Studio\12.0\Components\EhLib\Lib\$(ForPlatform)\$(ForConfig)" />
...
</ItemGroup>
<ItemGroup>
<AppDefinesItem Include="App" />
<!-- AppDefinesItem Include="CompilerDirective" -->
</ItemGroup>
<ItemGroup>
<AppPropertiesItem Include="DCC_ExeOutput=$(ExeOutputPath)" />
<AppPropertiesItem Include="DCC_DcuOutput=$(DcuOutputPath)" />
<AppPropertiesItem Include="DCC_BuildAllUnits=true" />
<AppPropertiesItem Include="DCC_Optimize=true" />
<AppPropertiesItem Include="DCC_DebugInformation=0" />
<AppPropertiesItem Include="DCC_PentiumSafeDivide=true" />
<AppPropertiesItem Include="DCC_RangeChecking=true" />
<AppPropertiesItem Include="DCC_IntegerOverflowCheck=true" />
<AppPropertiesItem Include="DCC_WriteableConstants=true" />
<AppPropertiesItem Include="DCC_IOChecking=true" />
<AppPropertiesItem Include="DCC_AssertionsAtRuntime=false" />
<AppPropertiesItem Include="DCC_Warnings=true" />
<AppPropertiesItem Include="DCC_MapFile=3" />
<AppPropertiesItem Include="DCC_ConsoleTarget=false" />
</ItemGroup>
<Target Name="CompileApp" DependsOnTargets="ResolveOutputPath">
<PropertyGroup>
<AppUnitSearchPath>#(AppUnitSearchPathItem)</AppUnitSearchPath>
<AppDefines>#(AppDefinesItem)</AppDefines>
</PropertyGroup>
<ItemGroup>
<AppProperties Include="Config=$(ForConfig)" />
<AppProperties Include="Platform=$(ForPlatform)" />
<!-- AppProperties Include="LibraryPath=$(AppUnitSearchPath)" -->
<AppProperties Include="DelphiLibraryPath=$(AppUnitSearchPath)" />
<AppProperties Include="UnitSearchPath=$(AppUnitSearchPath)" />
<AppProperties Include="ResourcePath=$(AppUnitSearchPath)" />
<AppProperties Include="IncludePath=$(AppUnitSearchPath)" />
<AppProperties Include="ObjPath=$(AppUnitSearchPath)" />
<AppProperties Include="DCC_Define=$(AppDefines)" />
<AppProperties Include="#(AppPropertiesItem)" />
</ItemGroup>
<MSBuild Projects="App.dproj" Properties="#(AppProperties)" />
</Target>
</Project>
What is missing here is the versioning part which can be done from this script using a resource template...
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.)
I am building various projects using the <MSBuild Projects="... markup. I am then executing some command line tools after the project is built.
E.g
<Target Name="Name">
<MSBuild Projects="" />
<Exec Command="" />
</Target>
I notice that the project is only built as required and get the following output when the build script is run: "Skipping target "CoreCompile" because all output files are up-to-date". This is great but how do I make my <Exec... commands use the same condition so that they are only run when necessary as well?
Update: I've implemented gregmac's suggestion but its still executing the command regardless. This is what I've got now:
<Target Name="Name">
<MSBuild Projects="">
<Output TaskParameter="TargetOutputs" ItemName="AssembliesBuiltByChildProjects" />
</MSBuild>
<Exec Command="" Condition="'#(AssembliesBuiltByChildProjects)'!=''" />
Any further help is much appreciated. This is a bit of a sticking point for me.
Thanks for any tips.
Alan
You should be able to use the TargetOutputs parameter:
<MSBuild Projects="" >
<Output TaskParameter="TargetOutputs" ItemName="AssembliesBuiltByChildProjects" />
</MSBuild>
<Message Text="Assemblies built: #(AssembliesBuiltByChildProjects)" /> <!-- just for debug -->
<Exec Command="" Condition="'#(AssembliesBuiltByChildProjects)'!=''" />
If you can add the following to each of your projects:
<Target Name="DoStuffWithNewlyCompiledAssembly">
<Exec Command="" />
</Target>
... then you only need to add a property:
<Target Name="Name">
<MSBuild Projects="" Properties="TargetsTriggeredByCompilation=DoStuffWithNewlyCompiledAssembly" />
</Target>
This works because someone smart at Microsoft added the following line at the end of the CoreCompile target in Microsoft.[CSharp|VisualBasic][.Core].targets (the file name depends on the language and MSBuild/Visual Studio version).
<CallTarget Targets="$(TargetsTriggeredByCompilation)" Condition="'$(TargetsTriggeredByCompilation)' != ''"/>
So if you specify a target name in the TargetsTriggeredByCompilation property, your target will run if CoreCompile runs-- and your target will not run if CoreCompile is skipped (e.g. because the output assembly is already up-to-date with respect to the code).
You are asking wrong question.
Exec does not have any condition, But you can have condition on Target element which can be used like this.
<Target Name="Name" Condition="#(AssembliesBuiltByChildProjects)'!=''">
<MSBuild Projects="">
<Output TaskParameter="TargetOutputs" ItemName="AssembliesBuiltByChildProjects" />
</MSBuild>
<Exec Command=""/>
</Target>
<Target Name="Name" Condition="#(AssembliesBuiltByChildProjects)'==''">
...
</Target>
I did manage to find a solution to fit my needs although it may not be the optimal solution.
See my answer to my other question here: MSBuild Post-Build
Thanks,
Alan
I'm having some strange problems copying files in a custom script in TFS2008 without SP1, I have to run the build several times to get the files copied (most of the times its in the second build that i get the files), let me give you the details:
This is happening with ASP sites and VS2003 Web solutions, (vs2008 solutions are OK)
In ASP I have a dummy 2008 solution, the build compiles this dummy, I override AfterCompile and in there I copy all the files to the drop location
In VS 2003 i have also a dummy 2008 solution, the build first compiles the dummy, I override AfterCompile, use "Exec" and "Command" to compile the 2003 solution and then copy the files to the drop location.
As you can see both approaches are similar, I'm not having problems with the builds per se, my problem is reproducible in two ways (and yes, i do check out, update, check in and then test the build):
Create a new build, configure the script, run the build the first time, some DLL's in the bin folder are not copied, run the build for the second time and i get all the files.
Build already configured and running OK, add some file to the project (this mostly happens with the ASP sites), run the build, don't get this new file, run the build again and i get this new file.
Here is my build script for a VS2003 Web solution as an example
<PropertyGroup>
<TasksPath>D:\BuildTools\</TasksPath>
<VS2003Devenv>D:\Archivos de programa\Microsoft Visual Studio .NET 2003\Common7\IDE\devenv.com</VS2003Devenv>
<VS2003VirtualFolder>CnbvPifWeb</VS2003VirtualFolder>
<VS2003Suba>Cnbv.Pif.Web</VS2003Suba>
<VS2003Project>Cnbv.Pif.Web</VS2003Project>
<VS2003WebSiteName>Sitio Web predeterminado</VS2003WebSiteName>
<VS2003Configuration>Release</VS2003Configuration>
<VS2003Branch>Desarrollo</VS2003Branch>
<VS2003RelativePath>$(SolutionRoot)\$(VS2003Branch)\$(VS2003Suba)\</VS2003RelativePath>
<VS2003SolutionPath>$(VS2003RelativePath)Cnbv.Pif.Web.sln</VS2003SolutionPath>
<VS2003LocalFolder>$(VS2003RelativePath)Sources\$(VS2003Project)\</VS2003LocalFolder>
<VS2003Output>$(BinariesRoot)\$(VS2003Project)\</VS2003Output>
<VS2003CachePath>C:\Documents and Settings\srvfoundation\VSWebCache\230-2555-CPU015\</VS2003CachePath>
<VS2003ProjectExtension>vbproj</VS2003ProjectExtension>
<VS2003CacheFile>$(VS2003CachePath)$(VS2003VirtualFolder)\_vti_pvt\$(VS2003Project).$(VS2003ProjectExtension).cache</VS2003CacheFile>
</PropertyGroup>
<Import Project="$(TasksPath)Microsoft.Sdc.Common.tasks"/>
<UsingTask TaskName="Microsoft.Sdc.Tasks.Web.WebSite.CreateVirtualDirectory" AssemblyFile="Microsoft.Sdc.Tasks.dll" />
<UsingTask TaskName="Microsoft.Sdc.Tasks.Web.WebSite.DeleteVirtualDirectory" AssemblyFile="Microsoft.Sdc.Tasks.dll" />
<ItemGroup>
<!--list of ouput files, excluding .DLL outside bin and some other files-->
<VS2003OutputFiles
Include="$(VS2003LocalFolder)**\*.*"
Exclude="$(VS2003LocalFolder)**\*.vb;$(VS2003LocalFolder)**\*.cs;$(VS2003LocalFolder)**\*.resx;$(VS2003LocalFolder)**\*.vspscc;$(VS2003LocalFolder)**\*.csproj;$(VS2003LocalFolder)**\*.vbproj;$(VS2003LocalFolder)**\*.scc;$(VS2003LocalFolder)**\*.webinfo;$(VS2003LocalFolder)**\*.snk;$(VS2003LocalFolder)**\*.dll;$(VS2003LocalFolder)**\*.exe;" />
<!-- copy dll to bin folder -->
<VS2003OutputBinFiles
Include="$(VS2003LocalFolder)bin\*.dll"/>
</ItemGroup>
<Target Name="AfterCompile">
<Message Text="Deleting cache file" />
<Microsoft.Build.Tasks.Delete
Condition="Exists('$(VS2003CacheFile)')"
Files="$(VS2003CacheFile)" />
<Message Text="Creating virtual folder $(VS2003VirtualFolder) in IIS in local path $(VS2003LocalFolder)" />
<Web.WebSite.CreateVirtualDirectory
VirtualDirectoryName="$(VS2003VirtualFolder)"
Path="$(VS2003LocalFolder)"
WebSiteName="$(VS2003WebSiteName)" />
<Message Text="Compiling $(VS2003Project) in $(VS2003Branch)" />
<Exec
Command=""$(VS2003Devenv)" "$(VS2003SolutionPath)" /build $(VS2003Configuration) /out "$(VS2003LocalFolder)$(VS2003Project).log" "/>
<Message Text="Eliminando la carpeta virtual $(VS2003VirtualFolder) en IIS" />
<Web.WebSite.DeleteVirtualDirectory
WebSiteName="$(VS2003WebSiteName)"
VirtualDirectoryName="$(VS2003VirtualFolder)" />
<MakeDir Condition="!Exists('$(VS2003Output)')" Directories="$(VS2003Output)" />
<Message Text="Copying output files #(VS2003OutputFiles)" />
<Copy
SourceFiles="#(VS2003OutputFiles)"
DestinationFiles="#(VS2003OutputFiles->'$(VS2003Output)%(RecursiveDir)%(Filename)%(Extension)')"
/>
<MakeDir Condition="!Exists('$(VS2003Output)bin\')" Directories="$(VS2003Output)bin\" />
<Message Text="Copying DLL to bin folder #(VS2003OutputBinFiles)" />
<Copy
SourceFiles="#(VS2003OutputBinFiles)"
DestinationFiles="#(VS2003OutputBinFiles->'$(VS2003Output)bin\%(Filename)%(Extension)')"
/>
<OnError ExecuteTargets="VS2003Fail" />
</Target>
<Target Name="VS2003Fail">
<Message Text="Copying log file $(VS2003RelativePath)$(VS2003Project).log" />
<Copy Condition="Exists('$(VS2003RelativePath)$(VS2003Project).log')" SourceFiles="$(VS2003RelativePath)$(VS2003Project).log" DestinationFolder="$(DropLocation)\$(BuildNumber)" />
<CallTarget ContinueOnError ="true" Targets ="CreateWorkItemWhenPartialSucceed" />
</Target>
<Target
Name="CreateWorkItemWhenPartialSucceed"
Condition=" '$(SkipWorkItemCreation)'!='true' and '$(IsDesktopBuild)'!='true' ">
<Message Text="ejecutando work" />
<PropertyGroup>
<WorkItemTitle>$(WorkItemTitle) $(BuildNumber)</WorkItemTitle>
<BuildLogText>$(BuildlogText) <ahref='file:///$(DropLocation)\$(BuildNumber)\BuildLog.txt'>$(DropLocation)\$(BuildNumber)\BuildLog.txt</a >.</BuildLogText>
<ErrorWarningLogText Condition="!Exists('$(MSBuildProjectDirectory)\ErrorsWarningsLog.txt')"></ErrorWarningLogText>
<ErrorWarningLogText Condition="Exists('$(MSBuildProjectDirectory)\ErrorsWarningsLog.txt')">$(ErrorWarningLogText) <a href='file:///$(DropLocation)\$(BuildNumber)\ErrorsWarningsLog.txt'>$(DropLocation)\$(BuildNumber)\ErrorsWarningsLog.txt</a >.</ErrorWarningLogText>
<WorkItemDescription>$(DescriptionText) %3CBR%2F%3E $(BuildlogText) %3CBR%2F%3E $(ErrorWarningLogText)</WorkItemDescription>
</PropertyGroup>
<CreateNewWorkItem
TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
BuildNumber="$(BuildNumber)"
Description="$(WorkItemDescription)"
TeamProject="$(TeamProject)"
Title="$(WorkItemTitle)"
WorkItemFieldValues="$(WorkItemFieldValues)"
WorkItemType="$(WorkItemType)"
ContinueOnError="true" />
</Target>
When I see the ouput of this message in the log
<Message Text="Copying DLL to bin folder #(VS2003OutputBinFiles)" />
the first time i see just the name of one file, the second time it prints all the correct files, and the same happens with the ASP sites, if I add a file i see the file in the output in the second build.
I hope you can help me out figuring this out, thanks a lot.
Juan Zamudio
this was the answer in the tfs forum by OsirisJakob
The problem is that you define your item groups at the root level. This means that they are evaluated immediately when the project file loaded. What you want is for them to be evaluated when the AfterCompile target is executed.
Since you are running TFS 2008, you can solve this problem by moving the item groups into the AfterCompile target (a.k.a. Dynamic item groups). This will cause the item group to be evaluated by the time the AfterCompile target is executed, and will give you the correct result.