Software Management (Part 2) — Continuous Integration

Setting up a GitLab project with Gitlab CI and a Gitlab Runner

Be sure to also check out the other parts of this tutorial:

Finished product: https://gitlab.com/TimoGlastra/softwaremanagementapp


The steps we are going to walk through are:

  1. Create GitLab repository on GitLab.com (or your own GitLab server)
  2. Checking the default GitLab Runner to execute our pipelines and jobs
  3. Create a .gitlab-ci.yml and define our CI jobs

Creating the GitLab repository

We are going to push our boilerplate project to a GitLab repository.

Go to GitLab.com, create an account if you don’t have one, and create a new project. You can do this by clicking ‘New project’ in the upper right corner. Specify a project name and click ‘Create project’.

Now copy the project URL (see image below). By default it uses an SSH URL, if you don’t know what that is, click on SSH and select HTTPS.

Repository URL

Go back to your Terminal / Command Line and execute the following commands:

  • cd into your React Native project folder. e.g. cd SoftwareManagementApp
  • git init (make sure git is installed) to initialize an empty repository
  • git add . to add all files to the repository
  • git commit -m "initalized React Native TypeScript project" to commit the files to the current branch
  • git remote add origin https://gitlab.com/TimoGlastra/SoftwareManagementApp.git to let git know where your repository is hosted. (be sure to replace the URL with your repositories URL)
  • git push -u origin master to push the code to GitLab.

Checking the GitLab Runner

Runners are needed to execute jobs. GitLab.com was so generous to set up some shared runners for everyone that you can use for free. If you have a private repository the runners are limited to run 2000 minutes per month. If your project is public you have no limit to how much CI minutes you can use from GitLab.

For now, we are going to use the free shared runners provided by GitLab. Later on, when we are going to test the native part of the application, we are going to set up our own runner. This is because the shared GitLab runners can’t build/run iOS apps. Even though they can build/run Android apps, we need to set up a custom runner for iOS anyway so why not use it for Android as well.

Diving into the .gitlab-ci.yml file

The .gitlab-ci.yml is the definition file of all our CI jobs. Simply put, it explains to GitLab what it needs to do with our repository to run the tests. The CI file is written in YAML. The official YAML website explains it as:

YAML is a human friendly data serialization standard for all programming languages.

Believing this explanation from YAML.org it’s perfect for explaining GitLab what to do with our repository. There are a lot of ways to configure your .gitlab-ci.yml file which I can’t all explain in this tutorial. If you’re interested in all the possibilities check the GitLab docs here.

For now, we are going to create a dummy job which we are going to replace in the next tutorials. This is just for showing what it can do and how it works. Feel free to experiment a little with the .gitlab-ci.yml file so the definition of the jobs will feel more familiar in the next tutorials.

Creating the .gitlab-ci.yml file

In the root of your repository create an empty file called .gitlab-ci.yml and copy the following text into the file:

A short explanation of the terms used in the file:

stages: A CI job can have multiple stages. Here only ‘testing’ is defined but in a real-world example, for example, a ‘deploy’ stage could be added to automatically deploy a new version of your application after all tests are successful.

  • Stages are run in the order they are defined in the CI file.
  • A stage will only run if the previous stage was successful, this is crucial when you, for example, have a ‘deploy’ stage. Nobody wants to deploy broken code (I hope 🙄).

unit: This is the name of a job to be run. You can name it anything you want, with a few exceptions.

image: This is the Docker image to be used by the runner. It is not a requirement to use Docker, but the free shared runners on GitLab.com are all Docker runners. Later on, we are going to run some jobs outside of docker directly in the shell (a.k.a. directly on your pc) with our own runner.

If you’re not familiar with docker, I really suggest you read a little bit about it to at least understand the fundamentals. I think this site does a pretty good job explaining the basics, but you could also check out the official Docker site. If you’re not interested in learning some of the basics (I can’t imagine why not. It’s awesome) you can just copy what I’m doing and everything should work.

Using docker we can create a new environment every time we run the jobs. This way some bad PC configurations can’t screw up our jobs.

  • We use Node version 10.10 to run this job. We are not executing any code just yet, but we are going to need Node eventually because we are making a JavaScript (TypeScript) application.

stage: Note the lack of the s (stage, not stages). The stage tag defines which stage to associate this job with. We only have one stage so, naturally, we will associate it with the ‘test’ stage.

script: This is where the good stuff happens. The script tag defines all the commands to run. We are only running one command, which echoes the text: ‘Running test job’

  • Same as the stages tag, the commands are run in the order they are defined.

Testing if it works

Sweet! We now have a gitlab-ci.yml file which does basically nothing, but let’s test if this nothing will run. As mentioned earlier, GitLab CI is integrated directly into GitLab and offers free shared runners, so we don’t have to setup anything.

All we have to do is commit and push our code and wait for the magic to happen.

git add .gitlab-ci.yml
git commit -m "Added CI setup"
git push

On the main page of your repository go to ‘CI / CD’ → ‘Jobs’ and click the first and only job. If you’re quick it may still be running. In my case, it was already finished. Take some time to read the logs.

As you can see the only thing it really does is printing the command and not the output. That’s a derp on my side, but it still does what we want; run a practically empty job when we push code to our repository.

The ‘test’ job has passed!

I really hoped you liked this part of the tutorial. When you are ready, be sure to continue with part 3 of this tutorial: Software Management (Part 3) — Testing