TeamCity getting fxcop and coveragereport into build artifacts via artifact paths - teamcity

i'm trying to get the fxCop result xml and coveragereport.xml to publish to the artifacts after build.
the following is what I have now,
%system.teamcity.build.tempDir%/fxcop-output*/fxcop-result.xml => BuildLog/FxCop
%system.teamcity.build.tempDir%/teamcity*ncover/CoverageReport.xml => BuildLog/Coverage
but the result directory has the following format
BuildLog --> Coverage --> teamcity8681981431807223307ncover --> CoverageReport.xml
BuildLog --> FxCop --> fxcop-output-3810116228914218788 --> fxcop-result.xml
I am curious what should I do to make it like the following without the containing folder structure.
BuildLog --> Coverage --> CoverageReport.xml
BuildLog --> FxCop --> fxcop-result.xml
thanks

Because there is an asterisk (*) in the artifact source definition, there could be more than one source file grabbed by the search pattern.
To differenciate these (theoretically multiple) files in the output path, TeamCity will add the match for the * - pattern in the output structure, e.g. [...]teamcity 8681981431807223307 ncover[...]. Therefore it is impossible to select (potentially) multiple files and store them as one file.
Perhaps a different approach is the answer. You could write a MSBuild script that uses the TeamCity Build Script Interaction feature, similar to this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0">
<ItemGroup>
<FxCopResults Include="%system.teamcity.build.tempDir%/fxcop-output*/fxcop-result.xml" />
<CoverageResults Include="%system.teamcity.build.tempDir%/teamcity*ncover/CoverageReport.xml" />
</ItemGroup>
<Target Name="PublishArtifacts">
<Message Text="##teamCity[publishArtifacts '%(FxCopResults) => BuildLog\FxCop'" />
<Message Text="##teamCity[publishArtifacts '%(CoverageResults) => BuildLog\Coverage'" />
</Target>
Finally, a TeamCity Build Step with the MSBuild build runner could be used to start the msbuild target "PublishArtifacts" in this script after the analysis build steps were performed.

Related

How to build project in multiple configurations to automate the build process?

I have a solution, which contains a native project. For the main project to properly work, the following steps should be taken:
The native project has to be built in Release/x86 configuration
The native project has to be built in Release/x64 configuration
All .NET projects have to be built
Both binaries from steps 1 and 2 have to be placed in the main project's output folder.
Is there a way to configure project, so that all of those steps happen upon simply choosing "Build | Rebuild all"? I know of the batch build option, but I'd still have to execute step 4 manually.
I think you have to use msbuild script to build your project rather than VS IDE. Scripts are more flexible and can realize your requirements.
1) create a new file called build.proj and then add these on that file:
<Project>
<ItemGroup>
<!--include all c# csproj files to build these projects all at once-->
<NetProjectFile Include="**\*.csproj" />
<!--include the c++ proj files-->
<NativeProjectFile Include="**\*.vcxproj" />
</ItemGroup>
<Target Name="Build">
<MSBuild Projects="#(NetProjectFile)" Targets="Restore;Build" Properties="Configuration=Debug;Platform=AnyCPU"/>
<!--OutDir is the path of the execute file ,pdb.... if you also want the intermediate files to be in the same folder, you should also use IntDir -->
<MSBuild Projects="#(NativeProjectFile)" Targets="Build" Properties="Configuration=Release;Platform=x86;OutDir=xxx\xxx\"/>
<MSBuild Projects="#(NativeProjectFile)" Targets="Build" Properties="Configuration=Release;Platform=x64;OutDir=xxx\xxx\"/>
</Target>
</Project>
3) Just run msbuild build.proj -t:Build to get what you want.

Make visual studio build when output won't change?

