CopyAllFilesToSingleFolderForMsdeployDependsOn hook works on local but not when built in TFS - visual-studio-2012

With reference to this article by SamStephens and this by Sayed, I have managed to include additional dependent files during packaging when built LOCALLY using Visual Studio 2012.
The issue starts when I built the codes in TFS. Looking through the logs, it looks like the CopyAllFilesToSingleFolderForMsdeployDependsOn is not hooked on.
CopyAllFilesToSingleFolderForMsdeployDependsOn =
;
;
CopyAllFilesToSingleFolderForPackageDependsOn =
;
;
So I have a Deployment.csproj with a CreatePackage.targets file and in this target file, it would build the web application project. The following is the snippet of the file which I combine what I learned from both the articles stated earlier.
<!-- Create Web Deploy package for local build. -->
<Target Name="WebPackage" Condition="'$(TfsBuild)' == ''">
<!-- MSBuild the project. -->
<MSBuild Projects="..\webapplication.csproj"
Targets="Package"
Properties="
Platform=$(Platform);
VisualStudioVersion=$(VisualStudioVersion);
Configuration=$(Configuration);
WebPublishMethod=Package;
ExcludeApp_Data=false;
DeployOnBuild=true;
DeployTarget=Package;
PackageAsSingleFile=true;
PackageLocation=$(PackageOutputDirectory);
PublishProfile=$(MSBuildThisFileFullPath);
ExcludeFoldersFromDeployment=Scripts;
ExcludeFilesFromDeployment=parameters.xml;">
</MSBuild>
</Target>
<PropertyGroup>
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
DefineAssemblies;
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForMsdeployDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
<AssemblySource Condition="'$(TfsBuild)' == ''">$(SolutionDir)\ProjectA\bin\$(Configuration)\ProjectA.dll</AssemblySource>
<AssemblySource Condition="'$(TfsBuild)' == 'true'">$(OutputDirectory)ProjectA.dll</AssemblySource>
<Target Name="DefineAssemblies">
<ItemGroup>
<FilesToInclude Include="$(AssemblySource)">
<Dir>lib</Dir>
</FilesToInclude >
</ItemGroup>
</Target>
<Target Name="CustomCollectFiles">
<ItemGroup>
<FilesForPackagingFromProject Include="#(FilesToInclude )">
<DestinationRelativePath>%(FilesToInclude.Dir)\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
So the question is: Why is this working nicely locally in VS2012 and not in the TFS build?
I've been stuck in this for two days now so I would really appreciate any help.

Related

ASP .NET Core : Directory.EnumerateFiles and IIS hosting

