Wednesday, November 9, 2011

Build Automation

One of the most important parts of any development shop is release management, yet it's amazing that most companies have a fly by the seat of your pants approach. As developer we create our own misery by ignoring this critic task.  Nobody cares that the code works on your computer; if there is a problem it should be easy to fix.... AND!!! fixing the issue isn't adding a line or two of code, checking it in and praying.


Release Management has more to do with outputs rather then code.  Constantly producing the same well tested product using the same method each time and tracking all code, symbols, and binary related to that output is critical.


Fortunately there are tools available to assist developers with full build automation.


NOTE TO PRODUCT\PROJECT MANAGERS:   DO NOT!!! expect a junior or intermediate resource to complete this complex task.  Also, this is not a one time task it's a job role to maintain the build process. Changes to the output product that require modifications to the build process have to be completed as required.


Like most companies these days, nobody wants to pay money on time, resources, and products if they feel they have been getting along just fine without a real release management process.  One of the best tools available is CruiseControl (also CruiseControl.NET). I will be discussing the .NET version of CruiseControl available at http://www.cruisecontrolnet.org/projects/ccnet


Companies will still have to spend money on a senior resource and the time it takes to setup a continuous integration server, however, time spend on packaging of future releases should be 50 - 70% less. This allows a company to reevaluate their current release schedule and produce releases more frequently.  Another major bonus is it removes any possible dependencies on specific resources that have limited availability.

CruiseControl.NET is easy to install and config, the installer is a simple next... next... done process.  CruiseControl.NET installs as a windows service and also installs a web dashboard to monitor and control the service (Ensure IIS is already installed on the target computer).  Another consideration is security, CruiseControl.NET by default installs under the local host process.  I recommend establishing a network domain account and have your administration grant rights to network resources, under windows services, find CruiseControl.NET, click properties, and update the LogOn tab with the network username and password.  This will also CruiseControl.NET to operate as a separate identity, publishing outputs to network drives, send status emails, getting\commiting with source control, etc...

CruiseControl.NET's main configuration file "ccnet.config" is installed in the "server" sub folder. This is where you config all your project,  the primary basics of you project are

  1. Defined your project - name, description, category, working directory
  2. Source Control - type of source control, locations, security
  3. Versions Labeler - type of labeler, major, minor, build
  4. Task - building source code, copying files, etc...
  5. Publishing - logger, destination locations, email
The url below contents information on all the possible xml tags available and how to config each one.
http://www.cruisecontrolnet.org/projects/ccnet/wiki/ConfiguringTheServer

Here is a good example of a basic project configuration using SVN, Visual Studio, InnoSetup.
    - Pulls code from SVN
    - Defined a version 1.5.3 (The SVN revision number is appended, Ex: 1.5.3.3873)
    - nANT script to apply CruiseControl.NET version to AssemblyInfo.cs files
    - Compiles debug and release mode using Visual Studio 2010
    - Executes some batch command to move newly compiled files into release structure folders
    - Compiles release into self extracting installer using InnoSetup with a digital signs .exe
    - Publishes installer to network drive under the version folder \1.5.3.3873\MyInstall.exe

 (Note: Project compiles and saving symbol files for future support issue, the source code is also tagged to allow remote debugging of issues on non-developement environments.)

<cruisecontrol xmlns:cb="urn:ccnet.config.builder">

<project name="MyProduct">
      <category>Products</category>
      <description>My awesome product is awesome</description>
      <webURL>http://localhost/ccnet/MyProduct/ViewLatestBuildReport.aspx</webURL>
      <workingDirectory>C:\Dev\MyProduct</workingDirectory>

<sourcecontrol type="svn">
      <executable>C:\Program Files (x86)\CollabNet\Subversion Client\svn.exe</executable>
      <trunkUrl>https://192.168.1.2/MyProduct/trunk</trunkUrl>
      <workingDirectory>C:\Dev\MyProduct</workingDirectory>
      <username>svnUsername</username>
      <password>svnPassword</password>
      <tagOnSuccess>true</tagOnSuccess>

      <tagBaseUrl>https://192.168.1.2/MyProduct/tags</tagBaseUrl>
</sourcecontrol>