In my project I have a json file I use for configuration that I have git set to ignore. When the repository is first cloned, the configuration file that is part of the project and that is copied to the output directory doesn't exist. I've gotten this to work using tasks in the 'BeforeBuild' target in the project that will copy the sample file to the actual config file if it doesn't exist.
<Target Name="BeforeBuild">
<ItemGroup>
<MySourceFiles Include="Configuration.sample.json" />
</ItemGroup>
<ItemGroup>
<MyDestinationFiles Include="Configuration.json" />
</ItemGroup>
<Message Importance="high" Condition="!Exists('#(MyDestinationFiles)')"
Text="Copying #(MySourceFiles) to #(MyDestinationFiles)" />
<Copy Condition="!Exists('#(MyDestinationFiles)')"
SourceFiles="#(MySourceFiles)"
DestinationFiles="#(MyDestinationFiles)" />
</Target>
So if I build the project, then delete the configuration file and do a build, nothing happens because no changes have been made that would change the outputs I think. Is there a way to change the project file so that a build will be flagged as necessary? It shouldn't come up very often and I can always do a 'Clean' or 'Rebuild' manually, but it's nagging at me since I'm just starting to learn MSBuild files.
From the documentation on a Target's Outputs attribute:
The files that form outputs into this target. Multiple files are
separated by semicolons. The timestamps of the files will be compared
with the timestamps of files in Inputs to determine whether the Target
is up to date
So if you add the paths to the outputfiles created by your Beforebuild target to it's Outputs attribute, at the start of every build msbuild will check if those files exist and if not it will start a build because now the project is considered to not be up-to-date anymore. In practice use:
<Target Name="BeforeBuild" Outputs="#(MyDestinationFiles)">

dll.refresh with devenv vs msbuild (Website Project, not application)

