The world of programmers is widely associated with coding: dark screens filled with green lines of random digits and weird commands, all being written with surreal speed. Well… no, that’s the Matrix Digital Rain, not real life. Or…is it? 🤓
Now, jokes aside, as a front-end developer, I would agree that most of the time is indeed spent writing lines of code, but what I want to talk about in this article is what happens besides the actual code-writing phase, or what you might know as DevOps.
A CI/CD platform is a comprehensive set of tools that help developers, engineers, and DevOps practitioners package and deliver software to the end users.
Let’s see what happens within a project’s pipeline in order to better understand what Continuous Integration (CI) and Continuous Delivery/Deployment (CD) are.
At Wolfpack Digital, we use Scrum Methodology, meaning we always have a clear structure for our teams in order to deliver incrementally while prioritizing efficient planning, collaborative execution, and continuous improvement. In simpler words, the idea is that we break work down into shippable pieces so that large projects can get completed while the team continues to ship value to the customers on a regular basis.
Instead of building out features in isolation and integrating them at the end of a development cycle, the code is integrated with the shared repository by each developer multiple times throughout the day. Now, what Continuous Integration(CI) refers to is the build and testing stages that get triggered when a commit to the main branch gets done. In other words, with CI, code changes are automatically built and tested in order to have the code always prepared for a release to production.
The build stage of the CI/CD pipeline automates developer contributions and provides tools to standardize software quality and environments, making it easier to address bugs quicker and reduce the time it takes to validate and release new software updates.
After a successful build, the test stage lets you automate unit testing and/or integration testing to provide the most test coverage possible.
As depicted in the image below, what follows next is Continuous Deployment, as it defines an extension of this automation and allows for the software to be deployed after every code commit that passes a test suite without human intervention (e.g., approvals). Continuous Delivery, on the other hand, refers to the preparation for deployment where humans decide if/when/where to deploy.
Source: Continuous Integration (CI) Explained
Each stage in the pipeline acts as a gate that evaluates a certain aspect of the code. Problems detected in an early stage stop the code from progressing further through the pipeline. It doesn’t make sense to run the entire pipeline if there are fundamental bugs in code to fix first. Therefore detailed results and logs about the failure are immediately sent to the team to fix.
There are quite some options regarding CI/CD platforms, such as Jenkins, GitLab, CircleCI, and so on. We will now dig into the more technical part and see how to set up such a CI/CD pipeline using CircleCI on a Nuxt.js app. I will assume the project repository is already linked to CircleCI - check the documentation on the setup steps if needed.
What connects CircleCI to your project is a config.yml file held under a .circleci directory. The good part is that once you connect your repo to CircleCI, on the projects page, you’ll find a “Set up project” button, where the platform provides pre-defined config.yml files that allow you to have a boilerplate file for you to start working on.
From the sample configurations listed, I chose the ‘Hello World demo’ option, which created a demo config file and had the “Commit and run“ button, which led to an automated push to my repository with the file shown in Fig 1. Also, the CircleCI dashboard now shows the first workflow that was run with the “say-hello” job that we see predefined in the config.yml file.
I think the best way to get an overview of what this YAML template means is to take each line at a time and see what’s behind those concepts.
Fig. 1 - config.yml generated file
Fig. 2 - CircleCI dashboard
Think of workflows as the section of the YAML file where everything gets put in place. In the example above, you can see that a workflow’s name is defined and a job named “say-hello“, which was declared above, in the jobs section. A workflow comprises of one or more uniquely named jobs and orchestrates their run order. It is possible to run jobs concurrently, sequentially, on a schedule, or with a manual gate using an approval job.
Jobs are the building blocks of your configuration. Jobs are collections of steps that run commands/scripts as required and are executed as a single unit in an execution environment.
Each job must declare an executor that is either docker, machine, windows, or macos.
The steps section is a collection of executable commands required to complete a job.
In order for your CI/CD workflow to do something with your code, it needs to get the code first. The built-in step checkout does that. It gets the code from your repo so that it can get all files and perform the things you are asking it to do. After this step is performed, the shell commands defined under run will get executed, and the result can be seen in the CircleCI dashboard as depicted in Fig. 2.
Now that we discussed the terminology let’s try to adapt the config.yml file in order to create a job that runs a lint check using prettier and eslint on every new commit.
Fig. 3 - lint job configuration
Supposing we already have the needed packages installed, I added a lint job that uses a pre-built Docker image maintained by CircleCI for Node.js to be able to use the shell commands defined in the package.json file (yarn lint).
The steps section starts with the default checkout step we discussed above, and then we have two named shell commands that will execute sequentially.
Fig. 4 - CircleCI job view
I’ve committed the changes to my repo, and there you go - let’s see how the output looks in the CircleCI dashboard (Fig. 4).
There are the titles defined in the config, followed by the terminal output generated by the commands ✅.
Now the fun part begins! Let’s break something to see how the CI pipeline behaves 😈.
I, therefore, used the yarn remove eslint command to delete this package in order to show how the lint step behaves in this scenario, and voila!
A failed workflow is now visible on the dashboard, and the failed job looks like this:
What I presented in this article were the very basics of using CircleCI within a project, but the capabilities that this platform allows you to do are tremendous, for example:
To sum this article up, let’s recap the benefits and definitions of CI/CD practices:
Continuous Integration is the process that kicks off after a developer checks in code to the code repository, allowing lint checks, builds, and unit/integration tests to run.
Continuous Delivery is the process of packaging up the software artifacts (the ones created during Continuous Integration) and getting them to the state where they are ready to be delivered into an environment like QA, UAT, or Production.
Continuous Deployment is the process of deploying the packaged software (from the Continuous Delivery process) into one or more environments without human intervention. In other terms, this translates into defining another shell command for a deploy job in the config.yml file.
In conclusion, researching CI/CD might be uncomfortable, yet it is a very necessary step that any developer should take the time for. Probably dealing with bash code isn’t your go-to thing, but it definitely helps you understand what goes beneath your front-end frameworks that are so beginner-friendly yet resemble such a small part of what a senior developer’s work is.
Stay up to date with the tech solutions we build for startups, scale-ups and companies around the world. Read tech trends and news about what we do besides building apps.