Nightly "publish build" in CruiseControl.NET

I manage a CI-server for a bunch of projects of my company, running under CruiseControl.NET 1.6.7981.1. The projects logically form a "product", but are (at least partially) independent from each other. As comparison, MS Office is a "product" consisting of the independent projects "Word", "Excel", etc.

Each project has its own ccnet-project which get build whenever a change is committed to source-control (via IntervalTrigger). This works fine.

The product itself consists of the output of the different "child" projects as well as additional static data (bitmaps, sample data, ...). For this I have a separate "publish" ccnet-project which does these steps and then copies the data to a new output folder on the network. This "publishing" works fine as well. Each time it is run, a new folder is created; currently each folder is approx. 1GB in size.

I have two additional requirements:

  • Since "publish" generates such huge amounts of data, I want to run it nightly (unless someone manually triggers it). We actually have two versions of the product and all child projects running on the CI-server (dev and last-release). The last-release gets patches only, so there might be several days when nothing has been done in the child-projects. So "publish" should only run if a child-project has been modified.
  • Someone might break the build of one of the child-projects. Until it is fixed, the parent "publish" project should not be run.
  • The way I tried to solve it does not work correctly, however. My current ccnet.config looks approx. as follows (relevant parts only):

    <project name="Child 1 dev" queue="dev" queuePriority="1">
        <!-- Build the project -->
        <publishers>
            <!-- Logger, statistics, ... -->
            <conditional>
                <conditions>
                    <statusCondition value="Success" />
                    <lastStatusCondition value="Failure" />
                </conditions>
                <tasks>
                    <cruiseServerControl>
                        <actions>
                            <controlAction type="StartProject" project="Publish dev" />
                        </actions>
                    </cruiseServerControl>
                </tasks>
            </conditional>
            <conditional>
                <conditions>
                    <statusCondition value="Failure" />
                </conditions>
                <tasks>
                    <cruiseServerControl>
                        <actions>
                            <controlAction type="StopProject" project="Publish dev" />
                        </actions>
                    </cruiseServerControl>
                </tasks>
            </conditional>
        </publishers>
    </project>
    
    <!-- Additional "child" projects as above -->
    
    <project name="Publish dev" queue="dev" queuePriority="10">
        <triggers>
            <multiTrigger operator="And">
                <triggers>
                    <multiTrigger operator="Or">
                        <triggers>
                            <projectTrigger project="Child 1" />
                            <projectTrigger project="Child 2" />
                            <projectTrigger project="Child 3" />
                        </triggers>
                    </multiTrigger>
                    <scheduleTrigger buildCondition="ForceBuild" time="23:30" />
                </triggers>
            </multiTrigger>
        </triggers>
        <!-- Do the publishing, a bunch of exec tasks. -->
    </project>
    

    The problems:

  • If nothing is done in the child projects for several days, then no "publish" is run. After this, as soon as something changes in the child projects, "publish" runs. I am guessing that the ScheduleTrigger is staying triggered. I tried wrapping the ScheduleTrigger in a FilterTrigger, but then sometimes no build ran at all.
  • If the build of a child project fails, the publish project is stopped. However, starting the project again after the build has succeeded often doesn't work.
  • So in short, I guess the solution would a set of triggers for "publish dev" which triggers:

  • Each night at 23:30 (for example).
  • When any child project has been successfully built since the previous "publish dev".
  • And no child project is in a build-failed state (ie all child projects are in a successful build state).
  • If #2 or #3 are wrong, the next check should only be the next night.

    EDIT:

    Something definitely wrong with the lastStatusCondition. I have the following outputs:

    Failed build:

    2011-04-01 10:14:06,105 [Child 1 dev] [DEBUG] - Checking conditions
    2011-04-01 10:14:06,105 [Child 1 dev] [DEBUG] - Checking status - matching to Success
    2011-04-01 10:14:06,105 [Child 1 dev] [INFO] - Conditions did not pass - running else tasks
    2011-04-01 10:14:06,105 [Child 1 dev] [INFO] - Tasks completed: 0 successful, 0 failed
    2011-04-01 10:14:06,105 [Child 1 dev] [DEBUG] - Checking conditions
    2011-04-01 10:14:06,105 [Child 1 dev] [DEBUG] - Checking status - matching to Failure
    2011-04-01 10:14:06,121 [Child 1 dev] [INFO] - Conditions passed - running tasks
    

    So everything is working fine. Then I immediately build it again, with build fixed:

    2011-04-01 10:18:36,078 [Child 1 dev] [DEBUG] - Checking conditions
    2011-04-01 10:18:36,078 [Child 1 dev] [DEBUG] - Checking status - matching to Success
    2011-04-01 10:18:36,078 [Child 1 dev] [DEBUG] - Checking last build status - matching to Failure
    2011-04-01 10:18:36,078 [Child 1 dev] [INFO] - Conditions did not pass - running else tasks
    2011-04-01 10:18:36,093 [Child 1 dev] [INFO] - Tasks completed: 0 successful, 0 failed
    2011-04-01 10:18:36,093 [Child 1 dev] [DEBUG] - Checking conditions
    2011-04-01 10:18:36,093 [Child 1 dev] [DEBUG] - Checking status - matching to Failure
    2011-04-01 10:18:36,093 [Child 1 dev] [INFO] - Conditions did not pass - running else tasks
    2011-04-01 10:18:36,093 [Child 1 dev] [INFO] - Tasks completed: 0 successful, 0 failed
    

    So despite the previous build having failed (as you can see from the matching to Failure in the first log), the previous build status property of the current (successful) build apparently is not Failure! I guess I'll have to file a bug against ccnet...


    Have a look at my blog, I provided a solution there. Comments are appreciated :

    http://rubenwillems.blogspot.com/2011/04/tuning-ccnet-to-your-whishes-new.html


    For your first problem, my thought are like yours : I think the schedule trigger keeps fired and waits for the multiple "OR trigger" to be fired. Note that this behaviour is expected when you reverse role : when a child project is successfully build you want to wait until the second trigger fires (at 23:30).

    A couple of idea to fit your requirements would be :

  • Add the <triggerStatus>Success</triggerStatus> to the project triggers (to prevent exceptions)
  • Set the innerTrigger of the project triggers to a schedule trigger instead of the default interval trigger. A schedule trigger set to fire at 23:30 should solve your problem
  • As for your second problem, I have no idea why the project would not restart, sowwy.

    I personnaly managed to deal with these products problem with Enterprise Continuous Integration, we used it for almost a year and it's great relief.

    链接地址: http://www.djcxy.com/p/23272.html

    上一篇: 直接开发到中央存储库,或不

    下一篇: 在CruiseControl.NET中每晚“发布构建”