I am creating a CI server for our application(s) and have run into an issue with msbuild for our Website Project. It builds off a solution, but no proj file (as it is not a website application and cannot be). MSBuild won't pull in the dll.refresh files into the bin folder. (Not specific to a CI issue, but that's the goal) If I run it against devenv.com (CLI attempts) to build then it does pull in the dll.refresh and appears to work just fine.
From what I can find on MsBuild logs, it appears the the Copy task (which is just the default rule from msbuild itself) doesn't target the /bin folder when looking for the DLL files, but the root of the solution (/www in this case).
Just looking for some more information, as all other research points have seeming run dry at this point. (Does it have to be Msbuild? No, but I would like to make the CI configuration very simple for anyone else to re-produce and a custom build script/batch file and VS install on the CI server would make it much more complex).
Thanks.
I cannot reproduce the behavior you describe using VS2013 / MSBuild 12.0.31101.0.
Repro:
Create new website in VS
Add Reference to assembly on disk
Clean the bin directory of all files except *.refresh
Save all
Run msbuild WebsiteSolution.sln
Result: DLLs referenced in the *.refresh are re-created.
A read-through of the generated MSBuild file shows that the paths in the *.refresh files are resolved relative to the base directory of the website. I will note that this only occurs on the Build target, so I don't know what you mean when you say "the Copy task [...] is the default rule". Perhaps you are using some custom MSBuild target which needs to include the default target?
The relevant parts of the generated MSBuild (produced with MSBuildEmitSolution=1):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<!-- Edit: Snipped -->
<!-- The website location is stored relative to the .sln -->
<!-- (which is the same as the location of the temporary msbuild file) -->
<Project_[...]_AspNetPhysicalPath>..\..\WebSites\WebSite1\</Project_[...]_AspNetPhysicalPath>
<!-- Edit: Snipped -->
</PropertyGroup>
<ItemDefinitionGroup />
<!-- Edit: Snipped -->
<Target Name="Build" Condition=" ('$(CurrentSolutionConfigurationContents)' != '') and (false or ( ('$(Configuration)' == 'Debug') and ('$(Platform)' == 'Any CPU') ) or ( ('$(Configuration)' == 'Release') and ('$(Platform)' == 'Any CPU') )) " DependsOnTargets="GetFrameworkPathAndRedistList">
<!-- Edit: Snipped -->
<!-- *.refresh items are discovered and saved in [...]_References_RefreshFile -->
<CreateItem Include="$(Project_[...]_AspNetPhysicalPath)\Bin\*.refresh">
<Output TaskParameter="Include" ItemName="Project_[...]_References_RefreshFile" />
</CreateItem>
<!-- The contents of the *.refresh are read to [...]_References_ReferenceRelPath -->
<ReadLinesFromFile Condition=" '%(Project_[...]_References_RefreshFile.Identity)' != '' " File="%(Project_[...]_References_RefreshFile.Identity)">
<Output TaskParameter="Lines" ItemName="Project_[...]_References_ReferenceRelPath" />
</ReadLinesFromFile>
<!-- Those contents are relative to [...]_AspNetPhysicalPath -->
<CombinePath BasePath="$(Project_[...]_AspNetPhysicalPath)" Paths="#(Project_[...]_References_ReferenceRelPath)">
<Output TaskParameter="CombinedPaths" ItemName="Project_[...]_References" />
</CombinePath>
<!-- This seems to be a no-op, since you cannot copy if it doesn't exist -->
<Copy Condition="!Exists('%(Project_[...]_References.Identity)')" ContinueOnError="true" SourceFiles="#(Project_[...]_References->'%(FullPath)')" DestinationFolder="$(Project_[...]_AspNetPhysicalPath)\Bin\" />
<!-- Edit: Snipped -->
<!-- This will copy [...]_References to [...]_References_CopyLocalFiles and add references -->
<ResolveAssemblyReference Condition="Exists('%(Project_[...]_References.Identity)')" Assemblies="#(Project_[...]_References->'%(FullPath)')" TargetFrameworkDirectories="$(Project_[...]__TargetFrameworkDirectories)" FullFrameworkFolders="$(Project_[...]__FullFrameworkReferenceAssemblyPaths)" SearchPaths="{RawFileName};{TargetFrameworkDirectory};{GAC}" FindDependencies="true" FindSatellites="true" FindSerializationAssemblies="true" FindRelatedFiles="true" TargetFrameworkMoniker=".NETFramework,Version=v4.5">
<Output TaskParameter="CopyLocalFiles" ItemName="Project_[...]_References_CopyLocalFiles" />
</ResolveAssemblyReference>
<!-- [...]_References_CopyLocalFiles is copied to the bin directory -->
<Copy Condition="(false) or ('$(AspNetConfiguration)' == 'Debug') or ('$(AspNetConfiguration)' == 'Release')" SourceFiles="#(Project_[...]_References_CopyLocalFiles)" DestinationFiles="#(Project_[...]_References_CopyLocalFiles->'$(Project_[...]_AspNetPhysicalPath)\Bin\%(DestinationSubDirectory)%(Filename)%(Extension)')" />
<!-- Edit: Snipped -->
</Target>
<!-- Edit: Snipped -->
</Project>
I have not tried this on a machine which does not have VS installed, so it may not apply directly, but you should definitely be able to build with the generated metaproj file even without Visual Studio installed.
I had this problem as well; the problem was actually that our build configuration was neither Debug nor Release, so msbuild was actually skipping the compile (and thus the restore with *.refresh):
Skipping because the "Dev" configuration is not supported for this web
project. You can use the AspNetConfiguration property to override the
configuration used for building web projects, by adding
/p:AspNetConfiguration= to the command line. Currently web
projects only support Debug and Release configurations.

Using SlowCheetah's app.config transformations with Setup projects

