Our team of 8 developers all use NCrunch and we are having problems with some of our larger solutions with frequent NCrunch build/retest failures due to DLL references.
First off, I will mention that I have read and (think) I fully understood the Project Atomicity page (http://www.ncrunch.net/documentation/considerations-and-constraints_project-atomicity), and I've searched the forums and found this thread:
http://forum.ncrunch.net...ssembly-References.aspx which might be relevant, but doesn't go very far.
While I understand why it's easier on NCrunch to use (and require) project references to determine inter-project dependencies, and that is uses msbuild so doesn't have access to solution-defined dependencies, requiring project references is not a useful way for us to reference projects within several of our solutions (at least not all the time). This is because we have several projects that are shared common "base" code across several applications, and those have their own solutions, their own code repositories, and their own separate CI builds that still have to run properly. On developer machines, these solutions are checked out in sibling folders under a parent dev folder. To attempt to illustrate, let's say we have the following:
"Base" solution 1 (versioned independently and has its own repository and CI build):
Base Project A
Base Project B (project references to A)
Base Project C (project references to A and B)
"Base" solution 2 (versioned independently and has its own repository and CI build):
[solution contains a Solution Folder which includes the A, B, and C projects, which are only built under configurations other than Debug and Release]
Base Project X
Base Project Y (project reference to X; dll reference to A)
Base Project Z (project references to X and Y; dll references to A, B, and C)
Product solution P (versioned independently and has its own repository and CI build):
[solution contains a Solution Folder which includes the A, B, C, X, Y, and Z projects, which are only built under configurations other than Debug and Release]
Product Project P (dll references to A, B, X, and Y)
Product Project P.Tests (project reference to P, dll references to A, B, C, X, Y, and Z)
For our purposes, we're talking about problems working in Product solution P.
It's probably obvious that this can work in NCrunch with proper references to required libraries everywhere, but that dependencies aren't clear to NCrunch. This means that rebuilding everything queues the builds in a fairly random-looking order, and the projects have to be manually re-compiled in the NCrunch Tests window in the proper order after some fail - sometimes with multiple tries - in order to get things rebuilt and re-tested properly. To resolve this, I tried making all references be project references for NCrunch. I created a new build configuration in each of the projects called "Local Debug" (copied from the Debug configuration), similar to this:
Code:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Local Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\build\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup>
In order to allow NCrunch and local developer-machine builds to work, the project files were modified with conditional references. The old inter-project dll references were removed and conditions added in a separate block like this:
Code:
<Choose>
<!-- CI builds are done using Debug for testing builds, Release for less frequent RC builds, but this should also work locally when building in Debug also -->
<When Condition="'$(Configuration)' == 'Debug' Or '$(Configuration)' == 'Release'">
<!-- dll refs -->
<ItemGroup>
<Reference Include="Base.A">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Base.1\build\Base.A.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Base.B">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Base.1\build\Base.B.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Base.C">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Base.1\build\Base.C.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
<!-- typically used for Local Debug builds -->
<Otherwise>
<!-- project refs -->
<ItemGroup>
<ProjectReference Include="..\..\Base.1\Base.A\Base.A.fsproj">
<Project>{3B2DFDD4-9C93-4BAA-8778-848153C07E40}</Project>
<Name>Base.A</Name>
</ProjectReference>
<ProjectReference Include="..\..\Base.1\Base.B\Base.B.csproj">
<Project>{9A6AB529-04EC-427B-9F8C-35E36516DE8F}</Project>
<Name>Base.B</Name>
</ProjectReference>
<ProjectReference Include="..\..\Base.1\Base.C\Base.C.csproj">
<Project>{6D27F041-4110-4567-B5B4-6CB935F49402}</Project>
<Name>Base.C</Name>
</ProjectReference>
</ItemGroup>
</Otherwise>
</Choose>
<!-- unconditional project refs and other 3rd party dll refs here -->
<ItemGroup>
<ProjectReference Include="..\ProductP\ProductP.csproj">
<Project>{5517F38F-D6CD-431D-8163-F421EDFDBD14}</Project>
<Name>ProductP</Name>
</ProjectReference>
</ItemGroup>
The solution was modified so that a Local Debug solution configuration ran each project in its Local Debug configuration. The NCrunch configuration was then modified so that the projects that required conditional dll references had "Use build configuration" set to Local Debug. That resulted in errors like this:
Quote:..\..\..\..\..\..\..\..\..\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets (1028)#0: The specified project reference metadata for the reference "..\..\Base.1\Base.A\Base.A.fsproj" is missing or has an invalid value: Project
After trying some different things, I wondered if NCrunch was just using the first references rather than using the conditions, so I tried inverting the condition and making the first block be the project references and the second block be the dll references. That resulted in the same error with "Use build configuration" set to Local Debug.
I also tried using a simpler version of the conditional blocks, using something like the following:
Code:
<!-- dll refs -->
<ItemGroup Condition="'$(Configuration)' == 'Debug' Or '$(Configuration)' == 'Release'">
<Reference Include="Base.A">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Base.1\build\Base.A.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Base.B">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Base.1\build\Base.B.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Base.C">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Base.1\build\Base.C.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<!-- project refs -->
<ItemGroup Condition="'$(Configuration)' != 'Debug' And '$(Configuration)' != 'Release'">
<ProjectReference Include="..\..\Base.1\Base.A\Base.A.fsproj">
<Project>{3B2DFDD4-9C93-4BAA-8778-848153C07E40}</Project>
<Name>Base.A</Name>
</ProjectReference>
<ProjectReference Include="..\..\Base.1\Base.B\Base.B.csproj">
<Project>{9A6AB529-04EC-427B-9F8C-35E36516DE8F}</Project>
<Name>Base.B</Name>
</ProjectReference>
<ProjectReference Include="..\..\Base.1\Base.C\Base.C.csproj">
<Project>{6D27F041-4110-4567-B5B4-6CB935F49402}</Project>
<Name>Base.C</Name>
</ProjectReference>
</ItemGroup>
... which gives the same error also with "Use build configuration" set to Local Debug.
Ultimately, I could not get it working the way I want. I still have the conditionals in the project files, but I have the NCrunch configuration set with "Use build configuration" set to blank, which for our projects defaults to the Debug configuration. This seems to cause NCrunch to use the dll references, and seems to be preventing the "...specified project reference metadata..." error. It still doesn't build things in the right order, however, which leaves me back at square 1.
It's worth mentioning that for small solutions dll references aren't as much of a problem - or may be an infrequent one. I created a small sample solution to test this and NCrunch doesn't have as many problems with it (aside from the "...specified project reference metadata..." error when I configure the sample solution that way). In our actual Product P solution, however, 10 Base.1 projects are included in local builds of the Product P solution, and 4 of the Base.2 projects (which depend on Base.1 projects) are included in the solution.
This could likely be resolved by removing all of the Base.1 and Base.2 projects from the Product P solution and sticking with DLL references, but we include them because we tend to focus on a product at a time, and frequently modify code in Base.1 and Base.2 during development. Including them allows us to avoid multiple copies of VS open to rebuild Base then rebuild Product P, and to give better up-front visibility of the scope of changes among other things.
What I would like to know is whether the mis-handling of conditionals is expected in the current version of NCrunch, or am I using them in a way not handled by NCrunch that could be fixed with different syntax? Any other suggestions on how to address this without creating alternate copies of the projects would be appreciated.