Background: Working for a company that designs and develops the best software solutions, my team was challenged with creating new tournament software for one of our clients. For this, we needed to have a CI that could provide multiple options. We wanted to build an Electron.JS app for numerous OS and testing processes to ensure high performance and an automated release cycle. We also wanted to create software to prepare and manage tournaments with multiple instances running on multiple machines, in sync.
Goals: A high performing CI/CD to support software acceleration.
"CI/CD Solutions such as Jenkins have no equivalent on-premise. With Jenkins, you can control everything you do."
Solution and Results:
We had multiple goals for this project in which we relied on Jenkins.
First, we needed our product to be resilient and have a fail-fast pipeline (build, test unit, test E2E, and lint to flag programming errors, bugs, stylistic errors, and suspicious constructs.) The goal was to fail really fast to have a lot of feedback from our CI to improve our productivity. We used a Kubernetes cluster to provision our workers and pipeline tools inside a pod YAML description. This way, we could leverage the charge to the K8S cluster. But the pipeline was slow. It was slow because there were all blank sheets in this environment.
Second, we needed our product to have semantic versioning (SemVer) distributed to clients.
Third, as one of the project’s products is embedded software, we needed to build it for multiple OS: Windows, Mac, Linux.
Finally, we needed to deliver the software to our client with just a simple click. They had given us an FTP server for the release. This process is a bit laborious.
The Jenkins capabilities we relied on included:
The Jenkins-Kubernetes plugin to spin up k8s pod agents with our needed tools leveraging the Jenkins main instance load.
Jenkins’s credentials capabilities help us interact freely with many SCM providers (auto-commit and tag for SemVer).
The Declarative pipeline, which made it easy to read and understand, conditional execution with "when" is strong and useful. The same goes for post-stage conditions "successful" and "unsuccessful." We used it mainly to store our Cypress recording only if the stage failed. We wouldn’t need test recordings if they all passed.
The artifact storage capabilities make it easy to share the executables internally to test really fast. Our PO has a link to our 'latest' artifact so he could keep up with our software without asking us to provide it to him.
The credentials make it easy to integrate software licenses needed for the build.
CI/CD Solutions such as Jenkins have no equivalent on-premise. We need complete control of where the data resides. The most crucial feature of Jenkins is DSL. With Jenkins, you can control everything you do. This has pros and cons; many common things aren’t abstracted by default. We created a DSL and imported it automatically to extend Jenkins' capabilities. This way, we had many of our internal protocols factored for our teams.
We are pleased with the performance of our new CI/CD. With it, we were able to accomplish:
build times that are 2x faster
builds which are more stable using k8s capabilities as agents
automated releases cycles and shortened turnaround times from 2 days to 2 hours
automated semantic versioning based on commit messages