CI (Continuous Integration) was originally intended to be used in combination with automated unit tests written through the practices of Test driven development. Initially this was conceived of as running all unit tests and verifying they all passed before committing to the mainline.

jenkins

After reading this post you will know everything to install and configure Jenkins CI for building Rails application i.e. running all tests and sending notifications if build was failed.

First lets check that we have the same environment:

uname -a
# Linux staff-vm 3.2.0-29-generic #46-Ubuntu SMP Fri Jul 27 17:03:23 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

Just a reminder: NEVER install Jenkins on your production server and here is why:

jenkins on production

It is NewRelic graph which shows us that there is huge impact on the database which enlarge response time significantly.

RVM and Ruby

OK, lets check if we have ruby or mysql installed. You should get the same output:

rvm -v
# => -bash: rvm: command not found

ruby -v
# => -bash: ruby: command not found

mysql --version
# => -bash: mysql: command not found

For rvm installation we need to have git core and curl, install them like this:

sudo apt-get install build-essential git-core
sudo apt-get install curl

Now we can install rvm with ruby:

curl -L https://get.rvm.io | bash -s stable --ruby

and if you don't need the latest version of ruby don't forget to install one (1.8.7 for example):

rvm install ruby-1.8.7

Mysql

To install mysql just run in your terminal:

sudo apt-get install mysql-client mysql-server libmysql-ruby libmysqlclient-dev

Postgres

sudo aptitude install libpq-dev

If you had a problem with UTF-8 take a look at http://wiki.gentoo.org/wiki/PostgreSQL

Jenkins

So lets install Jenkins, original manual could be found here:

https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins+on+Ubuntu

To follow that manual we need to install aptitude:

sudo apt-get install aptitude

For now we will need just this block of commands:

wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
sudo aptitude update
sudo aptitude install jenkins

Lets start jenkins like this (or through service command):

sudo /etc/init.d/jenkins start

If you need port different from 8080 you can edit jenkins HTTP_PORT config param:

sudo vi /etc/default/jenkins

Nginx config

If you also need to config nginx try to find it with (on my machine config was lost in the folders so this is why I pay attention to that):

sudo find / -name nginx

So now we need to configure nginx and not only for proxying but to hide jenkins web interface. When I first installed Jenkins there was a bug – if you enable jenkins authorization you can't build project via url hook (get request with token as param). So the solution was simply to hide jenkins with http-auth and to enable hooks to specific locations like this:

upstream jenkins {
  server 127.0.0.1:8080;
}

server {
  listen 111.111.111.111:80;
  server_name ci.our_project.com *.ci.our_project.com;

  try_files $uri @jenkins;

  location @jenkins {
      proxy_pass http://jenkins;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;

      auth_basic "Restricted";
      auth_basic_user_file /path/to/htpasswd.jenkins;
  }

  location ~ /job/\w+/build {
    root            /var/cache/.jenkins/war;
    try_files $uri @jenkins;
  }

  location / {
    root            /var/cache/jenkins/war/;
    # Optional configuration to detect and redirect iPhones
    if ($http_user_agent ~* '(iPhone|iPod)') {
      rewrite ^/$ /view/iphone/ redirect;
    }

    auth_basic "Restricted";
    auth_basic_user_file /path/to/htpasswd.jenkins;

    try_files $uri @jenkins;
 }
}

OKay, so by this moment we should have jenkins web interface working and available at ci.our_project.com:

web interface

Jenkins user

Now we need to configure Jenkins for fetching data from git repo and run tests. So since Jenkins has its own user lets generate ssh pair for it:

sudo su jenkins
ssh-keygen -t rsa

To trigger builds remotely you should enable security (in Manage Jenkins -> Configure system). Just set matrix based authorization and anonymous is Administrator.

Now check you bash config, for me it looks like this by now:

cat /var/lib/jenkins/.bashrc

PATH=$PATH:/home/your_project/.rvm/bin # Add RVM to PATH for scripting
if [[ -s "$HOME/.rvm/scripts/rvm" ]]; then . "$HOME/.rvm/scripts/rvm"; fi

Git repo

OK, so now we are ready to create Jenkins job for our project. New Job -> Free-style project. If you use Git be sure to install some plugins: Manage Jenkins -> Manage Plugins and install Git plugin, Github plugin to enable fetching data and configuring Github url hook for Jenkins.

After creating a job navigate to its configuration, choose Source Code Management as Git and enter your Repository URL:

After installing Git plugin you can specify path to you repo:

git repo

URL hook

For triggering build we will use URL hook, for this you need to specify build token for you trigger in Build triggers section:

trigger

Build section, we are almost done. For our case choose Execute shell option so textarea for shell commands will appear. I have config like this:

Configure build

#!/bin/bash -x
sudo su jenkins
source /var/lib/jenkins/.bashrc
rvm use 1.9.3
bundle install
read -d '' database_yml <<"EOF"  
login: &login
  adapter: mysql2
  username: "root"
  password: "password"
  encoding: utf8

test: &test
  database: my_project_test
  <<: *login
EOF

echo "$database_yml" > config/database.yml
rake db:test:prepare RAILS_ENV=test
rake ci:setup:rspec spec RAILS_ENV=test

CI reporter

You may notice that we don't use rspec spec in the last command. This is because of Jenkins doesn't understand rspec console output. For Jenkins to understand it we need to use ci_reporter gem which generate xml output for our tests: https://github.com/nicksieger/ci_reporter

group :test do
  gem 'ci_reporter'
end

Bundle issues

On each build we will run bundle so be sure to install all necessary libraries for you project. For me it was smth like this:

sudo apt-get install libxslt-dev libxml2-dev
sudo apt-get install libmagickwand-dev

<http://nokogiri.org/tutorials/installing_nokogiri.html>

sudo aptitude install memcached
sudo apt-get install sphinxsearch

Jenkins folder rights

But even if you forget to install smth Jenkins will fail build and notify you.

Your app will be downloaded to /var/lib/jenkins/jobs/YOUR_PROJECT/workspace

If your app create some file (uploads testing for example) don't forget to give jenkins user permission for writing:

sudo chmod 757 -R /var/lib/jenkins/jobs/

Email notifications

Also don't forget to setup email notifications, for example you can create jenkins gmail account and set up gmail smtp:

http://kb.siteground.com/article/How_to_use_Googles_free_SMTP_server.html

In Jenkins config for your project add post-build action as Send email like this:

email

Git tag issue

After adding multiple gits (unfuddle, github) I got error with git tag command.

Solution: http://fijiaaron.wordpress.com/2012/03/08/skip-internal-tag-jenkins-git/

Github gook

Github intagration: http://fourkitchens.com/blog/2011/09/20/trigger-jenkins-builds-pushing-github

Have nice development with Jenkins!

stat

Uninstall Jenkins is easy too, just:

sudo apt-get remove jenkins

#jenkins #rails