Reading time: 35 minutes | Coding time: 15 minutes
GitHub is a source code management tool that stores source code files of our projects in remote repository. In 2019, GitHub launched GitHub Action, integrated with GitHub that gives the features of CI/CD (Continuous Integration and Continuous Deployment) in an automated workflow which can be used to build, test and deploy our source code files from GitHub.
Continuous Integration: Continuous Integration is a collaborative software product development methodology which encourages each member of the development team to contribute to the central code base atleast once daily so that there are multiple increments to the project every day.
This methodology reduces chances of risk because changes are small and thus chances or errors and bugs missed in testing process are small. Also, CI increases the speed of development.
The process of CI includes following:
- Source Code Repository Management (Implementation)
- Automated Testing (with tools like JUnit etc.)
- Automated Building (using tools like Apache Maven etc.)
Automated Workflow: Whenever a workflow is said to be continuous, automation is a key principle attached with it. Continuity in flow means that the process is not stopping at any stage and is flowing smoothly.
Automation aims to minimize the human intervention for maximizing throughput and efficiency.
This happens when we automate our flow using scripts etc.
An analogy to understand the continuity in Software Development is that a build trigger is created so that whenever a team member pushes source code on a central repository, it is instantaneously merged with central repository, sent for automated testing; if the test passes, it is directly deployed to production environment else feedback is sent to all the members of the project.
Continuous Deployment: Continuous Deployment extends the idea of continuous integration by deploying the final product of the CI cycle (an executable file) to the production environment available for use by the customers after performing extensive automated testing.
Continuous Deployment includes following:
- Unit Testing
- Platform Testing
- Automated Testing
- Deploy to Production
- Post Production testing and monitoring
Events for triggering GitHub Actions: GitHub Actions are generally triggered after a specified event has occurred, event though they may also be invoked using schedulers etc.
Following events are important and commonly used:
1. push: A push event occurs when a file is created, deleted or modified and successfully synchronized with the remote Git repository.
2. pull_request: A pull request is created when changes are made in a separate branch and sent for merging with the main branch after review.
3. delete: A delete event occurs when a file is removed from the Git repository. 4. create: A create event occurs when a file is added in the Git repository.
5. issue: Whenever a issue is opened or closed, the GitHub event may be triggered.
A general list of events has been published by GitHub here
1. Docker: Docker is a virtualization software falling under PaaS (Platform as a Service) category.
It is used for OS level virtualization: It simulates a specific OS type environment called Docker Container based on a Docker Image over the parent OS kernel of the local machine.
Docker Image is a static specification of the virtual environment we want.
Docker Containers are run time entity based on the Docker Image
Docker containers run on the Docker Engine.
Containers are lightweight virtual machines.
2. Scripting: Scripting is used to automate the workflow by defining a set of tasks that will be executed on triggers or on a specified schedule.
Various languages used for scripting are:
a. Shell Scripting
Here, we use Shell Scripting for our GitHub Action automation.
Click here for references to these topics.
Table of Contents
1. Create a Dockerfile for Containerization
GitHub Actions use Docker containers for an isolated environment because:
- They are lightweight virtual machine.
- Portable and can run anywhere using Docker Engine on cloud.
- Secure because environment is isolated.
Docker Engine searches for a special file called Dockerfile which defines the Docker Image.
Here is a simplistic Dockerfile which has to be defined in action-a/ directory on the GitHub repository.
FROM debian:9.5-slim ADD script1.sh /script1.sh RUN chmod +x /script1.sh ENTRYPOINT ["/script1.sh"]
- FROM: from keyword is used to create a container of the specified operating system. Here, Debian, a type of Linux OS is used.
Operating System name may be followed by their versions and special tags.
- ADD: Add command is used to add the files stored on local system to the Docker Container.
Here, script1.sh file has to be copied from the Git repository on the same directory (action-a/) to the / root folder of Docker container of Debian.
- RUN: Run keyword is used to execute a certain command when the Dockerfile is executed.
Here, chmod command is used to give the script1.sh file executable permissions.
- ENTRYPOINT: Entrypoint command is used to execute certain tasks on creation of Docker Container before giving the user an interactive access to the container.
Here, script1.sh file is executed on the entrypoint.
2. Create a Shell Script for automating the workflow
Shell Scripting is used in GitHub action to automate the workflow.
Here, a script1.sh file is created to print the Hello World message.
This script1.sh file is defined in Dockerfile which has to be added to Debian system.
Thus, script1.sh file is to be made in the action-a/ directory with following content:
#!/bin/bash echo "Hello world my name is $MY_NAME" echo "This is tutorial for my blog @OpenGenus"
Here, echo command is used to print the message to the standard output on execution.
MY_NAME is a variable which is not defined yet. It will be covered later.
3. Define the Workflow with a push trigger
Workflow: Generic aim of the GitHub Action
Actions(Jobs): Independent sub-tasks to achieve the workflow.
Thus, one workflow has one or more actions.
For GitHub Actions, we define the workflow and their respective action(s) in the .github/workflows directory in the main.yml file.
Content of main.yml file:
name: A workflow for my Hello World file on: push jobs: build: name: Hello world action runs-on: ubuntu-latest steps: - uses: actions/checkout@master - uses: ./action-a env: MY_NAME: "Nishkarsh Raj"
In this file,
First two lines define the workflow.
name: Name of the workflow.
on: It defines the trigger point of workflow which can be a schedule or an event based trigger.
Here, push is used. Thus on a push event (whenever a file is modified or created in the remote Git repository), the workflow will automatically execute.
Rest lines define the Action (Job) for the workflow.
Jobs: Basic entity of the action for the workflow.
build: Identifier attached with the action.
name: Name of the action to be performed. They uniquely identify an action when multiple actions are defined in the same workflow.
steps: a sequence of operations to be performed in the action.
uses: It is a keyword defining the path of the repository to be used for action (here, action/a) along with the branch for the action (Here, merge)
Another uses keyword defines the actions/ user which is the official account of GitHub Actions and it referes to their checkoutrepository.
env: Defines environment variables to be used
Here, we define the variable MY_NAME which is used in the script1.sh file.
Since we have used the push event for triggering the GitHub action, pushing the main.yml file to the Git repository has already triggered the action.
To see the output, click on the Actions tab on the top bar under the GitHub Repository name on the repository homepage.
It shows the workflow name along with different actions perfomed on each push event.
Click on the latest workflow execution.
The workflow execution consists of four steps:
1. Set Up job: Verify the main.yml file and set up the GitHub action environment
2. Run actions/checkout@master: Configure the environment using the checkout repository of the GitHub Action official account on GitHub.
3. Run ./action-a: Create Docker Container from the Dockerfile specified in the action-a/ directory on our local repository and execute the operations.
4. Complete Job: Deallocate memory and dependencies of the container and give exit status.
Click on Run ./action-a to see the output of the execution of shell script at end of it.
Create a Workflow triggered using pull_request event
In the above example, push event triggered GitHub Action.
Here, we create a trigger whenever a pull request is made in the repository.
In the .github/workflows/main.yml file, replace the on: push command with the following line:
on: [push, pull_request]
Thus, the workflow is now triggered by both a push event and a pull_request event.
This statement can be used to trigger GitHub action only on the Pull request event.
The following image shows the diff between previous version of the file and current version of the file.
Now, make some changes in a new branch so that a pull request can be made to the repository.
Here, we add a comment in the action-a/script1.sh file in the comment branch.
Create a pull request from the comment branch to the master branch.
A pull request undergoes two checks by GitHub Action,
- First check is triggered by the pull request and checks the possible output of the GitHub action after merge.
- Second check is triggered by push event and checks the state of the previous version GitHub Action.
Click on Show all checks to see the detailed report.
Click on Actions tab in the toolbar to see step by step report.
As seen on the left side, our workflow has two actions, one for push event and one for the pull_request event.