Learn CI/CD Pipelines with GitHub Actions 🤗
Tags: cd, ci, github, devops
Published: 2023-04-15 15:31:42

Software Development has evolved a lot, and Continuous Integration and Continuous Deployment (CI/CD) play a significant role in it. When we talk about CI/CD, there are two primary tools that we talk about. First is GitHub Actions and second is Jenkins.

In this blog, I will be taking you through the following things:

- Understanding CI/CD.
- How GitHub Actions work.

### Understanding CI/CD

CI/CD is Continuous Integration and Continuous Deployment. To understand these terms let’s look at the following workflow diagram:


![CI/CD](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gwps8vtqafvga8xlwceh.png)

This is the bird's eye view of the CI/CD pipeline. Developer writes some code and pushes it to the remote repository, which is in most cases handled by GitHub. From GitHub, application code goes through the build and test processes in some remote machines. Build and Test processes comes in a continuous integration phase. In the continuous deployment phase build and test code in used to create docker images, which can later be used to create containers, which are used for Kubernetes Cluster.

### How GitHub Actions is used for CI/CD

GitHub Actions is a tool that does certain actions on the occurrence of a particular kind of event. An event can be a push to the repository, an issue raised, a pull request, a first contribution, etc. Any event that can be recognized by GitHub can be used to trigger some action. To see all possible events check out GitHub Action [events](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows).

We tell GitHub Action what to do and when to use YAML files. Inside the YAML file, we write workflow. Simply a workflow is a collection of job definitions that will be executed concurrently as well as sequentially. A job consists of several steps which will be executed sequentially. By default, jobs run in parallel, but we can specify the dependence of one job on another, then the dependent job will start only when the job on which it depends on finishes its work.

To better understand the workflow look at the diagram below:



![Dependency GitHub Actions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6owx9272axtgoeksg88.png)

### Location to store YAML file in GitHub

All the YAML files related to GitHub workflow

### How to write workflow in the YAML file

**Comments:**

You can write comments by starting the line with a ‘#’.


![Comments YAML](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/18ql8al72fy6woba7pw6.png)

**name**:

We can start by giving workflow a name using the ‘name’ keyword, although it is not must to have it. If you do not provide a name to the workflow it will take the name as the name of the YAML file.

**on**:

Using the ‘on’ keyword we can specify the type of actions on which certain task has to be performed. We can only specify this only at one place in the code, i.e. you cannot have two ‘on’ in the file.

Ways of writing content inside ‘on’ section:

`on: push`

`on: [push, pull_request]`

```
# events on which actions should be triggered
on:
  push:
    branches: [ "main" ]
```

Check out more ways of writing this [here](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions).

Generally, it comes just after the name in the workflow file.

**env**:

Inside the env section, you can specify some key-value pairs, which can be used later inside the file. For a value, you cannot use a key inside the env section.

Example:

```cpp
env: 
	ARTIFACT_NAME: Shivam
```

When there is more than one environment variable with the same name, GitHub uses the more specific one. We will see how this works in the later example.

**jobs**:

We can write one or more jobs inside the workflow file. By default, jobs run in parallel, but we can also set some dependencies between the jobs, so that if one job is dependent on another then it will only start executing when the job on which it depends finishes its work.

Way of writing jobs:

```cpp
jobs:
	job1:   # identifier
		name: Job1
	job2:
		name: Job2
	job3:
		name: Job3
		needs: [job2]
```

In the script above, we have specified three jobs with identifiers and names. We must have an identifier for the job but the name is not always required. In job3, it is mentioned that it depends upon the job2, which means it will start executing only when the job2 finishes its work.

Inside the job, we mention a few other things like runs-on and steps. Runs on tell the workflow on which virtual machine this job has to be performed and the steps inside the jobs section tell the steps with which the job will be performed.

**steps**:

A job contains a sequence of tasks called steps. Steps can run commands, run setup tasks, or run an action in your repository, a public repository, or an action published in a Docker registry.

‘uses’ and ‘run’ are used under jobs to tell the command or action to be performed.

We can also use ‘env’ under jobs.

```
steps:
      - name: Print a greeting
        env:
          MY_VAR: Hi there! My name is
          FIRST_NAME: Shivam
          MIDDLE_NAME: Kumar
          LAST_NAME: Pandey
        run: |
          echo $MY_VAR $FIRST_NAME $MIDDLE_NAME $LAST_NAME.
```

From what we have learned till now let us see how we can write files for continuous integration.

### Continuous Integration with GitHub Action

Let’s have a look at the following YAML file. I have taken the example given below from GitHub page itself.

```jsx
name: GitHub Actions Demo
run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
on: [push]
jobs:
Explore-GitHub-Actions:
runs-on: ubuntu-latest
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
- run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
- name: Check out repository code
uses: actions/checkout@v3
- run: echo "💡 The ${{ github.repository }} repository has been cloned to the runner."
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
- name: List files in the repository
run: |
ls ${{ github.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
```

Let's look at all the keywords of the above GitHub action file. Starting with 

`name` using the name we are giving the name to this GitHub workflow as GitHub Actions Demo.

`run-name` using the run-name we give the workflow runs a name.

`on` using the on, we tell the workflow when to trigger some action.

`jobs` using the jobs, we tell the workflow that whatever is under the jobs keyword will be used to specify how and where the job is going to take place.

`runs-on` using the runs-on, we tell the workflow what kind of virtual machine should be used.

`steps` is containing the sequence of commands that should be run.

`run` is used to specify a single command to run on the virtual machine.

`uses` is used to specify the location and version of a reusable workflow file to run as a job.

I hope this will help to kickstart your GitHub action learning.

To dive deep into GitHub action check out their [docs](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions).

Support it by giving it a like 😊.