Continuous Integration (CI) with Jenkins

Continuous Integration is the idea of running a full build every time someone on a team publishes new changes to source control (such as git).  The idea of setting it up allows for greater visibility into changes, by finding which build exhibits problems and which doesn't as every build happens immediately following a change in source.  This process allows QA to quickly and easily track the life of a bug.
By marrying the CI server with other tasks such as Unit tests to check on the system, we get a higher level of confidence that the code under test is stable.  A competent CI system can run several tasks that are often viewed as a drudgery by developers to try and run at regular intervals.  Unit Tests, Integration Tests, code coverage reports, profiling, memory consumption reports, and quick / easy build deployment with automated publishing are just some of the common tasks a Jenkins server can be found doing.
As we're embedded developers, we often will have to target both iPhone OS and Android development.  Thus a build server would likely want to use OSX for the operating system.  Here, I'm going to present how to setup OSX build server for Android development.  I'm going to target some of the more advanced things we can ask a build server to do for us and then circle back and update when we have a profiler that we can use from the CI that's geared for a SnapDragon processor.

Step 1: Prerequisites 


  1. Install Java Runtime Environment (JRE) from Oracle.  I recommend version 7 as some things aren't quite 100% with version 8 and version 6 that ships with Apple is rather limited.
  2. Install Homebrew to make everything much easier.
  3. Install Jenkins by running brew install jenkins
  4. Setup your Jenkins User on the server that you intend to run the server.  I don't give the user access to a login shell or access to anything other than its home directory
    1. sudo mkdir /var/jenkins
    2. sudo /usr/sbin/dseditgroup -o create -r 'Jenkins CI Group' -i 600 _jenkins
    3. sudo dscl . -append /Groups/_jenkins passwd "*"
    4. sudo dscl . -create /Users/_jenkins
    5. sudo dscl . -append /Users/_jenkins RecordName jenkins
    6. sudo dscl . -append /Users/_jenkins RealName "Jenkins CI Server"
    7. sudo dscl . -append /Users/_jenkins uid 600
    8. sudo dscl . -append /Users/_jenkins gid 600
    9. sudo dscl . -append /Users/_jenkins shell /usr/bin/false
    10. sudo dscl . -append /Users/_jenkins home /var/jenkins
    11. sudo dscl . -append /Users/_jenkins passwd "*"
    12. sudo dscl . -append /Groups/_jenkins GroupMembership _jenkins
    13. sudo chown -R jenkins /var/jenkins
    14. sudo chgrp -R _jenkins /var/jenkins

Step 2: The Setup

  1. Create the Daemon.  A Daemon is a process that runs in the background to allow things like servers to launch, run and be monitored automatically.  Automation means that it is done right once and then every subsequent time without error, so it's definitely the right way to get this setup.  OSX uses LaunchD to launch and keep daemons running in the background.  So the way to set it up is to create a file: /Library/LaunchDaemons/org.jenkins-ci.plist Here's what to place in that file:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>Label</key>
      <string>Jenkins</string>
      <key>ProgramArguments</key>
      <array>
        <string>/usr/bin/java</string>
        <string>-jar</string>
        <string>/usr/local/Cellar/jenkins/1.414/lib/jenkins.war</string>
      </array>
      <key>OnDemand</key>
      <false/>
      <key>RunAtLoad</key>
      <true/>
      <key>UserName</key>
      <string>jenkins</string>
    </dict>
    </plist>
  2. Now let's tell the daemon to start (or you can simply reboot the server as it will auto start on computer boot). sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist
  3. You should now have Jenkins up and running on port 8080.  http://localhost:8080 will reach it if you're on the local machine.

Step 3: The Configuration

  1. Install the Jenkins plugins you want to use.  I recommend the gradle plugin, the git plugin, the android plugin and the test report / code coverage plugins.
  2. Click "new job" and enter your git pull information.  If you have the chance, use a webhook pull request system so you don't have to use the polling option (reduces network bandwidth required to run Jenkins.
  3. In your invoke gradle, I highly recommend using the gradle wrapper command line by running ./gradlew from the command option in your Jenkins job.
  4. I recommend running a command like ./gradlew clean assembleRelease test
  5. Gradle will then clean the project, create a package and then run unit tests.
  6. The Unit Tests I published here can also create coverage output so adding a post execute Jenkins task to interpret them is a good idea.
  7. The last thing to setup is Lint, thankfully the Android Jenkins plugin has a simple post action task that will take care of that.
You should now have a complete Jenkins setup ready for any Android application.  In a future article, I will discuss extending this Jenkins setup to utilize external toolsets and even a robot that will run physical tests on a VR headset.  Stay tuned!

Comments

Popular posts from this blog

Drone VR Software Architecture

Status of the blog

Build Snapdragon Flight Drone