Clean/Full Rebuild of a project every night in CruiseControl.NET - msbuild

I've set up some rather large C++ projects to do integration builds in CruiseControl.NET, using MSBuild.
Now I'd like to schedule a complete Clean of the working directory once a night. How can I do that with CC.NET ?

You can create a project that cleans your working directory at specified time.
<project name="CleanWorkingDir">
<triggers>
<scheduleTrigger time="23:30" buildCondition="ForceBuild" name="Scheduled"/>
</triggers>
<tasks>
<exec executable="c:\projects\myproject\build.bat"/>
</tasks>
</project>

Use the clean copy on the source control block, everything is already done for you. All you have to do is set it to true. If you really just want a project to clean that directory, then don't have any build tasks. However, as a matter of good release engineering you really should use cleancopy with all your individual builds. Otherwise, you cnanot be sure the build would work on an absolutely clean machine.

We created a script that deletes everything in the source directory and placed it in the prebuild step:
<prebuild>
<exec>
<executable>Clean_Source.bat</executable>
<baseDirectory>SourceDir</baseDirectory>
</exec>
</prebuild>

Related

How to change msbuild working directory in TFS 2013 workflow

I have a TFS 2013 build xaml workflow, that eventually calls the Microsoft.TeamFoundation.Build.Workflow.Activities.MSBuild activity once for each solution that I want to build. When msbuild.exe is called, it's working directory is the working directory of the current solution being built. I can see this through the 'MSBuildStartupDirectory' property when running msbuild with a 'diagnostic' verbosity.
Unfortunately, I need the working of msbuild.exe to be somewhere else when msbuild.exe starts. This is because I use the MSBuild SonarQube runner that imposes constraints on the directory from which msbuild is called.
I have looked at the 'msbuild' activity and there is no way to control the working directory. Is there another way to control the working directory of this activity?
Its been a while since I edited a build process template but I believe you could use an activity that just executes a command in CMD and provide the full MSBuild command. I'm sure there are tons of variables you will need to setup for this to work.
Instead of editing the build process template have you considered using a PowerShell script in the Post-build script to execute SonarQube?
I still haven't found any way to control the working directory of msbuild. But since I know that the working directory will be the directory of the project being built by msbuild, I created a new proj file at the root of my workspace (where my working directory has to be) and only build this new proj file from my workflow. This new proj file then builds all my other solutions. That way, my working directory is the same for all the solutions being built.
Here is an example of my top level proj file:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<ItemGroup>
<Solutions Include="**\*.sln"/>
</ItemGroup>
<Target Name="Build">
<MSBuild Projects="#(Solutions)" Targets="Build"/>
</Target>
</Project>
But beware that doing this may affect the output directory (OutDir) given to each solution. So you may want to do something like this:
<MSBuild Projects="#(Solutions)" Targets="Build" Properties="OutDir=$(OutDir)..\%(Solutions.Filename)"/>

MSbuild style cop extensions task to run on solution

