Managing your dotfiles with GNU/Make

Everyone knows about pushing your dotfiles to github/bitbucket or whatever version control provider you like best but not many people implement a easy way to copy or link the dotfiles.

Lots of people use bloated gems to manage the linking or even write there own but to me these are just over engineered for my needs. My solution is to use a tool that will be already on everyone's machine GNU/Make - nice and simple!

Below is a copy of my Makefile which I used to keep my desktop (archlinux) and my laptop (Slackware) in sync. You can also find it on my git account.

Makefile
DOTFILES = $(shell pwd)

all : linkfiles linkfolders linkmisc

linkfiles:: bashrc vimrc xinitrc Xresources
    for file in $^; do ln -fs $(DOTFILES)/$$file ${HOME}/.$$file; done

linkfolders:: vim ncmpcpp
    for folder in $^; do ln -fns $(DOTFILES)/$$folder ${HOME}/.$$folder; done

linkmisc:: bin dwm
    for folder in $^; do ln -fns $(DOTFILES)/$$folder ${HOME}/$$folder; done

Continuous Integration using Jenkins

This post is a rough guide on getting up and running with Continuous Integration using Jenkins.

  • Build on commits to a git repo.
  • Check for security issues with the code base using Brakeman.
  • Run the code base tests, in this case RSpec tests.
  • Deploy to Engineyard, AWS instances.
  • Rollback if the deploy has failed.

I will add a Chef cookbook and a SaltStack state to my git to automate the install - the way it should be!

Jenkins setup on CentOS/Redhat

Installing Jenkins can be as easy as downloading the Jenkins WAR file and then running it from the command line. I prefer to use Jenkins own repo as it allows you to update to the latest version with easy and in the case of redhat based distributions you get an INIT script too.

To install Jenkins via YUM then run these commands as root or sudo under a user account and you will be good to go!

  • sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
  • sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
  • sudo yum install jenkins

Now that Jenkins is installed running the init script via Service or directly will start it up on localhost:8080 by default.

service jenkins start

Also if you want Jenkins to start on boot then remember to add Jenkins to init 3, I hope your not running a server under init 5.

chkconfig jenkins on --level 3

Nginx Configuration

I normally like to setup Jenkins under a domain name to eliminate the need to specify port numbers and for added control over the service. If you would like to do this then install Nginx.

yum install nginx

Copy the configuration to /etc/nginx/conf.d/mydomain.conf and restart nginx

service nginx restart or /etc/init.d/nginx restart

server { listen 80; server_name ci.mydomain.com; root /var/run/jenkins/war/; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log;

location @jenkins {
        sendfile off;
        proxy_pass         http://127.0.0.1:8080;
        proxy_redirect     default;

        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_max_temp_file_size 0;

        #this is the maximum upload size
        client_max_body_size       10m;
        client_body_buffer_size    128k;

        proxy_connect_timeout      90;
        proxy_send_timeout         90;
        proxy_read_timeout         90;
        proxy_buffer_size          4k;
        proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
        proxy_temp_file_write_size 64k;
}

location / {
        try_files $uri @jenkins;
}

}

Jenkins Plugins

To install Jenkins plug-ins from the main page go to Manage Jenkins -> Plugin Manager then click available. From here you can search for the plug-ins listed below.

On a side note, checkout the Chuck Norris and Green ball plug-ins.

Jenkins Git Plugin

The main plug-in that you will need is this one, it allows us to pull down from a Git repo.

Brakeman Plugin

Brakeman plugin detects security vulnerabilities in RoR applications and as such is useful to run against builds for production environments. To run Brakeman during a build add the following line to your build step.

    brakeman -o brakeman-output.tabs

This is included in my build script below.

ThinBackup Plugin

ThinBackup Plugin takes a backup of your current Jenkins Home in TAR GZ format, clearly very handy! Once you have it installed then go to Manage Jenkins -> ThinBackup -> Settings and fill out the required information. I suggest you use something like Rsnapshot to pull the backups offsite nightly.

Dashboard View

Dashboard View allows you to make a custom view that looks a lot snappier than the default. You can use this to remove any un-needed information such as build times etc.

Workspace Cleanup Plugin

I love this plugin, before each build it will clear out the workspace. Such a simple thing to do but not clearing out the workspace has caused me a few headaches in the past!

When you create a new build make sure you tick the box saying clear out workspace before build!

Jenkins Build Script

Once I have created a new Job, selected a free-style project and then filled in the git account information (remember the delete workspace checkbox). As a post-build action select Publish Brakeman warnings and as the File output enter

brakeman-output.tabs

Add the script below in as a Build step as a execute shell, it will do the following steps:

  • Run a bundle install for and GEM updates.
  • Create the DBs and migrate and changes.
  • Run Brakeman
  • Run the RSpec tests, if they fail Jenkins will fail the build.
  • Deploy the code base to EngineYard
  • Check the URL for a 200 response, if it fails rollback to the last good version

You can easily modify this script to use Capistrano instead of the Engineyard Gem. The results of the Brakeman scan will be shown on the Job main page.

My Build Script:

    set +x

    ### CONFIG ###

    APPNAME='EngineYard Application Name'
    EY_ENV='EngineYard Environment Name'
    BRANCH='Git Branch'
    URL='URL FOR SMOKE TEST'

    ###

    BUNDLE=~/.rbenv/shims/bundle
    BRAKEMAN=~/.rbenv/shims/brakeman
    EY_GEM=~/.rbenv/shims/ey

    cd "$WORKSPACE"
    $BUNDLE install
    $BUNDLE exec rake db:create db:migrate db:test:prepare

    $BRAKEMAN -o brakeman-output.tabs --no-progress --separate-models

    if ! $BUNDLE exec rspec; then
        echo "RSpec Tests have failed" >&2
    else
        $EY_GEM deploy --app $APPNAME --environment $EY_ENV --branch $BRANCH -m
    fi

    if ! curl -s -w "%{http_code}" $URL -o /dev/null | grep 200; then
        echo "Server returned a failed Response Code, Rolling back."
        # Should be a production only thing I think, comment out if
        # not needed!
        $EY_GEM rollback --app $APPNAME --environment $EY_ENV
    else
        echo "Server returned a 200 Response Code."
    fi

    set -x