<labeller type="assemblyVersionLabeller">
         <major>1</major>
         <minor>5</minor>
         <build>3</build>
         <incrementOnFailure>false</incrementOnFailure>
</labeller>

<tasks>

         <!-- LABEL ASSEMBLIES WITH NEW VERSION NUMBER -->
          <nant>
                   <executable>C:\Dev\Tools\nant-0.91\bin\nant.exe</executable>
                   <baseDirectory>C:\Dev\MyProduct\ReleaseManagement\Scripts</baseDirectory>
                   <nologo>false</nologo>
                   <buildFile>nANT_AssemblyLabeler.build</buildFile>
                   <buildTimeoutSeconds>6000</buildTimeoutSeconds>
          </nant>

            <!-- BUILD PRODUCT IN DEBUG MODE -->
            <devenv>
                  <solutionfile>MyProduct.sln</solutionfile>
                  <configuration>Release</configuration>
                  <executable>C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com</executable>
                  <version>VS2010</version>
            </devenv>

            <!-- BUILD PRODUCT IN RELEASE MODE -->
            <devenv>
                <solutionfile>MyProduct.sln</solutionfile>
                <configuration>Release</configuration>
                <executable>C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com</executable>
                <version>VS2010</version>
         </devenv>

         <!-- COPY DEBUG OUTPUTS AND ALL SYMBOLS FILES TO DEBUG FOLDER -->
         <exec>
                  <executable>C:\Windows\System32\cmd.exe</executable>
                  <baseDirectory>C:\Dev\MyProduct\ReleaseManagement\Debug\1.x\Products</baseDirectory>
                 <buildArgs>/c CopyFilesForSupporting.bat</buildArgs>
         </exec>

          <!-- BUILD RELEASE ASSEMBLIES TO RELEASE FOLDER WHERE OTHER NON COMPILED REQUIRES FILES EXISTS TO INCLUDING BY INSTALLER -->
         <exec>
               <executable>C:\Windows\System32\cmd.exe</executable>
               <baseDirectory>C:\Dev\MyProduct\ReleaseManagement\Releases\1.x\Products</baseDirectory>
               <buildArgs>/c CopyAssembliesToReleaseFolder.bat</buildArgs>
         </exec>

         <!-- COMPILE RELEASE FOLDER INTO A SELF EXTRACTING INSTALLER AND DIGITAL SIGN THE FILE -->
         <exec>
               <executable>C:\Program Files (x86)\Inno Setup 5\ISCC.exe</executable>
              <baseDirectory>C:\Dev\MyProduct\ReleaseManagement\Releases\1.x\Products</baseDirectory>
              <buildArgs>"/SMYSignCode=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\SignTool.exe sign /a /f C:\Dev\MyProduct\ReleaseManagement\My_Code_Signing.pfx /v /t http://timestamp.verisign.com/scripts/timstamp.dll /p mypassword $f" MyInnoSetup.iss</buildArgs>
           </exec>
 

    </tasks>

      <publishers>

          <!-- COPIES DEBUG FOLDER OUTPUTS TO NETWORK AND VERSIONS THE FOLDER (Ex. \Debug\1.5.3.8439\) -->
          <buildpublisher>
                <sourceDir>C:\MyProduct\ReleaseManagement\Debug\1.x\Products\Output</sourceDir>
                <publishDir>\\MyFileServer\1.x\Debug</publishDir>
                <useLabelSubDirectory>true</useLabelSubDirectory>
                <alwaysPublish>false</alwaysPublish>
          </buildpublisher>

          <!-- COPIES RELEASE FOLDER OUTPUTS TO NETWORK AND VERSIONS THE FOLDER (Ex. \Release\1.5.3.8439\) -->
          <buildpublisher>
                <sourceDir>C:\MyProduct\ReleaseManagement\Releases\1.x\Products\Output</sourceDir>
                <publishDir>\\MyFileServer\1.x\Release</publishDir>
                <useLabelSubDirectory>true</useLabelSubDirectory>
                <alwaysPublish>false</alwaysPublish>
           </buildpublisher>

           <xmllogger logDir="C:\Dev\MyProduct\ReleaseManagement\1.x\BuildLogs" />

      </publishers>

    </project>
 

</cruisecontrol>










No comments: