Flutter Continuous Integration using GitLab

Part 1 — Building the pipeline and running our tests.

Kieran McCarthy
Version 1
7 min readApr 29, 2021

--

Introduction

With projects big and small, the need for multiple contributors to deliver products to build out great features and deliver ground breaking products adds complexity to how individual changes are to be integrated. Great tools make this less complex through Continuous Integration. A cog in the DevOps process allows for multiple individuals to automate merging changes of their code into a central repository multiple times a day. Each check-in is then verified by an automated build, allowing teams to detect problems early.

By integrating regularly, you can detect errors quickly, and locate them more easily. This is what I will show you how to implement for building Flutter applications using GitLab.

Prerequisites

  • Flutter installed on your local machine.
  • A GitLab account.
  • Git installed on your local machine.
  • SSH key created.

Project Setup

So to get started, we will create a brand new application from scratch which comes with the Flutter scaffold command. But be aware, you will be able to follow the process for your existing projects and applications.

In your favourite terminal create a new Flutter application, you can name it what you like but we named it like below:

flutter create flutterclilab

This will give you a scaffold project to work with using the below folder structure:

Folder structure for created scaffold application.

So I want to see what the tests look like to see what I’m working with. In Flutter you have a folder called test which tells the Flutter/Dart SDK to look within this folder to run its test command “$ flutter test”. Let’s check out what test comes with the existing scaffold:

widget_test.darts contents.

Okay, let's start it up and give it a test run, and when I mean test run I mean Unit Test Run!!

Visual Studio Code is my IDE of choice, so when I want to run my tests, I open Test=>Run All Tests. So let’s see the results out of the bag:

Passed all tests belonging to the project

Great! The unit tests passed straight up. We can now set up our source control.

Personally, I love GitLab. I’ve been using it since I started developing and I love the tools it gives you to run pipelines and how the interface is laid out. So let's set up a new empty project in GitLab. If you don’t have an account just yet with GitLab, setting up an account is very easy and it’s free…which is another reason I love GitLab, as all my earnings pretty much goes on my coffee habits ☕🤯

In GitLab, click New Project and click Create blank project/repository. You will then be given a form to enter your details. Give your project a name and choose the visibility level and click create:

With the repository now set up, we can push our codebase up into GitLab for others to work on.

In your terminal, enter in the commands GitLab provides to Push an existing folder:

cd existing_folder
git init
git remote add origin git@gitlab.com:SmiffyKMc/fluttercilab.git
git add .
git commit -m "Initial commit"
git push -u origin master

If all succeeded, you should see the code base stored in your Project Overview tab!

Visual proof of source code in our source control host.

Building the Quality Gate

Now it’s time to add some manners and rules to how others work with our amazing innovative counter application! We will do this by introducing a Quality Gate.

A quality gate is a set of conditions that indicates if the project analyzed is “good enough for you or not” to be delivered to the next stage in your software life cycle.

So let’s create some branches which will be protected from users pushing their changes without some validation done. Inside the GitLab menu, click on Repository=>Branches. Here, click on New Branch and call it “development”.

We can now switch between the two branches, but we want to now protect the development branch from direct pushing of code without a code review as we will want our developers to use this branch to integrate their changes into.

Click on Settings=>Repository=>Protected Branches. Choose the development branch and set both the Allowed to Merge to Maintainers and Allowed to Push to No One:

Example of the settings

This change protects the branch from people pushing directly into it and allows just the Maintainers of the repository to merge the changes after a Merge Request is made which we will get to soon.

We are now ready to create our Continuous Integration pipeline by building our gitlab-ci.yaml file

Building the CI pipeline with YAML

For our new changes to be made, we need to create a new branch to work on and then push to GitLab to create our Merge Request. To create a new branch enter:

git branch cipipeline
git checkout cipipeline

Inside the root of your project, create a new file called gitlab-ci.yaml. Inside the file paste the below code:

# This file is a template, and might need editing before it works on your project.
# https://hub.docker.com/r/google/dart
image: mobiledevops/flutter-sdk-image:2.0.1

variables:

# Cache downloaded dependencies and plugins between builds.
# To keep cache across branches add 'key: "$CI_JOB_NAME"'
cache:
paths:
- .pub-cache/global_packages

stages:
- analyze_and_test

before_script:
- export PATH="$PATH":"$HOME/.flutter-sdk/.pub-cache/bin"
- flutter pub get
- flutter pub global activate junitreport

analyze_and_test:
stage: analyze_and_test
script:
- flutter analyze
- flutter test --machine | tojunit -o report.xml
artifacts:
when: always
reports:
junit:
- report.xml
tags:
- shared
only:
- merge_requests

Making the Merge Request

Now we can create a merge request to add our new file that will create the CI pipeline for us to analyse our code and to make sure there are no errors and also run our tests!

Run the below commands to add our changes and push these changes to GitLab:

git add .
git commit -m "Added gitlab-ci.yaml file for ci pipeline"
git push --set-upstream origin cipipeline

You should have received a message back from the terminal, something like this:

remote:
remote: To create a merge request for cipipeline, visit:
remote: https://gitlab.com/SmiffyKMc/fluttercilab/-/merge_requests/new?merge_request%5Bsource_branch%5D=cipipeline
remote:

Click on the link which was returned. This is a direct link to create a merge request to request your changes to be integrated into an existing branch or feature. Clicking on it will show something like the below:

Detail entry for merge request.

Once the details are filled in, and you set an Assignee and Reviewer, you can Create the Merge Request. The reviewer and assignee (or me for both for this tutorial 😜) will get a notification that there is a new Merge Request for them to review. I did get a notification, so let's check it out!

Showing the pipeline running after it was created.

Woohoo 🥳! We can see a pipeline has been created and is running! I want to see if the pipeline is successful before merging or reviewing the changes as GitLab will be able to tell us if anything was broken or if any tests failed due to changes! Let's click on the pipeline ID with the hash to view the output of the build:

Output from pipeline build

We can see the commands from the gitlab-ci.yaml file being outputted into the log and can also see that the job succeeded. But where are the tests? Did they succeed? The job didn’t fail so they must have. And we can see after the flutter test command that the job was uploading artefacts.

If we go back to our Merge Request we also see another section:

Section for our tests

Click on “View full report” and you will be able to see all the tests that have passed, failed, or skipped in a nice list for us to view:

An overview of our tests being run and passed in GitLab

I think we are now ready to Merge these changes into our Development branch now. In our Merge Request, simply click on Merge Changes and give the developer a 👍+1.

Conclusion of Part 1

We have created a project, built it a home to reside in, protected its branches, and built it a pipeline to analyse and run the tests associated with it. Not bad for a day's work! But what is important here is building the grounds for a solid quality codebase in which multiple developers will be able to automate their changes and get fast results if something goes wrong, allowing them to make changes correctly.

In the next part, we will implement a code coverage integration to export reports of code coverage from our tests and add a coverage badge to boast. We will also add linting to our Flutter project so developers have to follow the standards and rules made by the code owners and tech leads based on changeable configurations. This will also affect our build, if a linting rule isn’t followed, the build will break and you will get a 👎!

So follow and 👍 this post to be notified when part 2 is created to better protect your projects.

--

--

Kieran McCarthy
Version 1

Software Engineer | Deep Learning Enthusiast | Chat Bot Builder | Coffee Lover | Creator | Practising Writing