Introduction to CI/CD and CMake
What is CI/CD
- CI - Continuous Integration
- Improve: Source Code Delivery, Build, Test (Unit and Integration)
- CD - Continuous Delivery/ Deployment
- Improve: Deployment, User acceptance testing,
CI/CD Tools
- Jenkins
- Open-source mostly focused on CI
- Bamboo
- A CI tool and part of JIRA & bitbucket
- CircleCI
- Good for cross-platform environments (e.g., mobile apps)
- Gitlab CI/CD pipelines
- Integrates with gitlab, various types of pipelines (basic, DAG, multi-project, etc.)
CI/CD Pipeline Best Practices:
- Pipelines could change depending on the development process, teams, production, CI/CD tools, etc.
- Write the pipeline and determine which part can be automated (a lot of it)
- Some stages are necessary in your pipeline, e.g., testing, peer code review (pull requests), etc.
- Separate the stage environments for better management (e.g., use a separate branch on git)
- Devise metrics for transitioning to CD (e.g. test coverage)
Revisit Branching Strategies in git
Branching strategy is a set of rules an policies for creating branches, maintaining them, and merging them to optimize the agility of teams and quality of code
Branching Strategies - GitFlow
- Master: main stable branch
- Develop: main branch for development
- Feature: for new features branched off develop
- Release: for production
- release (testing), merged back to master & develop
- Hotfix: for fixing bugs
GitFlow Pros and Cons
Pros:
- Allows parallel development, production, and fixing bugs
- Organizes the work of the developers naturally
- Allows handling multiple versions (not crucial if using git tags)
Cons:
- Complicated pipelines due to multiple merges
- If a test fails in the master branch it could be difficult to pinpoint the branch that hosts the issue
- Not recommended for amateur teams & for agile CI/CD
Branching Strategies - Github Flow
- Master branch: stable deployable branch
- Feature branches: temporary branches off the master branch to isolate the work of developers. Merged back into the master branch
Github Flow Pros and Cons
Pros:
- Much simpler compared to gitflow
- Allows for agile development and short production cycles
- Allows for fast feedback and easier debugging
- Ideal for small teams
Cons:
- Not suitable for handling multiple versions
- More likely to have an unstable master branch due to lack of develop/release branches (requires good testing pipelines before merging into the master branch)
- Number of merge conflicts grows with bigger teams and slows CI/CD
Branching Strategies - Gitlab Flow
(Middle Ground between Github Flow and Git Flow)
- Master branch: act as the develop branch
- Environment branches: the middle branches before merging to the production branch (staging/pre-production)
- Production branch: the ‘downstream’ stable code in use
Gitlab Flow Pros and Cons
Pros:
- Provides proper isolation between production and development
- Allows for staging environments (testing vs production)
- Great for when the timing of the releases is not under control (iOS)
Cons:
- Requires proper setup of the staging & QA pipelines
- Could be complicated with large teams
Branching Strategies - Trunk-based Development
- Master branch: core “trunk” that received quick and frequent merges (e.g., once a day). Stable anytime
- Feature Branches: short-lived temporary branches that are merged quickly into the trunk (sometimes implemented with flags)
Trunk-based Development Pros and Cons
Pros:
- Avoids merge conflicts by forcing developers to integrate their changes quickly
- Encourages CI/CD due to faster integration and releases
- Enhances collaboration between the team members
Cons:
- Suited for more senior teams
- Requires careful management of features and multiple versions
- Requires streamlining of merging and integration phases (massive pipelines)
Building Systems
Assume we have the following files:
- A file containing the class complex:
complex.hpp
- A file containing the class calVar:
calc.hpp
- A file containing the function parseLine:
parse.cpp
- A file containing the main function:
calculator.cpp
To compile the entire project:
1 g++ -o calc.out main.cpp parse.cppWhat if the directory structure of the project changed?
./PROJECT/
: the project directory./PROJECT/include/
: header files./PROJECT/src/
: the source code files./PROJECT/bin/
: the executablesCompiling from the project directory:
1 g++ -o bin/calc.out src/main.cpp src/parse.cpp -I include
- What if the dependencies changes? For example, using different versions of g++
- If we change any of the files means compiling and linking all the files again
- We only need to recompile the changed file
- Is there a way to streamline the building process in an efficient way?
Building Systems Tool
A software build system is the usage of a set of tools for building software applications
- Putting together several parts of the software efficiently
- Automating the build as a pipeline in our CI/CD
- Each part might be in a different programming language
- We may want to build is for different target machines (execution environment)
GNU-MAKE
Uses a Makefile to issues commands what pieces need to be [re]compiled and [re]linked.
What is a Makefile: a set of rules in the following format:
1 | target ... : prerequisites ... |
A makefile
example
1 | SRC = ./src/ |
To run them:
1 | make |
Another makefile
example
1 | calc.out: main.cpp parse.cpp |
But Makefiles are tedious to make.
A better way is to use a Build System Generator:
- A tool that generates native build system files
- E.g. CMake
CMake
It uses CMake scripting (declarative) language to describe the build
The developer edits the CMakeLists.txt
- invokes CMake but should never edit the generated files by CMake (e.g., Makefiles)
CMake does not compile (remember it is a build system generator), the underlying build system (e.g., make) does, and you have to run that explicitly after running CMake
CMakeLists.txt
Example
1 | cmake_minimum_required(VERSION 3.10) |
Another example
1 | # put the minimum required version for CMake |