I need help in running stylecop task on all cs files included in solution.
Please let me know if its possible and how?
Right now I can run it on a file, but not on solution.
<CreateItem Include="$(RootPath)\**\*.cs">
<Output TaskParameter="Include" ItemName="StyleCopFiles"/>
</CreateItem>
<MSBuild.ExtensionPack.CodeQuality.StyleCop
TaskAction="Scan"
ShowOutput="true"
ForceFullAnalysis="true"
CacheResults="false"
SourceFiles="#(StyleCopFiles)"
logFile="$(OutDir)\StyleCopLog.txt"
SettingsFile="$(MSBuildStartupDirectory)\..\Settings.StyleCop"
ContinueOnError="false">
<Output TaskParameter="Succeeded" PropertyName="AllPassed"/>
<Output TaskParameter="ViolationCount" PropertyName="Violations"/>
<Output TaskParameter="FailedFiles" ItemName="Failures"/>
</MSBuild.ExtensionPack.CodeQuality.StyleCop>
Have you considered automatically running StyleCop rules as a part of your project build process? This won't run all rules at the solution level but at a project level. I prefer this approach because the rules will run whenever you build your project/solution and will display as Warnings in the Error List panel (double click to navigate to the offending line of code). Configuring this on a project by project basis may seem like a pain but we have a different set of StyleCop rules for our Unit Test projects, and this allows us to configure them individually.
Also, You won't have to explicitly add a MSBuild task to your build script because building the projects will automatically execute the StyleCop rules.
It's also worth noting that I'm using the NuGet Package: StyleCop.MSBuild (version 4.7.17.1) and using a relative path to reference the package from within my .csproj file like this:
<Project>
<Import Project="..\Packages\StyleCop.MSBuild.4.7.17.1\tools\StyleCop.targets" />
</Project>
http://stylecop.codeplex.com/wikipage?title=Running%20StyleCop%20in%20VS2005%20or%20VS%20Express&referringTitle=Documentation
You can also set conditions on when you want the rules to run. If the condition evaluates to false StyleCop will not run. We use the condition to suppress StyleCop when running Unit Tests
<Project>
<Import Project="..\Packages\StyleCop.MSBuild.4.7.17.1\tools\StyleCop.targets" Condition="'$(NCrunch)'!='1'" />
</Project>
In order to configure StyleCop rules, you will need to install StyleCop_v4.7.17.0.msi. We only define a single Settings.StyleCop file (Parent Settings File) for our entire codebase.
http://stylecop.codeplex.com/wikipage?title=Sharing%20StyleCop%20Settings%20Across%20Projects&referringTitle=Documentation

Make a target run once at the Solution level in MSBuild

I need a set of tasks that need to be executed exactly once for the entire solution. This will run tasks that will modify each project to run a separate set of tasks for each project. We had done this earlier using a separate project to the solution which had the solution level tasks, but we want to move away from that. Has anyone done this or does anyone have any suggestions on how to implement this?
Since Solution files are not in MSBuild format they are not easily extended or customized. If you want more control over the build process you would have to create a "driver" msbuild file which would replace your solution file. Inside this driver file you would build all the projects that you needed and perform some additional tasks. You would do this using the MSBuild task. Here is a sample showing how to build more than 1 project.
<Project ...>
<ItemGroup>
<Projects Include="proj01.csproj"/>
<Projects Include="proj02.csproj"/>
<Projects Include="proj03.csproj"/>
</ItemGroup>
<Target Name="BuildAll">
<MSBuild Projects="#(Projects)" BuildInParallel="true" />
</Target>
</Project>
So in your case you would just execute the tasks before you build the projects. Also note that I specified the value true for the BuildInParallel indicating that MSBuild can try and build more than one project at once.
An alternative solution is to have a single target that dispatches to an MSBuild invoked target with as many Global properties removed as possible. My team have a target in the InitialTargets of a Directory.Build.props Import'ed props file - something like:
<Target Name="Prebuild">
<MSBuild Projects="$(MSBuildThisFileFullPath)"
Targets="PrebuildWorker"
RemoveProperties="Configuration;Platform;TargetFramework;BuildProjectReferences" />
</Target>
Since MSBuild appears to synchronize parallel builds on the {project file, global properties, target} set, then by removing all of the properties you can synchronize the build and run it once for all projects being built. The downside: you have to maintain the RemoveProperties attribute - MSBuild doesn't have a way to remove all global properties. If something in the build issues a new MSBuild task with a custom property specified, then you'll get a second instance of the Target invoked.
And - of course - your build will be synchronized on this target. You could try hooking the target up by setting, say, CompileDependsOn to depend on the Prebuild target, to allow independent progress in the build. But to have the target run early and ubiquitously using InitialTargets seems like the better option.

MSBuild speedup: how to remove unnecessary project builds?

