views:

259

answers:

4

I have an app and shared library with separate CC build triggers (a successful library build will also trigger a build of the app), with a queue set up to make sure that CC doesn't attempt to build the app until the library is finished.

Something weird happened this morning. I'm working over a slowish VPN and committed a bunch of changes to my app and a shared library (this was all done as a single commit). CC did a build of my app first which failed because it couldn't find two new classes in the shared library. After this the shared library built successfully, followed by my app building successfully.

It looks like CC attempted to build after the changes to my app had been downloaded to the build server, but before the changes to the library had arrived. Is this possible, or do I need to look elsewhere to find out what was the cause?

This is the error I got in the build log for the application:

<error code="CS0246" file="SomeClass.cs" line="###" column="###"><![CDATA[The type or namespace name 'ClassAddedToSharedLibraryInThisCommit' could not be found (are you missing a using directive or an assembly reference?)]]></error>

An excerpt from my CCnet.config file is below:

 <project name="App1" queue="hourly" queuePriority="2">
    <triggers>
      <multiTrigger operator="Or">
        <triggers>
          <projectTrigger project="sharedLib">
            <triggerStatus>Success</triggerStatus>
            <innerTrigger type="intervalTrigger" seconds="30" buildCondition="ForceBuild"/>
          </projectTrigger>
          <filterTrigger startTime="16:00" endTime="7:00">
            <trigger type="intervalTrigger" seconds ="625" />
          </filterTrigger>
        </triggers>
      </multiTrigger>
    </triggers>
   <sourcecontrol type="svn">
      <tagOnSuccess>false</tagOnSuccess>
      <tagBaseUrl>https://servername/...&lt;/tagBaseUrl&gt;
      <autoGetSource>true</autoGetSource>
      <executable>c:\program files\subversion\bin\svn.exe</executable>
      <trunkUrl>https://servername/.../App1/...&lt;/trunkUrl&gt;
      <workingDirectory>C:\svn\...\App1\...</workingDirectory>
    </sourcecontrol>
    <tasks>
      <msbuild>
        <executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe</executable>
        <workingDirectory>C:\svn\...\App1\...</workingDirectory>
        <projectFile>App1.sln</projectFile>
        <buildArgs>/p:Configuration=Debug /v:m /m</buildArgs>
        <logger>C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
        <timeout>1000000</timeout>
      </msbuild>
    </tasks>
  </project>
 <project name="sharedLib" queue="hourly" queuePriority="1">
    <triggers>
      <filterTrigger startTime="16:00" endTime="7:00">
        <trigger type="intervalTrigger" seconds ="350" />
      </filterTrigger>
    </triggers>
    <sourcecontrol type="svn">
      <tagOnSuccess>false</tagOnSuccess>
      <tagBaseUrl>https://servername/...&lt;/tagBaseUrl&gt;
      <autoGetSource>true</autoGetSource>
      <executable>c:\program files\subversion\bin\svn.exe</executable>
      <trunkUrl>https://https://servername/.../SharedLib/...&lt;/trunkUrl&gt;
      <workingDirectory>C:\svn\...\sharedLib\...</workingDirectory>
    </sourcecontrol>
    <tasks>
      <msbuild>
        <executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe</executable>
        <workingDirectory>C:\svn\...\sharedLib\...</workingDirectory>
        <projectFile>sharedLib.csproj</projectFile>
        <buildArgs>/p:Configuration=Debug /v:m /m</buildArgs>
        <logger>C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
        <timeout>1000000</timeout>
      </msbuild>
    </tasks>
  </project>
A: 

I've had a similar issue with CC.Net, but not on SVN. I'm not familiar with how their commits work. But on my SCM, CC.Net polled the server for changes in the middle of a check-in and launched a build, even though there were other files getting checked in.

Personally, I didn't worry about it, because it was a perfect storm where the CC.Net trigger happened to get fired in the middle of a check-in. In my almost 3 years of using CC.Net, I'd say that's happened twice.

taylonr
that sounds like what happened to me. I guess I assumed CC had tighter integration with the source control system.
Dan Neely
Yeah, but from other comments, it sounds like it's not possible on SVN. My SCM allows for atomic or non-atomic check-ins. I was using the non-atomic (since it was default)
taylonr
+1  A: 

Subversion commits are atomic, so this should not be possible. Cruise control should not see any new files until the checkin is complete. You'll have to put the blame elsewhere.

Unless you're actually using two separate subversion repositories (perhaps using svn:external?)

amarillion
Just one repository, but see my comments to consultutah.
Dan Neely
A: 

SVN commits are atomic. Nothing can fetch your commit until it is all posted to the server. What I think you are seeing is the default non-queuing behavior in CC.NET.

To prevent this, you need to set the queue attribute on the project element:

<project name="build_shared_library" queue="my-lock-value">...
<project name="build_app" queue="my-lock-value">...

Both the library and the app should have the same value in the queue attribute.

consultutah
We have a queue set up, and what I saw doesn't appear consistent with a queue problem. The shared library is included as a full project in the solutions, not just linked as a binary dll. As a result if my app built first it should compile the code in the library as well with the attempt to build the library concurrently failing due to a file lock.
Dan Neely
Does cruise control actually check with the SVN server to see if a new commit has been made and wait until all the files are copied to the build server (the SVN server and its data storage is on a separate system); or is it just watching the folder where the local copy of the SVN client is moving the files to? AFAIK NTFS does not support atomic actions on multiple files, which would mean that even though SVN considered the changes to files 1-10 a single event there would be a time where only files 1-8 were on the build server, while 9 and 10 were still being downloaded.
Dan Neely
CC.NET just runs an SVN log against the server to see if there are new changes, so they should all be there before you builds start.
consultutah
I added the logged error message to my question. I don't see any way to interpret it other than the trigger firing before all the files were copied from the svn server onto the build machine. The error was logged for both of the methods that returned the new type.
Dan Neely
Dan, could you post the relevant parts of your ccnet.config file? IT doesn't need to be too detailed, but getting the projects, tasks, and svn config (minus any usernames/passwords of course) might help.
consultutah
@consultutah updated
Dan Neely
A: 

I think you said it all in your question:

CC did a build of my app first which failed because it couldn't find two new classes in the shared library. After this the shared library built successfully, followed by my app building successfully.

There was no way for CC.NET to know that the changes to your app depended on changes to your library. Your configuration doesn't say that the "sharedLib" project must be built before the "App1" project is built, it just says that if they're both in the queue at the same time, "sharedLib" goes first.

You may want to consider having the "sharedLib" project trigger builds of the "App1" project.

Ross Patterson
This is a trigger to do that (the first of the two for app1). App1 needs to be able to build on its own when the only changes made are to it. Since sharedLib is part of the app1 solution App1 should built it if necessary without any additional intervention.
Dan Neely