When I publish my ASP .NET Core (v.2.2) web application on a IIS-server it throws an exception on this line:
Directory.EnumerateFiles(_environment.ContentRootPath + #"/Pages/API")
The exception:
An unhandled exception has occurred while executing the request.
Could not find a part of the path 'C:\Release\MySite\Pages\API'.
System.IO.DirectoryNotFoundException at
System.IO.Enumeration.FileSystemEnumerator`1.CreateDirectoryHandle(String
path, Boolean ignoreNotFound)
When I look inside the published folder there is no API folder, but should it not be inside of my website dll? Or can I not use relative or absolute paths to find files in my web project when I publish it on ISS?
Note: The pages in folder API have Build Action : content, and the code works without problem in development (with IIS-express).
For asp.net core, it will precompile views while publishing into Project.Views.dll. For Directory.EnumerateFiles, it only lists the real exist files in the disk.
For a solution, try to modify your project.csproj to add <MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>.
Full
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.0" />
</ItemGroup>
</Project>

Azure web role deploy does not copy non-project files

We are trying to deploy an AngularJs website to azure that is build with gulp. So we develop in a source application and gulp copies the files to the dist project. The dist project is a Azure cloud source Web Role. The "compiled" files are inside of the project folder, though for some reason they are not copied.
We turned on the option Properties -> Package/Publich Web -> All files in this project folder
After deploying I only see the packes.config, web.config and bin folder. Is there anything we need to do to get the rest of the files deployed?
Yep, gulp generated files are not actually part of the project (included in the xx.csproj file) which is why "All files..." does not work. We accomplish this by adding some custom targets for build to the project file - our gulp files are in a folder called "dist".
Unload Project >> Edit... then include something like:
<Target Name="CustomCollectFiles">
<ItemGroup>
<_DistFiles Include="dist\**\*" />
<FilesForPackagingFromProject Include="%(_DistFiles.Identity)">
<DestinationRelativePath>dist\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
<_SrcFiles Include="src\**\*" />
<FilesForPackagingFromProject Include="%(_SrcFiles.Identity)">
<DestinationRelativePath>src\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
<PropertyGroup>
<TypeScriptModuleKind>AMD</TypeScriptModuleKind>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>
.
.
.
<Target Name="AfterBuild" DependsOnTargets="CustomCollectFiles">
<Copy SourceFiles="#(_DistFiles)" DestinationFolder="dist" />
</Target>

How to setup building steps for CruiseControl.net from repository of the building project?

I'd like to store ccnet.config file (or other cc.net configuration file for this project) in the repository (git) of my project and make CC.NET use it when I force building from dashboard. How can I do it?
Thank you!
Your "ccnet.config" should remain fairly static.
If you need different "logic" for your solution/project building, then I suggest:
1. Write your ccnet.config code to pull source code from repository. (aka, Task #1)
2. In your repository, include a MasterBuild.proj (msbuild definition).
3. Have cc.net call msbuild.exe on MasterBuild.proj (aka, Task #2).
4. Have the majority of your logic inside the MasterBuild.proj file. That is what you check in/out of source control.
If you think of CC.NET as a "super fancy msbuild.exe executor", you're world will make more sense IMHO.
Here is a very basic msbuild (definition) file.
You can call it
MySolutionMasterBuild.proj (or similar)
Put this in the same directory as your .sln file (in source control).
Use CC.NET to download the code.
Then wire up msbuild.exe to call the below file.
Then have any extra logic inside the .proj file.
You can do some of the other CC.NET stuff, like post build emailing and merging any results xml, but the majority of the logic (my preference anyways)..........would be in the file below.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="AllTargetsWrapped">
<PropertyGroup>
<!-- Always declare some kind of "base directory" and then work off of that in the majority of cases -->
<WorkingCheckout>.</WorkingCheckout>
<ArtifactDestinationFolder>$(WorkingCheckout)\ZZZArtifacts</ArtifactDestinationFolder>
</PropertyGroup>
<Target Name="AllTargetsWrapped">
<CallTarget Targets="CleanArtifactFolder" />
<CallTarget Targets="BuildItUp" />
<CallTarget Targets="CopyFilesToArtifactFolder" />
</Target>
<Target Name="BuildItUp" >
<MSBuild Projects="$(WorkingCheckout)\MySolution.sln" Targets="Build" Properties="Configuration=$(Configuration)">
<Output TaskParameter="TargetOutputs" ItemName="TargetOutputsItemName"/>
</MSBuild>
<Message Text="BuildItUp completed" />
</Target>
<Target Name="CleanArtifactFolder">
<RemoveDir Directories="$(ArtifactDestinationFolder)" Condition="Exists($(ArtifactDestinationFolder))"/>
<MakeDir Directories="$(ArtifactDestinationFolder)" Condition="!Exists($(ArtifactDestinationFolder))"/>
<Message Text="Cleaning done" />
</Target>
<Target Name="CopyFilesToArtifactFolder">
<ItemGroup>
<MyExcludeFiles Include="$(WorkingCheckout)\**\*.doesnotexist" />
</ItemGroup>
<ItemGroup>
<MyIncludeFiles Include="$(WorkingCheckout)\bin\$(Configuration)\**\*.*" Exclude="#(MyExcludeFiles)"/>
</ItemGroup>
<Copy
SourceFiles="#(MyIncludeFiles)"
DestinationFiles="#(MyIncludeFiles->'$(ArtifactDestinationFolder)\%(Filename)%(Extension)')"
/>
</Target>
</Project>
Take a look at the scenario's at
http://www.cruisecontrolnet.org/projects/ccnet/wiki/Build_Server_Scenarios
Step 1 Setting up Source Control
Step 2 Build on Check-in
Step 3 Add unit tests
Step 4 Add Coverage
Step 5 Add source code analysis
There are build scripts foreseen in each step where you can base yourself on.

Include files in MSBuild that are not part of project

I'm trying to create an automated build for my web application project.
We use a standard CMS project and have tweaked some parts of it. Only the tweaked files are part of our project, but I want to include the full CMS in the deployment package.
So I've created a custom .targets file to define a task to include the CMS files during the build:
<Target Name="GetCMSFiles">
<ItemGroup>
<!-- Include the CMS files into the package -->
<_CMSFiles Include="..\packages\CMSFiles\**\*" />
<FilesForPackagingFromProject Include="%(_CMSFiles.Identity)">
<DestinationRelativePath>
%(RecursiveDir)%(Filename)%(Extension)
</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<!-- VS2010 -->
<CopyAllFilesToSingleFolderForPackageDependsOn>
GetCMSFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
<!-- VS2012 -->
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
GetCMSFiles;
$(CopyAllFilesToSingleFolderForMsdeployDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>
This works fine, but the problem is that the files from our project do not get copied to the deployment folder. So in other words, it does not overwrite the files that already exist after I copied them with the GetCMSFiles task.
The way I see it there are two options:
Force the CopyAllFilesToSingleFolder to overwrite any existing files in the deployment folder.
Have a condition in the GetCMSFiles task to only include files that don't already exist in the project.
But I'm not sure whether this is possible and how to achieve this. Any ideas?

Specifying results filename for vstest.console.exe

May be a silly question, but does anybody know how to specify the output filename of a VSTEST.Console.exe run? My command line is as follows:
vstest.console.exe [assembly] /logger:trx
At the end of the run, the following comes up in the console:
ResultsFile: somepath\TestResults\{username}_{workstation} {timestamp}.trx
I tried using the .runsettings file to specify the output location, but that only seems to control the output directory, but not the output file. Have not found anything else that would seem to control it.
I want to parse the TRX file and generate a report out of it (this already works, but if I can't specify the output path of the TRX file, I won't know where to pick it up from in the scripts!)
I have to be missing something here...
EDIT: See #AnaFranco's answer - apparently since VS2017 the file name can be configured like so:
vstest.console.exe [assembly] /logger:trx;LogFileName=[filename].trx
I'll leave the old answer for posterity and pre-2017 versions.
Nope, you're not missing anything. The TRX logger doesn't support any parameters (unlike the TFS publisher logger).
The logger assembly is located in "C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.TrxLogger.dll". If you check it out in your favorite .NET decompiler, you'll see the method TrxLogger.GetTrxFileName. It uses some basic knowledge about the current test run to produce the mangled name of form {username}_{workstation} {timestamp}.trx and is in no appreciable way configurable.
As far as I can tell, the TRX file is created in the TestResults\ folder under the current working directory unless otherwise configured. What you can do is:
Create a new temporary folder
Change the current directory to it
Run the test runner
Scan the folder for the result .trx file using your favorite recursive file search method and you're done
At least that is what I do in our build (MSBuild, sob):
<ItemGroup>
<TestResult Include="**\*.trx"/>
</ItemGroup>
I.e, gather all .trx files under the current directory and stuff them into the #(TestResult) item group for further processing.
This has worked for me for testing .net core I haven't tried it with .net framework:
vstest.console.exe [assembly] /logger:trx;LogFileName=[filename].trx
Maybe its a new thing
Update: This works for .net framework projects too using the latest Test platform and vstest.console.exe
Apparently, you can specify a directory where to put the *.trx file (not of the file itself though). This is, however, done via .runsettings file rather than via command line.
Excerpt from Bhuvaneshwari's blog:
If the default location of results need to be overriden user need to
pass this value using a runsettings file.
Example:
Mstest.exe /testcontainer:abc.dll /results:C:\Results.trx
Vstest.console.exe abc.dll /settings:output.runsettings
where the context of the
.runsettings file would be something like below :
<?xml version="1.0" encoding="UTF-8"?>
<RunSettings>
<RunConfiguration>
<ResultsDirectory>c:\</ResultsDirectory>
</RunConfiguration>
</RunSettings>
I had this issue as well. I decided to write a MSBuild target that executes vstest.console via the EXEC task, handling all its outputs, including the coverage results.
Basically, I captured the vstest output and used a regex to capture the *.trx and *.coverage portion of the output, which turned out to be really easy. Plus, it removes the TestResults directory to keep the workspace nice and clean.
In the end, you will get the *.trx file and the *.coverage file (optionally).
The script may look a bit complex, but it was necessary to fit our needs. I tried to clean it up a bit.
Hope this helps.
<Target Name="Test" DependsOnTargets="Build">
<!-- Declare the defaults and arrange parameters -->
<PropertyGroup>
<ArtifactsPath Condition=" '$(ArtifactsPath)' == '' ">Artifacts</ArtifactsPath>
<VSTestSessionName Condition=" '$(VSTestSessionName)' == ''">TestResults</VSTestSessionName>
<VSTestExe Condition=" '$(VSTestExe)' == '' ">C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe</VSTestExe>
<VSTestFailBuildOnTestFail Condition=" '$(VSTestFailBuildOnTestFail)' == '' ">false</VSTestFailBuildOnTestFail>
<VSTestInIsolation Condition=" '$(VSTestInIsolation)' == '' ">true</VSTestInIsolation>
<VSTestUseVsixExtensions Condition=" '$(VSTestUseVsixExtensions)' == '' ">true</VSTestUseVsixExtensions>
<VSTestFramework Condition=" '$(VSTestFramework)' == '' ">framework45</VSTestFramework>
<VSTestLogger Condition=" '$(VSTestLogger)' == '' ">trx</VSTestLogger>
<ErrorCode>0</ErrorCode>
</PropertyGroup>
<ItemGroup>
<VSTestResultsPath Include="$(VSTestResultsPath)" />
<VSTestParams Include="#(VSTestFiles ->'"%(FullPath)"', ' ')" />
<VSTestParams Condition="$(VSTestEnableCodeCoverage)" Include="/EnableCodeCoverage" />
<VSTestParams Condition="$(VSTestInIsolation)" Include="/InIsolation" />
<VSTestParams Include="/UseVsixExtensions:$(VSTestUseVsixExtensions)" />
<VSTestParams Include="/Framework:$(VSTestFramework)" />
<VSTestParams Include="/Logger:$(VSTestLogger)" />
<VSTestParams Condition="$(VSTestCaseFilter) != ''" Include="/TestCaseFilter:"$(VSTestCaseFilter)"" />
<VSTestParams Condition="$(VSTestRunSettings) != ''" Include="/Settings:"$(VSTestRunSettings)"" />
</ItemGroup>
<Message Text="TestAssembly: %(VSTestFiles.Identity)" Importance="high"/>
<Exec ContinueOnError="!$(VSTestFailBuildOnTestFail)" ConsoleToMSBuild="true" WorkingDirectory="$(WorkingDirectory)" Condition=" '#(VSTestFiles)' != ''"
Command=""$(VSTestExe)" #(VSTestParams, ' ')">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
<Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
</Exec>
<Message Importance="high" Text="VSTest exitcode: $(ErrorCode)"/>
<!-- Use the VSTest output to discover the Results & Coverage files respectively -->
<PropertyGroup>
<!-- Unencoded Regex: (?<=(Results file: )).*?(?=\;)|(?<=(Attachments:;)).*?(?=\;) -->
<ResultsFileRegexPattern>(?<=(Results File: )).*.trx</ResultsFileRegexPattern>
<CoverageFileRegexPattern>(?<=(Attachments:;)).*.coverage</CoverageFileRegexPattern>
<SourceResultsFile>$([System.Text.RegularExpressions.Regex]::Match($(OutputOfExec), $(ResultsFileRegexPattern)))</SourceResultsFile>
<SourceCoverageFile Condition="$(VSTestEnableCodeCoverage)">$([System.Text.RegularExpressions.Regex]::Match($(OutputOfExec), $(CoverageFileRegexPattern)))</SourceCoverageFile>
</PropertyGroup>
<ItemGroup>
<TestArtifact Include="$(SourceResultsFile)" />
<TestArtifact Include="$(SourceCoverageFile)" />
</ItemGroup>
<Warning Condition=" '$(SourceResultsFile)' == '' " Text=".trx file not found" />
<Warning Condition=" $(VSTestEnableCodeCoverage) and '$(SourceCoverageFile)' == '' " Text=".coverage file not found" />
<!-- Copy files to the artifact directory -->
<Copy SourceFiles="#(TestArtifact)" DestinationFiles="#(TestArtifact->'$(ArtifactsPath)\$(VSTestSessionName)%(Extension)')" />
<!-- Clear the test results temporary directory -->
<RemoveDir Directories="#(TestResults)" />
<ItemGroup>
<TestFile Include="$(ArtifactsPath)\**\$(VSTestSessionName).trx" />
<CoverageFile Include="$(ArtifactsPath)\**\$(VSTestSessionName).coverage" />
</ItemGroup>
<Message Text="TestReport: #(TestFile)" />
<Message Text="CoverageReport: #(CoverageFile)" />
</Target>

Resources