I have a solution with several projects in it. Let's say
project A depends on projects B and C
project B depends on project C
When I run my solution on the local machine VS builds each project once and it takes 1 minute. However, on our build machine it takes about 4 minutes to build and, as I can understand from the MSBuild logs it goes like this:
build A -> build B for A, build C for A
build B -> build C for B
So it builds some projects several times... How can I speed up the build process?
P.S. It's not a question of 3 extra minutes, I just wonder why is it so different from my local machine build?
I am not sure about your build order. Sometimes TeamBuild can look like it is building projects over and over but it is building for different configurations. Take a look and make sure you have not defined multiple FlavorsToBuild.
Also, if you don't want to do a fresh check out and rebuild every time, you can define this at the bottom of your TFSBuild file.
<PropertyGroup>
<IncrementalBuild>true</IncrementalBuild>
</PropertyGroup>-->
Put that right before the </Project> tag.
This sample seems to work for me. TestLib.Extra depends on TestLib. If I change something in TestLib, both projects will build. If I change only in TestLib.Extra, only that one will build, and if I don't change anything at all, they will just report Skipping target "CoreCompile" because all output files are up-to-date and so on.
<Target Name="Build">
<MSBuild Targets="Build" Projects="TestLib\TestLib.csproj" />
<MSBuild Targets="Build" Projects="TestLib.Extra\TestLib.Extra.csproj" />
</Target>
The trick is to use the "Build" target of the projects, rather than "Rebuild". The difference between these is essentially the same as the difference between the "Build" and "Rebuild" commands in the build menu in Visual Studio.
Edit
This works well also if the projects are included in a solution file, and you specify the solution to build instead:
<Target Name="Build">
<MSBuild Targets="Build" Projects="TestLib.sln" />
</Target>
Maybe like our's, your build server is a virtual machine (10x at least slower).
Also TFS (and maybe others), does a fresh checkout on build, so it will have to build all the projects regardless.
Are you using the /maxcpucount switch? There may be a difference in number of processors between your local machine and the build machine. This setting can also be different between your msbuild file and the visual studio setting which could also explain the difference you're seeing in build times.
I do this as follows. It is somewhat complicated custom build system but the basic idea is.
The dlls which are reused in many solutions are build to a known folder. This is achieved my using a msbuild project file that builds these common dlls.
When building other csproj files in a solution we copy the csproj files then use xslt manipulation to replace the project references with dll refernces for those common dlls.
The build scripts then build these changed csproj files using custom msbuild project files we maintain corresponding to each solutions. We don't build .sln files. These custom project files is a itemgroup of .csproj files in correct dependency order.
Maybe this can help you in achieving what you want.

How can you publish a ClickOnce application through CruiseControl.NET?