I'm using the SlowCheetah XML Transforms extension to handle web.config-like transformations with app.config. That part works great.
I added a setup project and configured it to include the project output of the first project. I noticed that when I ran the installer, it installed the non-transformed app.config. Looking at the Primary output Outputs (say that 10 times fast), I noticed that its finding the binary in Project\bin\Debug\Project.exe, but Project.exe.config comes from Project\app.config instead of Project\bin\Debug\Project.exe.config.
I could exclude app.config from the Primary output, and hard-code the path to a specific configuration's app.config (Project\bin\Debug\Project.exe.config), but then I'd get the same app.config regardless of which configuration I used to build it.
Is there a workaround for getting the appropriate transformed app.config in a Setup project?
Hi we are planning on releasing a new version which has ClickOnce support in the next few days. If you need a build of the add in before than which has the fix please contact me and I can get that out to you.
This may not be exactly the answer you're looking for but I have previously wrestled with how to get the correct app.config file into a setup project. I have a TFSBuild.proj msbuild file that uses transforms. The SlowCheetah transforms I think use the same msbuild task but I may be incorrect. SlowCheetah certainly provides a more useful user experience when working with transform files. My build file takes a slightly different approach. At the end of the automated build I wanted to generate installers for each of the target deployment environments. I use a number of msbuild extensions, including the TransformXml build task - not all required for the following but FWIW these are the imports:
<!-- import extensions -->
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>
I have the following environments defined:
<ItemGroup>
<!-- target deployment environments -->
<Configs Include="Prod" />
<Configs Include="Staging" />
<Configs Include="Test" />
</ItemGroup>
Then the standard AfterCompileSolution target contains a call to the target that generates the installer for each environment:
<Target Name="AfterCompileSolution">
<!-- Create installers for target deployment environments -->
<CallTarget Targets="MyProject" />
</Target>
<Target Name="MyProject" Outputs="%(Configs.Identity)">
<ItemGroup>
<MyProjectTempConfig Include="$(SolutionRoot)\MyProjectService\Temp.config" />
<MyProjectConfigFrom Include="$(SolutionRoot)\MyProjectService\App.%(Configs.Identity).config" />
<MyProjectConfigTo Include="$(SolutionRoot)\MyProjectService\App.config">
<Attributes>ReadOnly</Attributes>
</MyProjectConfigTo>
</ItemGroup>
<Message Text="MyProject - Target environment: %(Configs.Identity)" />
<!-- transform app.config using appropriate -->
<Copy SourceFiles="#(MyProjectConfigTo)"
DestinationFiles="#(MyProjectTempConfig)"
OverwriteReadOnlyFiles="true"
ContinueOnError="true"
Condition="!Exists(#(MyProjectTempConfig))"/>
<File TaskAction="RemoveAttributes" Files="#(MyProjectConfigTo)"/>
<TransformXml Source="#(MyProjectTempConfig)"
Transform="#(MyProjectConfigFrom)"
Destination="#(MyProjectConfigTo)" />
<!-- run setup -->
<Exec Command=""$(ProgramFiles)\Microsoft Visual Studio 10.0\Common7\IDE\devenv" "$(SolutionRoot)\MyProject.sln" /build Release /project MyProjectService.Setup"/>
<!-- rename output for target deployment environment -->
<Copy SourceFiles="$(SolutionRoot)\MyProjectService.Setup\Release\MyProjectService.msi"
DestinationFiles="$(OutDir)\%(Configs.Identity)_MyProjectService.msi"
OverwriteReadOnlyFiles="true"
ContinueOnError="true"/>
</Target>

run MsBuild tasks (targets?) after the solution is built?

Since this question seems to have baffled / underwhelmed SO I will rephrase it with a partially formed idea of my own.
Could I somehow set up a batch file or something that runs after the whole solution is built, and this batch file would call msbuild to build specific targets inside a certain project? In order for it to work, I would have to somehow force msbuild build the target without regard to whether it thinks it's "up to date", because that is the core issue I'm butting up against.
Since you are dealing with building specifically you may want to replace your batch file with an MSBuild file. For example:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<SolutionsToBuild Include="MySolution.sln"/>
<Projects Include="Proj1.csproj"/>
<Projects Include="Proj2.csproj"/>
<Projects Include="Proj3.csproj"/>
</ItemGroup>
<Target Name="BuildAll">
<!-- Just executes the DefaultTargets (Build) -->
<MSBuild Projects="#(SolutionsToBuild)"/>
<!-- Call Rebuild if you think its not building correctly -->
<MSBuild Projects="#(Projects)"
Targets="Rebuild"/>
</Target>
</Project>
Then you just invoke msbuild.exe on this file with:
msbuild.exe Build.proj /t:BuildAll
Since you said that you want to build specific projects after the solution is built just put those into the Projects ItemGroup as shown and use the MSBuild task to build them after the solution has been built. I've specified the Rebuild target to make sure you get a clean build.

Resources