How can we display a "step" inside Visual Studio build process? - visual-studio

When you are monitoring the TFS build from Visual Studio (2008 or 2005), you can see where it is up to.
The issue is that I have some Post-Build custom steps I would like the developer to be able to see directly throught the UI. Those steps take some times and we can also get a "timing" of the build step.
Any idea how to have it displayed?

This is the pattern that I normally use for adding steps to the build report in TFS 2008. (See http://code.msdn.microsoft.com/buildwallboard/ for the full example that I usually use in my Team Build talks)
Basically, the magic is that there is a custom task provided for you in TFS2008 called "BuildStep". Here is the section where I generate and MSI installer and build the appropriate build steps in the report:
<Target Name="PackageBinaries">
<!-- create the build step -->
<BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
Message="Creating Installer"
Condition=" '$(IsDesktopBuild)' != 'true' " >
<Output TaskParameter="Id"
PropertyName="InstallerStepId" />
</BuildStep>
<!-- Create the MSI file using WiX -->
<MSBuild Projects="$(SolutionRoot)\SetupProject\wallboard.wixproj"
Properties="BinariesSource=$(OutDir);PublishDir=$(BinariesRoot);Configuration=%(ConfigurationToBuild.FlavourToBuild)" >
</MSBuild>
<!-- If we sucessfully built the installer, tell TFS -->
<BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
Id="$(InstallerStepId)"
Status="Succeeded"
Condition=" '$(IsDesktopBuild)' != 'true' " />
<!-- Note that the condition above means that we do not talk to TFS when doing a Desktop Build -->
<!-- If we error during this step, then tell TFS we failed-->
<OnError ExecuteTargets="MarkInstallerFailed" />
</Target>
<Target Name="MarkInstallerFailed">
<!-- Called by the PackageBinaries method if creating the installer fails -->
<BuildStep TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
Id="$(InstallerStepId)"
Status="Failed"
Condition=" '$(IsDesktopBuild)' != 'true' " />
</Target>
So initially, I create the build step and save the Id of the step in a propery called InstallerStepId. After I have performed my task, I set the status of that step to Succeeded. If any errors occur during the step then I set the status of that step to Failed.
Good luck,
Martin.

Note that in #Martin Woodward's great example, PackageBinaries is one of the existing TFS build targets. If you want to use your own targets, you can use the CallTarget task to call them from one of the known targets, e.g.,
<Target Name="AfterDropBuild">
<CallTarget Targets="CreateDelivery"/>
<CallTarget Targets="CreateInventory"/>
</Target>
Then in your targets (e.g., CreateDelivery) use the BuildStep task as per Martin's example.

Related

Trick to run different pre/post build events when building with MSBuild or from Visual Studio IDE

Don't ask me why, but does anyone know any trick to put in the pre/post build event command that will run different commands if the project is being built from command line with MSBuild or from inside the Visual Studio IDE?
The easiest solution would be to define build targets that are conditioned on the $(BuildingInVisualStudio) property that visual studio sets to true when buildinging.
<Target Name="SpecialPreBuild" BeforeTargets="BeforeBuild" Condition="'$(BuildingInVisualStudio)' != 'true'">
<Exec Command="some-command.exe --magic" />
<Copy SourceFiles="foo.txt" DestinationFolder="bin\$(Configuration)\bar" />
</Target>
<Target Name="SpecialPostBuild" AfterTargets="AfterBuild" Condition="'$(BuildingInVisualStudio)' != 'true'">
<Exec Command="some-other-command.exe --magic" />
</Target>
If you want to skip these targets in other IDEs / editors as well, you could introduce a custom property as well and change the Condition attributes above to
Condition="'$(PerformSpecialLogic)' == 'true'"
That way no "default" builds will execute these targets and you could build with the following arguments in your build script / CI definition:
msbuild /p:PerformSpecialLogic=true

Sequentially build configurations in Visual Studio without MSBuild or plugins?

MSDN describes how to create a batch build, but does not provide a way to automate different batches (and one click solution for the GUI)
This question describes conditionally invoking a second build but doesn't appear to suffice for more than two sequential configurations
This question addresses the same situation, but again only for two configurations
In my test case, each configuration:
defines its own MACROS (which impact source code)
is applicable to multiple projects (class libraries). The projects are interdependent and require a specific build order in the context of the current configuration
I would like visual studio to build multiple configurations sequentially with a single build command.
Can child configurations be nested under a parent configuration, and be executed sequentially by visual studio when the parent configuration is built?
UPDATE : ATTEMPTED SOLUTION 1 [2016-03-11]
In response to Stijn's suggested answer I've tried the following:
Setup DotNetFramework 4.5 WinForms solution with 3 test projects and with 6 Configurations:
CORE_DEBUG
CORE_RELEASE
EXTENDED_DEBUG
EXTENDED_RELEASE
Debug
Release
The Debug Configuration must:
NOT trigger it's own configuration build (i.e. 'Debug')
must trigger the CORE_DEBUG and EXTENDED_DEBUG Configurations in sequence
I've added the following modified target to the first project's project file:
<Target Name="AfterBuild" Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
Building with the 'Debug' Configuration now, causes an EXTENDED_RELEASE build to trigger. Having a look at the solution file, I see that Visual Studio decided to automatically link 'Debug' to 'EXTENDED_RELEASE':
{4F9706AA-26A9-483C-81C4-22E301C54C89}.Debug|Any CPU.ActiveCfg = EXTENDED_RELEASE|Any CPU
{4F9706AA-26A9-483C-81C4-22E301C54C89}.Debug|Any CPU.Build.0 = EXTENDED_RELEASE|Any CPU
Removing the above two lines from the solution file doesn't help, since Visual Studio just regenerates them. In summary this now has two undesirable outcomes:
Visual Studio executes a 'Debug' build for Project1
Visual Studio then executes an 'EXTENDED_RELEASE' for Project2 and Project3
Conclusion: While this approach can work, it also (first) performs debug and release configuration builds respectively. Visual Studio
also lists all 6 Configurations in the build menu (we only want Debug
and Release to be visible, and behind the scenes Debug must trigger
CORE_DEBUG and EXTENDED_DEBUG, and Release must trigger CORE_RELEASE
and EXTENDED_RELEASE)
UPDATE : ATTEMPTED SOLUTION 2 [2016-03-16]
Moving on to a makefile project solution: I've created a makefile project as specified by stijn's answer below, and it worked perfectly!
Conclusion : This is the preferred solution in my opinion because it gives the user the most power and ability to control exactly how the build(s) must be executed and how the configurations must be handled.
The principle of the second SO question can be adjusted to build more than one configuration/platform sequentially by just invoking MsBuild multiple times. For instance:
<Target Name="AfterBuild" Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<MSBuild Projects="$(MySolution)" Properties="Configuration=Release;Platform=x86"/>
<MSBuild Projects="$(MySolution)" Properties="Configuration=Debug;Platform=x64"/>
<MSBuild Projects="$(MySolution)" Properties="Configuration=Release;Platform=x64"/>
</Target>
This can be cleaned up by using item batching, removing the condition and instead automatically determining which config is invoked and then only building the others etc but that's a bit out of scope here.
I'm not really convinced doing this in an AfterBuild target is the best way though, because then you'd need to adjust one of your 'normal' projects to also trigger a build of everything else. An alternative is to add a MakeFile Project to your solution, set up it's dependencies so that it comes last in the build order (at least if that is what you need), and set it's command line to invoke msbuild in a way similar as described above. You can even keep all logic in the same project file: set the 'Build Command Line' to
msbuild $(MsBuildThisFile) /t:CustomBuild /p:Configuration=$(Configuration);Platform=$(Platform)
so building the project will 'recurse' and make it call itself again with the same properties as called with by VS, but executing the CustomBuild target where you can then build your other projects/solutions to taste.
EDIT re: update
You're almost there, but you have to go to Configuration Manager and make sure the configurations are setup properly to begin with. From the start:
create new solution, add 3 projects
right-click solution, select Configuration Manager
in the Active solution configuration combobox select new
enter CORE_DEBUG for name, select DEBUG under Copy settings from and make sure the Create new project configurations is checked like
repeat for other configurations
for EXTENDED_RELEASE for instance, it should now look like
you probably did most of this already, but somehow Debug got assigned to EXTENDED_RELEASE somehow so that is one thing you should fix; you could do that by editing the solution manually but instead of removing lines you'd have to edit them to be correct else VS just adds them again, as you noticed
Now open first project in a text editor and near the end of the file where AfterBuild is already inserted but commented out, add
<ItemGroup>
<Configurations Condition="'$(Configuration)'=='Debug'" Include="CORE_DEBUG;EXTENDED_DEBUG" />
<Configurations Condition="'$(Configuration)'=='Release'" Include="CORE_RELEASE;EXTENDED_RELEASE" />
<Projects Include="$(SolutionDir)WindowsFormsApplication1.csproj;$(SolutionDir)WindowsFormsApplication2.csproj;$(SolutionDir)WindowsFormsApplication3.csproj" />
</ItemGroup>
<Target Name="AfterBuild" Condition="'#(Configurations)' != ''">
<Message Text="Projects=#(Projects) Configuration=%(Configurations.Identity)" />
<MSBuild Projects="#(Projects)" Targets="Build" Properties="Configuration=%(Configurations.Identity)" />
</Target>
you might need to adjust the paths to the projects. This will build CORE_DEBUG and EXTENDED_DEBUG for Debug builds, and likewise for Release builds. AfterBuild is skipped when the Configurations ItemGroup is empty, i.e. when not building Debug or Release which is exactly the point.
EDIT re: makefile
You can specify multiple commands for the makefile commandline. Click the arrow next to the 'Build Command Line' box and select '' To be sure you have everything right, Configuration Manager has to be set up to only build the makefile project for Debug/Release like:
and the makefile project's commandline looks like
Alternatively, and I'd prefer this myself, you create an msbuild file with the same content as above:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Configurations Condition="'$(Configuration)'=='Debug'" Include="CORE_DEBUG;EXTENDED_DEBUG" />
<Configurations Condition="'$(Configuration)'=='Release'" Include="CORE_RELEASE;EXTENDED_RELEASE" />
<Projects Include="$(SolutionDir)WindowsFormsApplication1.csproj;$(SolutionDir)WindowsFormsApplication2.csproj;$(SolutionDir)WindowsFormsApplication3.csproj" />
</ItemGroup>
<Target Name="Build" Condition="'#(Configurations)' != ''">
<Message Text="Projects=#(Projects) Configuration=%(Configurations.Identity)" />
<MSBuild Projects="#(Projects)" Targets="Build" Properties="Configuration=%(Configurations.Identity)" />
</Target>
</Project>
and your makefile command then invokes that file like
msbuild /path/to/msbuildfile /t:Build /p:Configuration=Debug;SolutionDir=$(SolutionDir)

Using specific Visual Studio Project Build configuration for running unit tests

My company already has a Team Foundation Server as a Continuous Integration platform. However, what I am looking to setup is a build configuration that a developer can run on their own development machine.
Let's say I have a Visual Studio solution that contains a .NET C# Class Library project (I'll call this the Library Project). It also contains another project containing the Unit Testing classes for Library Project (I'll call this the Testing Project).
I have the normal Debug and Release build configurations for each project and at the solution level. For both of these configurations, I have set it to only build the Library Project (so Testing Project does not get built).
What I would like to do is set up 2 new build configurations called Debug With Testing and Release With Testing. They will each be the same as the Debug and Release, respectively but I need them to have the following extra features:
Builds the Testing Project.
Run all test cases in the Testing Project.
Run Code Analysis on Library Project.
Generate report for testing and code analysis.
Save report in a specific location.
Doing item 1 is easy. However, I can't figure out how to do items 2 to 5. Can anyone point me in the right direction?
Any help will be greatly appreciated. TIA
You will need to write custom MS build code, I already do some similar task as the following:
Get the latest change from TFS
Build the solution including all projects
Deploy the Main Database locally
Deploy the Test Database locally which hold the test data used in the
data driven test
Run the sanity test or BVT (Build Verification Test) which has
belong to category 1 (Test the integration between DB and code)
Check-in the pending change
And hear the code of this tasks
<Target Name="GetLatestFromTFS2010" AfterTargets="build" >
<Message Importance="high" Text ="start GetLatest for the project "></Message>
<Exec Command='"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe" get $/AutoDBand/AutomateDatabaseAndTest/AutomateDatabaseAndTest /recursive /login:YourUsername,YourPassword' ContinueOnError='false'/>
</Target>
<!--===========Deploy Database============-->
<Target Name="DeployDatabase" AfterTargets="GetLatestFromTFS2010" Condition="'$(Configuration)' == 'DebugForCheck-in'">
<Message Importance="high" Text="-------------------------------- Deploying Database according to the connection string -------------------------------- " />
<Message Importance="high" Text=" "/>
<MSBuild Projects="..\DB\DB.dbproj" Targets="Build;Deploy" />
</Target>
<!--============Run the Test==================-->
<Target Name="UnitTests" AfterTargets="DeployDatabase" Condition="'$(Configuration)' == 'DebugForCheck-in'">
<Message Importance="high" Text="-------------------------------- Running Unit Tests for category 1 only--------------------------------" />
<Message Importance="high" Text=" "/>
<Exec Command='"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\mstest.exe" /testcontainer:"..\BLTest\bin\Debug\BLTest.dll" /category:cat1' />
</Target>
<Target Name="Chekin-pendingChange" AfterTargets="UnitTests" >
<Message Importance="high" Text ="-------------------------------- start Check-in process-------------------------------- "></Message>
<Message Importance="high" Text=" "/>
<Exec Command='"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\TF.exe" checkin $/AutoDBand/AutomateDatabaseAndTest/AutomateDatabaseAndTest /recursive /login:YourUsername,YourPassword' ContinueOnError='false'/>
</Target>
For more information you can see this article with source code
http://mohamedradwan.wordpress.com/2010/11/13/automate-the-best-practice-for-check-in-including-get-latest-deploy-db-run-test-check-in/
Have a look at something like:
TeamCity
Jenkins
Team Foundation Server
all are Continous Integration Servers, which are good in doing the jobs you like to have done.

MSBuild "Debug" configuration not working in VS 2010 Beta 2

I'm trying to set up my environment for developing, debugging and deploying Windows Desktop Gadgets. I've hit a bit of a roadblock in my project, where I can't run a build on my gadget when the configuration is set to "Debug". If the configuration is set to "Release", the build goes through the following custom tasks:
Copy gadget contents to a seperate folder.
Minify/obfuscate the javascript files, removing comments and whitespace.
Package the files into a CAB file.
Sign the CAB file with a digital certificate.
This runs just fine, my "Debug" configuration has the following tasks defined
Copy gadget folder to AppData\Local\Microsoft\Windows Sidebar\Gadgets\.
Start the gadget using the IDesktopGadget interface.
If I copy those two tasks to the "Release" configuration, they run just fine - no problems whatsoever. I've tried creating a seperate configuration called "Test", copied from the "Release" configuration.
If I try to build any configuration other than "Release", I get an instant message saying "Build succeeded" but no tasks have run at all.
EDIT: I've started a bounty because I still have the same problem with VS 2010 RC and it's very frustrating.
FURTHER EDIT:
Thanks to John I was able to debug the build process. It led me to realize that the <Target> element with condition for debugging was being completely ignored (not even processed). When I swapped the position of my <Target> elements, it worked:
<Target Name="Build" Condition="'$(Configuration)' == 'Release'">
<!--
<Obfuscate PathToJasob="C:\Program Files (x86)\Jasob.com\Jasob 3.5" Path="$(GadgetFolder)" Output="$(GadgetName)_obf" log="jasob_log.txt" />
-->
<BuildGadget BuildFormat="CAB" Path="$(GadgetFolder)" Target="$(GadgetName).gadget" />
<SignGadget CertName="Cert1" TimestampURL="http://timestamp.comodoca.com/authenticode" Target="$(GadgetName).gadget" />
</Target>
<Target Name="Build" Condition="'$(Configuration)' == 'Debug'">
<CopyToGadgets GadgetFolder="$(GadgetFolder)" GadgetName="$(GadgetName)" />
<RunGadget GadgetName="$(GadgetName)" />
</Target>
So it looks like the second <Target Name="Build"> element overrides the first, despite the Condition attribute being present. What can I do?
As Joe suggests:
Change your output path like this, and see if that fixes the issue:
<OutputPath>bin\Debug\</OutputPath>
Update
Have you tried running msbuild /verbosity:diagnostic ?
Can you try that and show the output?
Second Update
Make one target 'build', and then make two tasks in that target:
<Target Name="Build">
<CallTarget Targets="BuildRelease" Condition="'$(Configuration)' == 'Release'" />
<CallTarget Targets="BuildDebug" Condition="'$(Configuration)' == 'Debug'" />
</Target>
<Target Name="BuildRelease">
<!--
<Obfuscate PathToJasob="C:\Program Files (x86)\Jasob.com\Jasob 3.5" Path="$(GadgetFolder)" Output="$(GadgetName)_obf" log="jasob_log.txt" />
-->
<BuildGadget BuildFormat="CAB" Path="$(GadgetFolder)" Target="$(GadgetName).gadget" />
<SignGadget CertName="Cert1" TimestampURL="http://timestamp.comodoca.com/authenticode" Target="$(GadgetName).gadget" />
</Target>
<Target Name="BuildDebug">
<CopyToGadgets GadgetFolder="$(GadgetFolder)" GadgetName="$(GadgetName)" />
<RunGadget GadgetName="$(GadgetName)" />
</Target>
Just a guess:
Your Debug build has its output path set to bin\Release\.
The timestamps of the files in bin\Release\ are probably causing MSBuild to conclude that the debug build is already up to date. Try changing the the output path to bin\Debug\ for debug builds.

Publish ClickOnce from the command line

Is there a way to have Visual Studio 2008 execute the "Publish Now" button from the command line?
I've seen posts that suggest to use msbuild /target:publish to call it. That is OK, but MSBuild doesn't increment the revision number. I'm hoping for something like:
devenv mysolution.sln /publish
To increment build numbers, I am using MSBuild Extension pack inside my .csproj file as follows:
<Target Name="BeforeBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release-VersionIncrement|AnyCPU' ">
<CallTarget Targets="CleanAppBinFolder" />
<MSBuild.ExtensionPack.VisualStudio.TfsSource TaskAction="Checkout" ItemCol="#(AssemblyInfoFiles)" WorkingDirectory="C:\inetpub\wwwroot\MySolution" ContinueOnError="true" />
<!-- Microsoft's task that goes over assembly files and increments revision number. -->
<MSBuild.ExtensionPack.Framework.AssemblyInfo Condition="'$(Optimize)'=='True' " AssemblyInfoFiles="#(AssemblyInfoFiles)" AssemblyRevisionType="AutoIncrement" AssemblyFileRevisionType="AutoIncrement">
<Output TaskParameter="MaxAssemblyVersion" PropertyName="MaxAssemblyVersion" />
</MSBuild.ExtensionPack.Framework.AssemblyInfo>
<Message Text="----current version---: '$(MaxAssemblyVersion)'" />
</Target>
This way, anytime the configuration is set to Release-VersionIncrement, the version number is changed. When this is done, I can use the following MSBuild command to publish it:
msbuild c:\projects\MyProject.csproj
/t:ResolveReferences;_CopyWebApplication
/p:Configuration=Release;BuildingProject=true;WebProjectOutputDir=c:\inetpub\wwwroot\OutputProject\MyProjectOutput;OutDir=c:\inetpub\wwwroot\OutputProject\MyProjectOutput
Note that this is for an ASP.NET 3.5 web application.

Resources