I have CruiseControl.NET Version 1.4 set up on my development server. Whenever a developer checks in code, it makes a compile.
Now we're at a place where we can start giving our application to the testers. We'd like to use ClickOnce to distribute the application, with the idea being that when a tester goes to test the application, they have the latest build.
I can't find a way to make that happen with CruiseControl.NET. We're using MSBUILD to perform the builds.
We've done this and can give you some pointers to start.
2 things you should be aware of:
MSBuild can generate the necessary deployment files for you.
MSBuild won't deploy the files to the FTP or UNC share. You'll need a separate step for this.
To use MSBuild to generate the ClickOnce manifests, here's the command you'll need to issue:
msbuild /target:publish /p:Configuration=Release /p:Platform=AnyCPU; "c:\yourProject.csproj"
That will tell MSBuild to build your project and generate ClickOnce deployment files inside the bin\Release\YourProject.publish directory.
All that's left is to copy those files to the FTP/UNC share/wherever, and you're all set.
You can tell CruiseControl.NET to build using those MSBuild parameters.
You'll then need a CruiseControl.NET build task to take the generated deployment files and copy them to the FTP or UNC share. We use a custom little C# console program for this, but you could just as easily use a Powershell script.
Thanks for all the help. The final solution we implemented took a bit from every answer.
We found it easier to handle working with multiple environments using simple batch files. I'm not suggesting this is the best way to do this, but for our given scenario and requirements, this worked well. Supplement "Project" with your project name and "Environment" with your environment name (dev, test, stage, production, whatever).
Here is the tasks area of our "ccnet.config" file.
<!-- override settings -->
<exec>
<executable>F:\Source\Project\Environment\CruiseControl\CopySettings.bat</executable>
</exec>
<!-- compile -->
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
<workingDirectory>F:\Source\Project\Environment\</workingDirectory>
<projectFile>Project.sln</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Rebuild</targets>
<timeout>0</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
<!-- clickonce publish -->
<exec>
<executable>F:\Source\Project\Environment\CruiseControl\Publish.bat</executable>
</exec>
The first thing you will notice is that CopySettings.bat runs. This copies specific settings for the environment, such as database connections.
Next, the standard MSBUILD task runs. Any compile errors are caught here and handled as normal.
The last thing to execute is Publish.bat. This actually performs a MSBUILD "rebuild" again from command line, and parameters from CruiseControl are automatically passed in and built. Next, MSBUILD is called for the "publish" target. The exact same parameters are given to the publish as the rebuild was issued. This keeps the build numbers in sync. Also, our executables are named differently (i.e. - ProjectDev and ProjectTest). We end up with different version numbers and names, and this allows ClickOnce to do its thing.
The last part of Publish.bat copies the actual files to their new homes. We don't use the publish.htm as all our users are on the network, we just give them a shortcut to the manifest file on their desktop and they can click and always be running the correct executable with a version number that ties out in CruiseControl.
Here is CopySettings.bat
XCOPY "F:\Source\Project\Environment\CruiseControl\Project\app.config" "F:\Source\Project\Environment\Project" /Y /I /R
XCOPY "F:\Source\Project\Environment\CruiseControl\Project\My Project\Settings.Designer.vb" "F:\Source\Project\Environment\Project\My Project" /Y /I /R
XCOPY "F:\Source\Project\Environment\CruiseControl\Project\My Project\Settings.settings" "F:\Source\Project\Environment\Project\My Project" /Y /I /R
And lastly, here is Publish.bat
C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /target:rebuild "F:\Source\Project\Environment\Project\Project.vbproj" /property:ApplicationRevision=%CCNetLabel% /property:AssemblyName="ProjectEnvironment" /property:PublishUrl="\\Server\bin\Project\Environment\\"
C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /target:publish "F:\Source\Project\Environment\Project\Project.vbproj" /property:ApplicationVersion="1.0.0.%CCNetLabel%" /property:AssemblyVersion="1.0.0.%CCNetLabel%" /property:AssemblyName="ProjectEnvironment"
XCOPY "F:\Source\Project\Environment\Project\bin\Debug\app.publish" "F:\Binary\Project\Environment" /Y /I
XCOPY "F:\Source\Project\Environment\Project\bin\Debug\app.publish\Application Files" "F:\Binary\Project\Environment\Application Files" /Y /I /S
Like I said, it's probably not done the way that CruiseControl and MSBUILD developers had intended things to work, but it does work. If you need to get this working yesterday, it might be the solution you're looking for. Good luck!
I remember doing this last year for a ClickOnce project I was working on. I remember it taking me forever to figure out but here it is. What I wanted my scripts to do was to generate a different installer that pointed to our dev env and a different one for prod. Not only that but i needed it to inject the right versioning information so the existing clients would 'realize' there is a new version out there which is the whole point of clickOnce.
In this script you have to replace with your own server names etc. The trick is to save the publish.htm and project.publish file and inject the new version number based on the version that is provided to you by CC.NET.
Here is what my build script looked like:
<target name="deployProd">
<exec program="<framework_dir>\msbuild.exe" commandline="<project>/<project>.csproj /property:Configuration=PublishProd /property:ApplicationVersion=${build.label}.*;PublishUrl=\\<prod_location>\binups$\;InstallUrl=\\<prod_location>\binups$\;UpdateUrl=\\<prod_location>\binups$\;BootstrapperComponentsUrl=\\<prod_location>\prereqs$\ /target:publish"/>
<copy todir="<project>\bin\PublishProd\<project>.publish">
<fileset basedir=".">
<include name="publish.htm"/>
</fileset>
<filterchain>
<replacetokens>
<token key="CURRENT_VERSION" value="${build.label}"/>
</replacetokens>
</filterchain>
</copy>
</target>
Hope this helps
Just be able passing the ${CCNetLabel} in the CCNET.config msbuild task would be a great improvement.
You want to use the ClickOnce manifest generation tasks in msbuild. The process is a little long winded, so I am just going to point you to a couple of links. Here is the reference on msdn and a sample article to hopefully get you started.