Create a CI/CD pipeline with Codeship and Heroku

Continuous integration and deployment are two of the most important things to have in any modern web application, alongside a lean and production-ready development environment. At SourceLair, we try our best to give you the latter, while at the same time we integrate as well as possible with services covering the other steps of your code delivery chain.

In this tutorial, we'll describe how you can create a nice integration between SourceLair for developing, Codeship Pro for testing and Heroku for deployment.

Setting the stage

For this tutorial, you'll need:

For the sake of this tutorial, we'll create a Django application, backed by a PostgreSQL database, which we'll code in SourceLair, set up CI/CD in Codeship and then deploy to Heroku.

Getting started

The repository we'll use throughout the tutorial can be found at https://github.com/sourcelair-blueprints/django-postgres-ci-cd as base. Since we'll also need a PostgreSQL database, we have prepared a complete Blueprint which will:

  • create a new SourceLair project from the above repo
  • attach a PostgreSQL database
  • run pip install -r requirements.txt so that you have all the dependencies installed

After you've created your project, you will need to make sure your database contains any needed migrations by opening the Command Palette with Ctrl + Shift + P (Cmd on a Mac) and using the "Migrate" command

Now that you have added the needed migrations for your database, it's time to test that everything is working nicely. Open your server's Public URL from the eye-like icon in the sidebar, or by using the "Public URL" Command Palette command.

As you can see, you can add new posts, like them and then the likes are calculated and displayed under each post.

Setting up testing

Your application works nicely and correctly displays the correct number of likes, but are you sure they are always calculated correctly? Let's dive in the code to see how this works and make sure with a test that it will keep working 😀

Getting the testing code ready

Open the models.py file from the file explorer, or by using the Quick open functionality of SourceLair with Ctrl + Shift + O (or Cmd on a Mac). There, you'll see that we have two models defined, Article andLike. The interesting part though is that for performance reasons, the like_count value is saved in the Article model and not queried every time from the database. This is done with Django signals - open the signals.py file if you like to see how this works.

What we would like to make sure now is that every time we create a new Like entry, the like_count of the related model is incremented. For that reason, open the tests.py file and add the following code:

# blog/tests.py

from django.test import TestCase
from blog import models


class ModelsCase(TestCase):
    def setUp(self):
        self.article = models.Article.objects.create(
            title='New article', text='Demo text', author='42')

    def test_like_increment(self):
        """
        Test that creating a like, correctly increments the counter of the
        article.
        """
        models.Like.objects.create(article=self.article)
        self.article.refresh_from_db()
        self.assertEqual(self.article.like_count, 1)

This will make sure our condition is met. In order to test this locally, run the following command in your SourceLair terminal:

./manage.py test

This will run the test you just created and - hopefully - report that it worked!

Setting up GitHub and Codeship integration

Before you set up your project's CI integration, you'll need to:

Creating the needed files for Codeship

Codeship Pro is based on Docker, as is SourceLair. That's why it's super easy to describe your SourceLair project in a way that Codeship understands.

First, you'll need to create a Dockerfile.codeship file, which describes your main application:

# Dockerfile.codeship

FROM python:2.7.11-onbuild
MAINTAINER Antonis Kalipetis <[email protected]>

RUN apt-get update && \
    apt-get install -y netcat

Then, you'll need to create a file named codeship-services.yml, which describes the exact same stack you have on SourceLair - a Python application and a PostgreSQL database:

# codeship-services.yml

web:
    build:
        image: akalipetis/codeship
        dockerfile_path: Dockerfile.codeship
    links:
        - postgres
    environment:
        DATABASE_URL: "postgres://postgres:[email protected]/codeship"
postgres:
    image: "postgres:9.4"
    environment:
        POSTGRES_DB: codeship
        POSTGRES_PASSWORD: mysecretpassword

Finally, you'll need to describe the steps that Codeship needs to run in order to test your application in a codeship-steps.yml file:

# codeship-steps.yml

- service: web
  command: bash check_n_run.sh ./manage.py migrate
- service: web
  command: bash check_n_run.sh ./manage.py test

As you can see, we're using a file named check_n_run.sh to wrap our commands. This is used so that we make sure the PostgreSQL database is in place when the tests run. The check is pretty simple and straight-forward:

# check_n_run.sh

#!/bin/bash
set -e

function check_port() {
    local host=${1} && shift
    local port=${1} && shift
    local retries=5
    local wait=1

    until( $(nc -zv ${host} ${port}) ); do
        ((retries--))
        if [ $retries -lt 0 ]; then
            echo "Service ${host} didn't become ready in time."
            exit 1
        fi
        sleep "${wait}"
    done
}

check_port "postgres" "5432"

exec "[email protected]"

Shoot! 🚀

Everything should be ready now, so the only thing you need to do is commit and push your code to GitHub, using the "Commit" and "Push" Command Palette commands. After you have pushed your code, all you need to do is open Codeship and you'll see your build there.

🎉 Congratulations, you have just set up your project's continuous integration!

If you've been left behind, you can simply run the following command in your SourceLair terminal to fast-forward here:
git checkout -f step/final

Deploying your code

First we'll deploy the application to Heroku and then we'll set up continuous deployment

Deploying to Heroku from SourceLair

In order to deploy your code, you just need to run the following commands:

  • run the "Heroku: Create" Command Pallete command to create a new Heroku project
  • run the "Heroku: Deploy" Command Pallete command to deploy your Django application to Heroku
  • run heroku run ./manage.py migrate in your SourceLair terminal, in order to set up your Heroku database

That's it! Visit your Heroku URL - the one printed when you deployed your application - and you'll see it running live.

Setting up continuous deployment

Heroku integrates nicely with GitHub, so all you have to do is:

  1. open your Heroku dashboard
  2. select the application you just created
  3. switch to the "Deploy" tab
  4. select GitHub
  5. enter your repository's name and press "Search"
  6. select your repository from the list
  7. click on "Enable Automatic Deployment"
  8. 🎩 enjoy!

You can read more on Heroku's GitHub integration here.

Wrapping up

That was it. Now, each time you push to any branch, Codeship will kick in and start your automated testing suite, while every time you push to master, Heroku will make sure your code will be delivered to production. Easy and nice, wasn't it?

Where you can get

Updates and contact us

You can check out product updates at the SourceLair blog, or learn more about us at State of Progress, where we share our thoughts on software development and management.

Stay in touch

You can reach out to us at Twitter, Facebook, Instagram or email us at [email protected].