CI/CD (Continuous Integration/Continuous Delivery or Deployment) are methods to deliver applications with more frequency by using automation. CircleCI and Codecov are tools that can help you with this task.
Continuous Integration
Continuous Integration is when you develop a new feature and it is tested and consolidated with the shared repository. This automated process will provide some advantages like:
- Catch Bugs 🐛
- Reduce merge conflicts ✅
- Ensures the quality of the code 🔎
Continuous Delivery or Deployment
Continuous Delivery or Deployment refers to automation on the advanced parts of a pipeline. The main difference between them is:
- Continuous Delivery 📦 — Develop to release at any time.
- Continuous Deployment 🤖 — Deploy new features immediately
This means that on Continuous Delivery there needs to exist human approval for a new feature to be released and on Continuous Deployment that feature will be automatically deployed into production without any human interaction, which will require some very robust test suites.
CircleCI
CircleCI is a tool that will allow you to implement CI/CD on your project. It is pretty easy to create a YAML config, mainly because they provide excellent documentation. It may take between 5–10 minutes to configure a project.
Configuration
The first step is to create an account on CircleCI with your GitHub account. Then, you’ll need to set up the project you want on the CircleCI website. On the left tab, press the “Add projects” tab, which will take you to the following page that displays all your Github projects.
Then it will open a page with instructions to Set Up the project. There you will have a list of steps you have to follow.
Config.yml file
The first step is to create a folder named “.circleci” and add a file inside called “config.yml” with the following content:
-- CODE language-yml line-numbers --
version: 2<br>
jobs:<br>
build:<br>
docker: <br>
- image: circleci/ruby:2.4.1 <br>
steps: <br>
- checkout <br>
- run: echo "A first hello"<br>
This is the simplest config file that will only display a message on the CircleCI console. Push these changes to your GitHub repository. On the CircleCI page, you were before press the “Start Building” button.
After this, you will see the end-result right away.
Now, let us take a look at an important step called “checkout” which will retrieve the GitHub code into the CircleCI machine. To do this, edit the “config.yml” file with this:
-- CODE language-yml line-numbers --
version: 2<br>
jobs:<br>
build:<br>
docker:<br>
- image: alpine:3.7<br>
steps:<br>
- checkout<br>
- run:<br>
name: The First Step<br>
command: |<br>
echo 'Hello World!'<br>
echo 'This is the delivery pipeline'<br>
- run:<br>
name: Code has arrived<br>
command: |<br>
ls -al<br>
echo '^^^That should look familiar^^^'<br>
To show you that it retrieved all the code from the GitHub project the code above will also show you the file system inside the CircleCI machine
Before diving into more complex configurations let us talk about CircleCI Workflows which will let us make Continuous Delivery or Deployment.
CircleCI Workflows
Workflows let you define collections of jobs and their run order. This will increase your software development trough:
- Faster feedback ⚡️
- Shorter reruns 🏃
- More efficient use of resources 🌿
Besides this, with workflows you can:
- Run and troubleshoot jobs independently with real-time status feedback 🔧
- Schedule workflows for jobs that should only run periodically 🗓
- Fan-out to run multiple jobs in parallel for efficient version testing 🎯
- Fan-in to quickly deploy to multiple platforms 🚀
Workflows come in four different types:
- Scheduling/Cron — Allows you to define a schedule for jobs that should only run periodically 🗓
- Approval — Provides control over steps that need manual approval to continue 👍
- Branch specific — Allows you to specify which branches a build should run on 🌴
- Tag specific — Allows you to specify which tags a build should run on 🏷
With all this said, let’s see how it works!
Workflow set up
The first step to create a workflow is by editing the config.yml file. Where we will define the jobs and then the workflows.
On top of the file we create our jobs, and on the bottom of the file, we create the workflows:
-- CODE language-yml line-numbers --
version: 2<br>
jobs:<br>
Hello-World:<br>
docker:<br>
- image: alpine:3.7<br>
steps:<br>
- run:<br>
name: Hello World<br>
command: |<br>
echo 'Hello World!'<br>
echo 'This is the delivery pipeline'<br>
I-Have-Code:<br>
docker:<br>
- image: alpine:3.7<br>
steps:<br>
- checkout<br>
- run:<br>
name: Code Has Arrived<br>
command: |<br>
ls -al<br>
echo '^^^That should look familiar^^^'<br>
Run-With-Node:<br>
docker:<br>
- image: circleci/node:10-browsers<br>
steps:<br>
- run:<br>
name: Running In A Container With Node<br>
command: |<br>
node -v<br>
Now-Complete:<br>
docker:<br>
- image: alpine:3.7<br>
steps:<br>
- run:<br>
name: Approval Complete<br>
command: |<br>
echo 'Do work once the approval has completed'<br>
-- CODE language-yml line-numbers --
workflows:<br>
version: 2<br>
Example_Workflow:<br>
jobs:<br>
- Hello-World<br>
- I-Have-Code:<br>
requires:<br>
- Hello-World<br>
- Run-With-Node:<br>
requires:<br>
- Hello-World<br>
- Hold-For-Approval:<br>
type: approval<br>
requires:<br>
- Run-With-Node<br>
- I-Have-Code<br>
- Now-Complete:<br>
requires:<br>
- Hold-For-Approval<br>
Did you spot which type of workflow this is? It is an Approval workflow because, as you can see, the “Hold-for-approval” job is type “Approval”. This means that this workflow will only end when an allowed user approves it and for this, we can conclude that this is also a Continuous Delivery pipeline.
The following images show how this workflow is shown in the CircleCI interface and how we can approve this pipeline.
After all of this information, let’s apply it to a real project. First off, we will create some basic functions and some basic tests so that we can run the CircleCI tests and check if everything is going smoothly.
Basic functions
-- CODE language-js line-numbers --
function sum(a, b) {<br>
return a + b;<br>
}function sub(a, b) {<br>
return a - b<br>
}function multiply(a, b) {<br>
return a * b<br>
}function divide(a, b) {<br>
return a / b<br>
}<br>
module.exports = {<br>
sum,<br>
sub,<br>
multiply,<br>
divide,<br>
}<br>
Basic tests
-- CODE language-js line-numbers --
const {sum, sub, multiply, divide } = require('./index')test('Adds 1+2 and expects 3', () => {<br>
expect(sum(1,2)).toBe(3)<br>
})<br>test('Subtracts 2-1 and returns 1', () => {<br>
expect(sub(2, 1)).toBe(1)<br>
})<br>test('Multiply 2 and 2 a return 4', () => {<br>
expect(multiply(2, 2)).toBe(4)<br>
})<br>test('divides 4 per 2 and returns 2', () => {<br>
expect(divide(4, 2)).toBe(2)<br>
})
After creating this, we have to edit one of the jobs on our config.yml file so that it installs and runs our tests.
Since we already have a “Run-With-Node” job let’s edit it.
-- CODE language-yml line-numbers --
Run-With-Node:<br>
docker:<br>
- image: circleci/node:10-browsers<br>
steps:<br>
- checkout<br>
- run:<br>
name: install and run tests<br>
command: |<br>
yarn install && yarn test<br>
With this, we have all set up to run tests on CircleCI which will output something like this:
And that’s it for CircleCI 🎉 Now before jumping into Codecov on part 2 let’s just protect our master branch so that we are not able to push changes into master before all the tests run.
This can be easily made by going into the project settings, then accessing the “Branches” settings and add a rule where we protect the master branch and mark the “Require status to pass before merging”, selecting also all the status checks we want.
All is done in this part! 🎉 🥳
Head over to part two to continue the tutorial.