Setting up a CI pipeline with CircleCI
Tags: circleci, github, docker, testautomation
Published: 2020-05-08 09:04:03

---

title: Setting up a CI pipeline with CircleCI
published: true
tags: circleci, github, docker, test automation
---

Have you ever wondered how to properly setup the Continuous Integration for you new [Github](https://github.com/) repository? Let’s dive deep on it together!

---

### Overview of the tools used

In this tutorial I will help you configure [CircleCI](https://www.circleci.com) to setup your builds, running on a customized [Docker](https://www.docker.com/) image. I will focus on a Python codebase, using [pytest](https://docs.pytest.org/en/latest/) for test automation and [pytest-cov](https://pypi.org/project/pytest-cov/) for coverage reports generation.

In addition, I will explain you how to setup [Code Climate](https://codeclimate.com/), a useful tool to statically analyze your code, and [Codecov](https://codecov.io/), that will help you better visualize the coverage of your code.

---

# **Practical how-to**

_We will take as example the following repository: [tutorial_ci](https://github.com/fabiogallotti/tutorial_ci)._

### Setting up CircleCI

The first thing we need to do is creating, at the root of our repository, a folder _.circleci_, where we will create the file _config.yml ._

As a test, let’s start with the default “Hello World” workflow:

{% gist https://gist.github.com/fabiogallotti/29e1b71c958cd374d9fcf51654eb5660 %}

For the sake of this example, we can directly commit our change on the master branch of your repository.

Then we need to sign up with our Github account to [CircleCI](https://circleci.com/signup/)…

![](https://cdn-images-1.medium.com/max/4444/1*-0T-Ue32cedU27uhB2fz-g.png)

…and select the repository we want to build, clicking on _Set Up Project_ and in the following window, on *Add Manually *and on* Start Building*

![](https://cdn-images-1.medium.com/max/4068/1*uXb5TInZGm5nsdVaDdCZAw.png)

![](https://cdn-images-1.medium.com/max/4084/1*GNpwAWxIU0BXop4W_Zegbw.png)

![](https://cdn-images-1.medium.com/max/3212/1*5ScdFH1gaxH-jGnBlDqkOg.png)

And here it is, our first working build!

![](https://cdn-images-1.medium.com/max/4652/1*jGt-SSihqTUK_Pruba_qDA.png)

---

### Custom Docker Image

As of now, our build is not doing much, so let’s start doing some customization. All what we need to change is the _.circleci/config.yml_ file. (**note:** y*ou can always validate your .yml file using [yamllint](http://www.yamllint.com/).*)

The first customization I want to explain it’s how to generate and use a custom Docker image in your builds. To do so, you need to have an account on [Docker Hub](https://hub.docker.com/), where you will push the image to use.

If you don’t have an existing account, Sign Up and chose the Community plan.

![](https://cdn-images-1.medium.com/max/2432/1*k7zxeYkpgmIzmz54RvVadA.png)

![](https://cdn-images-1.medium.com/max/3708/1*i5f1RBrQUiZjTTkZuFTM1g.png)

Once validated your email, you can start creating a repository, where you can push the image we are going to create. We will call it tutorial_ci and keep it public.

![](https://cdn-images-1.medium.com/max/2836/1*yW7RQsj5M8S8O--oTQQjhw.png)

---

**Let’s create the image!**

As I told you, we will focus on a Python codebase, so for this example we will create, in a folder _docker_ at the root of the repository, the following _Dockerfile_:

{% gist https://gist.github.com/fabiogallotti/3060dcb03fe960e806cd15ebaa36286b %}

and _requirements.txt_:

{% gist https://gist.github.com/fabiogallotti/d3eeddef3795278e89c443f9255ff5c6 %}

In the folder docker, we need to build our image, with the command:

```
docker build -t <your_user_name>/tutorial_ci .
```

and then push it to Docker Hub:

```
docker push <your_user_name>/tutorial_ci
```

Here it is, ready to be used for our builds:

![](https://cdn-images-1.medium.com/max/5136/1*OoIKW0jH0VFNXB16h2pzsA.png)

In the config.yml, we will remove the usage of an external orb, and we will create our customized jobs using our newly created docker image.

{% gist https://gist.github.com/fabiogallotti/e5a9924018a99bd059adecfe9e945a20 %}

To give you a bit of details, we are defining a new job called “hello”, that will run on the image we just created, and will print out “Hello World”. The workflow “hello” will run this job.

![](https://cdn-images-1.medium.com/max/4656/1*4ekldsUVLzQ-nBcaC0E_Ag.png)

---

### Setting up Code Climate

What if we want some static analysis of our code?

We will start [linking our github account to Code Climate](https://codeclimate.com/login/github/join)

![](https://cdn-images-1.medium.com/max/2408/1*-K7XJt98UYQrnAr8LMlc4Q.png)

and adding our repository

![](https://cdn-images-1.medium.com/max/3476/1*YQhaKqGeocYyO6_8vH4pMg.png)

You will be prompt a warning related to having only a Dockerfile at this stage, you can proceed, and you will have your first build completed!

![](https://cdn-images-1.medium.com/max/2136/1*V1y0TBOVZk9DEGjyHQ5pQQ.png)

In the Repo Setting, Github tab, enable all the features clicking on the first _Set Up_; this way you will allow Code Climate to provide useful comments in your Pull Request.

![](https://cdn-images-1.medium.com/max/3500/1*Ait7fTwaFOhTvhukR8W11w.png)

Give permission to Code Climate:

![](https://cdn-images-1.medium.com/max/2344/1*AfTq22xJ030-OyLaTGuYzA.png)

Code Climate offers also the possibility to have some visualization of the coverage of your code.

![](https://cdn-images-1.medium.com/max/4544/1*L2eynZkNFwQjiRJDq7054w.png)

Let’s configure it in our _config.yml_:

{% gist https://gist.github.com/fabiogallotti/0a0a1a98257c19365430210a39f8fe9d %}

We first setup the test-reported, before the run of the test. Then we use pytest to run the tests, and we generate a coverage.xml file. Finally we upload the results to Code Climate.

There is one step missing though! We need to configure an Environment Variable in our CircleCI, in order to have everything working. Let’s do it, from the Project Settings.

![](https://cdn-images-1.medium.com/max/5608/1*d26RVBhcT-StGnid9PNR0A.png)

The variable we need to add is called CC_TEST_REPORTER_ID, and the value for it is available in the Repo Setting of our Code Climate account: (_I regenerated mine after taking the screenshot_)

![](https://cdn-images-1.medium.com/max/4364/1*jv_z9Oyo0cX9zg4gWiDVtA.png)

Once we add it, this is what we have:

![](https://cdn-images-1.medium.com/max/4072/1*fPnTzXH0lvj6yPIjYjo13w.png)

If we then push our changes to the central repository, we will have a failed build, because we don’t have any code yet.

![](https://cdn-images-1.medium.com/max/4644/1*EEHeFXXQFRfNmPy9QUfNZw.png)

Let’s create a basic function and a test to in order to have some results:

{% gist https://gist.github.com/fabiogallotti/2fa9ac1bd1780fd32e2483da8bbf9a0c %}

{% gist https://gist.github.com/fabiogallotti/47342523e75ea6a5e7f1a0b7c6e801d6 %}

Now the build it’s green, and we have our statistics on Code Climate!

![](https://cdn-images-1.medium.com/max/4640/1*Zk5fLuhwiIi2qQmnZW9Dlg.png)

![](https://cdn-images-1.medium.com/max/4520/1*AiZRhztd5sQlQsWEtc0eyQ.png)

### Setting up CodeCov

And what if we want some more coverage visualization for our code? Maybe even detailed at Pull Request time? CodeCov will help us on this.

Again, we will [link Github and CodeCov](https://codecov.io/gh).

![](https://cdn-images-1.medium.com/max/5424/1*CRJK8E1Vxa4ZaApgLbZI0w.png)

We will need again to create an Environment Variable in CircleCI, CODECOV_TOKEN, and you will find your token directly when you add the repository to CodeCov.

![](https://cdn-images-1.medium.com/max/4660/1*9QEow4rMNQ3oIcWrVo-m9A.png)

As before, in the Project Settings of our Repository in CircleCI, we will add the needed variable.

![](https://cdn-images-1.medium.com/max/4096/1*wc9DhJlo4GVU0FmGCFY6pQ.png)

Then, we need to customize our config.yml adding the Send to codecov step:

{% gist https://gist.github.com/fabiogallotti/8d18849d55d3b3ce40e3bdf1eb7cab09 %}

And here is the result on CodeCov:

![](https://cdn-images-1.medium.com/max/4680/1*y9IVdkQRHzzYPobDFI-Kew.png)

As latest step, we can also customize the coverage that is run, in order to not run agains the tests folder. What we need to do is simply to add a .coveragerc file, like this one:

{% gist https://gist.github.com/fabiogallotti/c0cd89f9a2b82e332cf931663e0d4092 %}

If we open a Pull Request for this change, we can see how CodeCov is directly adding a comment in it, reporting the result of its analyses:

![](https://cdn-images-1.medium.com/max/3048/1*zFU2w0MuQluBWBCUf0cofQ.png)

### Configurations of builds for Pull Requests from forks

The last thing I want to show you in this tutorial, is how to properly setup builds also for Pull Request from any fork.

In the Project Settings, Advanced tab, you have to enable the options:

- **Build forked pull requests,**

- **Pass secrets to builds from forked pull requests,**

- **Only build pull requests,**

- **Auto-cancel redundant builds.**

---

To end my tutorial, I would like to add two things:

- first one, you can ensure that these checks are ran before merging any of your Pull Request, creating Branch protections rules in Github:

![](https://cdn-images-1.medium.com/max/4240/1*NJj0yU95WGqd45-JGLVjxA.png)

![](https://cdn-images-1.medium.com/max/3000/1*dYNRyjFADwxhzGM814THsA.png)

- and that you can, for each one of the tools I spoke about today, add a badge in your [README.md](https://github.com/fabiogallotti/tutorial_ci/blob/master/README.md).

![](https://cdn-images-1.medium.com/max/2680/1*og65k5llzaFY4ML_W4a5Tg.png)

---

We reached the end of this long tutorial, I hope you enjoyed it and that you will benefit from it!