The development of any software project is not easy. There are plenty of places to go wrong and burn up valuable resources – time and money. What makes software development cheaper in a long term? Every unit test saves some time. Even better if it is automated.
Unit test automation is only a fraction of the CI/CD capabilities. Therefore we will explain the very basics of CI/CD systems along with the best practices for introducing them in any desktop or mobile Qt project. There will be also an example of setting up a CI system for cross-platform Qt applications.
This blog post is a written form of the talk I had during the Qt Developer Conference by KDAB in June 2022. Thankfully it was recorded and you can watch it on YouTube.
Why to introduce continuous integration in any software project?
Before I list the benefits of introducing a CI system to your project, let me give you an example of how to not develop apps. Before I launched Scythe Studio, I worked on a desktop Qt application for a year as a developer. The program was developed by one programmer for 10 years.
The code base was huge, but the problem was no time for making things properly. For managers refactoring or CI/CD was a waste of time. And surprisingly after this time, the code grew in an uncontrolled way causing a lot of issues with building the program along with dependencies.
All the scripts and everything was working only for that one developer. Basically, he was the only person who was capable of releasing this application on Windows. Involving other developers was problematic.
I joined the company. I told the manager, that we should introduce a CI/CD with unit tests and also with installer generation as we have been giving Windows version to testers often. It would automate things. Also, then other developers than the main one could release the app.
There were also other Windows-only apps that deserved CI/CD, so the potential to save time with continuous integration was huge. There was no green light for this, so I finally gave up after many attempts of convincing management.
After some time, I got a request to release the macOS version which was not done for at least 2 years. It took me a long time to not only adjust the app to a newer Qt version but also to a newer mac OS version. I have done it also with fancy scripts to make it automated, but because of the lack of the CI/CD system, I was the only person to release the macOS Qt-based software version.
What does this story from my personal experience teach us? What are the benefits of introducing CI/CD?
Reduced personnel risk
If you have a CI/CD system running in containers or a corporate server (so-called runner), you do not depend on the setup of a single developer. It is not that big of harm when somebody leaves your organization.
Reduced risk of mistake
Having a continuous integration setup allows you to quickly find and solve the issues at the build and unit test stages. This benefit is multiplied by every target you add to the setup.
Saving time and nerves
If the process is executed automatically in the pipeline, nobody needs to do it manually. The various CI/CD steps can take quite a long time, so this benefit really matters. You can also release apps or share test versions more often thanks to CI/CD.
This benefit is connected to the previous one. Not having to do something manually is comfort itself. Moreover, CI/CD setups make development, testing, and releasing cycles more straightforward.
Usually, setups are organized in steps. Therefore, with a proper CI/CD system you have an entire (or partial) process of giving the software to the user documented! You have it coded, so this is not secret knowledge known to a select few within the company.
True profit from introducing continuous integration
As you can notice all of these benefits boil down to two things. To time and safety. Those are the actual benefits of introducing CI/CD to the project. And being the CEO of the company taught me that money, and safety are the biggest concerns. CI/CD has a real impact on the business. That’s why this topic should be important also from a business perspective.
Basics of CI/CD systems
I hope that I convinced you that it is worth having CI/CD system for your project. It actually doesn’t matter whether it is a Qt project or not. It’s always beneficial to introduce it. Now let’s actually explain what the CI/CD system is and what it can look like for applications coded using the Qt framework.
What is continuous integration (CI)?
CI stands for Continous Integration and by that, I understand everything that you need to do to ensure that your software is in a releasable state. Everything that you check before you say that this version of SW is ready to see the light of day. What are the typical steps to put in a CI system for Qt apps?
- Static code analysis
- Smoke screen tests
- Unit and integration tests
- GUI tests
What is continuous delivery (CD)?
CD stands for Continuous Delivery or Continuous Deployment. Those are things that you have to actually release the newest software version like preparing installers and giving it to the user. What CD steps can you introduce in your setup for Qt projects?
- Codesigning app bundles
- Pushing app bundles to app stores
- Sending app bundles or installers to the server
Our typical CI system for cross-platform Qt application
The content of the CI/CD setup can be very different. It all depends on your project and standards. We all know that Qt projects are very varied. Below is a picture demonstrating the system for cross-platform Qt applications that we introduce in Scythe Studio whenever we start new projects that target Windows, Linux, macOS, iOS, and Android. Or a subset of those platforms.
However, all of that doesn’t matter. I’m not the one to tell you what you have to put in your CI/CD pipeline. I’m showing you that just to inspire you.
What tools build up a CI/CD system?
You already know what CI/CD is and what makes it up. Let’s now discover the tools needed to set up a CI/CD pipeline.
Code hosting service
In most of the projects we already use code hosting services like GitHub, BitBucket, or GitLab. Therefore, it should be nothing new to you. We need it as most of the CI/CD solution integrates with git repositories, so the pipeline can be executed as soon as you commit and push something to the repository.
CI/CD solution is something that triggers and manages the execution of the pipelines (sets of steps). There are many solutions and they have various approaches, but that’s something you have to choose. There are solutions that are parts of code hosting services like GitHub Actions or GitLab CI/CD, but there are also solutions like Jenkins that are universal and do not depend on the code hosting service.
Which solution should you choose for start? Go with the most straightforward one. If you host your code on GitHub, try GitHub Actions. If you use GitLab, try GitLab CI/CD. The most common choice for those using BitBucket is Jenkins.
CI/cd tasks runner
You will also need a runner – a device that will execute the pipeline tasks. Currently, you do not need to have a physical device for many tasks as you can use employ Docker and do things in containers on shared GitLab runners. Of course, it is also a security concern. The preference here should be to have your own device.
A sweet way of doing CI/CD for Qt apps is by using the aforementioned Docker. In containers, you can run qmake, CMake, compile apps, and create files ready to install or to push to AppStore. In a container, you can install chosen Qt version, Android SDK, or whatever you want. However, this is only possible for Qt projects targeted at Linux and Android.
To perform all the necessary CI steps for Windows, macOS, and iOS you would most likely need a physical device. If you are looking for the simplest solution to start, I can recommend buying Apple Mac Mini. They are relatively cheap and on one single device, you can run the pipeline for all the platforms targeted by your Qt application. For Linux apps you can install Docker and to compile Windows apps, you can install a VM on Mac Mini.
If you want to keep prepared application bundles or install files, you may want to introduce an artifacts repository. It’s like a warehouse for everything that is generated during the pipeline’s execution. It is optional.
GitLab example for Qt project setups
GitLab is a code hosting solution that is often used by Qt users. Using it you can implement all the necessary actions to have a running and shiny pipeline. To integrate your CI/CD scripts in GitLab, all you need to do is filling a special yaml file.
.gitlab-ci yaml file is a place where you provide details of the stages and jobs building the pipeline. In there using environment variables and special tags you can select commands to be executed, Qt framework version, Android SDK version, runner, and anything that you want to use in a particular situation.
Talk is cheap, go straight to the demo project making such a pipeline. It’s on this GitLab repository.
In the end, I wanted to encourage you to start thinking about CI/CD setup as a must-have and not a nice-to-have. It has a real impact on the business and developers’ work. In the video from QtDevCon, there are a bit more insights and tips shared. Including creating setups for legacy projects. Make sure you check it out.