Automate your software workflow with GitHub Actions and boost development efficiency. Also, learn how to build, test & deploy code directly from your GitHub repository to save your time effectively:
This article illustrates the efficiency of GitHub Actions in streamlining CI/CD processes directly within the GitHub platform, making external integrations redundant.
GitHub Actions is an inbuilt CI/CD platform that allows you to automate, build, test, and deploy applications.
Learn to Use GitHub Actions: Step-by-Step Guide

What are GitHub Actions
GitHub Actions are typically event-driven, meaning you can run a series of commands after an event. For example, when someone creates a pull request or a GitHub issue.
Below is the GitHub Actions Workflow process, which we will see in action through a few examples.

Workflows are triggered automatically when an event occurs. A workflow contains a job. The job then includes and uses steps to control the order in which actions are run. Each job will run on a runner, which is a virtual machine or even inside a container.
Here is a simple video on GitHub Actions:
GitHub Actions provides support for Linux, Windows, and MacOS virtual machines. These runners can be self-hosted in your data centers or on the cloud.
In this article, we will look at specific examples using self-hosted runners.
Key Components of GitHub Actions
Workflows: Workflows comprise one or more jobs and can be scheduled or triggered by an event. Many pre-defined workflow templates are available in GitHub Marketplace, which will be a good starting point.
GitHub workflows are written in YAML. The workflow refers to the .yml (YAML) file and is placed in .github/workflows directory
The GitHub repository can have multiple workflows. One for Build only and the other for the Deploy process.
Events: An activity that triggers a workflow. For example, activity can be when a user pushes a commit to a repository or when the pull request is created.
Example: Using a single event
# Workflow is triggered when code is pushed to any branch in a repository
on: push
Example: Using multiple events
# Workflow is triggered on push or pull request events
on: [push, pull_request]
Example: Using a particular branch (feature)
on:
# Workflow trigger on push or pull request, only for the feature branch
push:
branches:
– feature
pull_request:
branches:
– feature
Job: A job is a series of steps that is executed on the runner as shown in the above diagram
Step: A step is an individual task that can run commands in a job. A step can be either an action or a script.
Actions: Actions are commands that are added as steps in a job. One can create your own actions, or use actions that are created by the GitHub community. We will see how to use an action in a workflow and include it as a step.
Further Reading => Managing GitHub Repository – A Complete Study
GitHub Hosted Runners
GitHub offers hosted runners as virtual machines with Linux, Windows, and MacOS operating systems, which are used to run the workflows
Available GitHub-hosted runner types as described in https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners are:

In the GitHub Actions workflow (YAML file) we will reference the above hosted runner as
runs-on: windows-2016
GitHub Self-Hosted Runner
You can host your runners and customize the environment used to run jobs in your GitHub Actions workflows. Self-hosted runners can be on-premise physical machines, virtual machines, or on the cloud. This self-hosted runner offers better control over the hardware, OS, and software tools to be used.
We will add self-hosted runners at the repository level, which is for a single repository. It can also be applied at an Organization level for multiple repositories or at Enterprise level for multiple organizations.
Once configured the runner machine connects to GitHub.
Supported self-hosted runners are mentioned in Supported architectures and operating systems for self-hosted runners
Adding a self-hosted runner to a repository
To add self-hosted runners to a single repository, follow the below steps:
On the main page of the repository.
- Click Settings.
- In the left sidebar, click Runners under Actions.
- Under “Runners”, click on the Add Runner button.
- Select the operating system (Windows) and architecture (X64) for the self-hosted runner machine.


Open the PowerShell window on your Windows machine and run the commands as shown.
PS D:\actions-runner> [Net.ServicePointManager]:: SecurityProtocol = [Net.SecurityProtocolType]::Tls12
PS D:\actions-runner> Invoke-WebRequest -Uri https://github.com/actions/runner/releases/download/v2.278.0/actions-runner-win-x64-2.278.0.zip -OutFile actions-runner-win-x64-2.278.0.zip
PS D:\actions-runner> dir
Directory: D:\actions-runner

PS D:\actions-runner> Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::Extract
ToDirectory(“$PWD/actions-runner-win-x64-2.278.0.zip”, “$PWD”)
PS D:\actions-runner> dir
Directory: D:\actions-runner

PS D:\actions-runner> ./config.cmd –url https://github.com/vniranjan1972/HW-Maven-Repo –token AETIUMKYPSD6SLEEB4OYSZTA2272W

# Authentication
Connected to GitHub
# Runner Registration
Enter the name of the runner: [press Enter for L-0310] AG-VN-Runner
This runner will have the following labels: ‘self-hosted’, ‘Windows’, ‘X64’
Enter any additional labels (ex. label-1,label-2): [press Enter to skip]
Runner successfully added
Runner connection is good
# Runner settings
Enter name of work folder: [press Enter for _work]
Settings Saved.
Would you like to run the runner as a service? (Y/N) [press Enter for N]
Note: As an admin before starting the runner please set the execution policy in the PowerShell window
Set-ExecutionPolicy RemoteSigned


The self-hosted runner is now added successfully.

# For each job use the below YAML in your workflow file
runs-on: self-hosted
Creating the First GitHub Actions Workflow
Example 1: From your repository on GitHub, create a new file in the .github/workflows directory named hello-world.yml

Copy the following YAML contents into the hello-world.yml file
name: hello-world
on: push
jobs:
firstjob:
runs-on: self-hosted
steps:
- name: Printing my name
run: echo "Hi Niranjan, Welcome to GitHub Actions"
Understanding the above workflow in order
- Name of the workflow as it will appear in the Actions tab (This is defined by name field)
- Trigger the workflow based on the push event (This is defined by on field)
- The above workflow contains only one job with the name of firstjob.
- The job runs on a self-hosted runner and not an inbuilt hosted runner (This is defined by the runs-on field)
- The job contains only one step by the name Printing my name and executes an echo command only
Commit the changes to the main branch.

Go to the Actions tab and click on the workflow to view the result of the run.


So next time when a change is made to the code and pushed to the repo the workflow will be triggered.
Example 2: Print the GitHub repository name, workspace directory, and other default environment variables
Also, refer to the Default environment variables
name: hello-world
on: push
jobs:
firstjob:
runs-on: self-hosted
steps:
- name: Printing my name
run: echo "Hi Niranjan, Welcome to GitHub Actions"
- name: Print GitHub Repository
run: echo $env:GITHUB_REPOSITORY
- name: Print GitHub Workspace
run: echo $env:GITHUB_WORKSPACE
- name: Print GitHub Workflow Name
run: echo $env:GITHUB_WORKFLOW
- name: Print GitHub Workflow Initiator
run: echo $env:GITHUB_ACTOR
- name: Print GitHub Runner Name
run: echo $env:RUNNER_NAME
- name: Print GitHub Runner OS
run: echo $env:RUNNER_OS

GitHub Marketplace
In a typical DevSecOps flow we will need to perform SCM checkout wherein a copy of the source code repository is downloaded onto your build machine where the runner is running and then build is performed e.g., maven build, code analysis using SonarQube, unit testing, pushing the build artifact files to a binary repository manager like Nexus or Artifactory and then deploy to tomcat etc.
GitHub Marketplace allows us to find specific apps/actions for use across the entire DevSecOps flow (CI/CD/CT) as described above.
GitHub Marketplace can be browsed @ https://github.com/marketplace

One can think of this as similar to Jenkins plugins. Let’s see how to make use of these apps or actions in our workflow.
Java Maven Example – Build and Deployment Workflow
Example 1: Below is the workflow showing a Maven Build
In the Actions tab click on New Workflow and enter the contents of the YML file
name: CI and CD with Maven
on:
push:
branches: [ master ]
jobs:
build:
runs-on: self-hosted
steps:
- uses: actions/checkout@v2
- name: Build with Maven
run: mvn clean install
Go to the Actions Tab and click on the job to view the log.

| In the workflow there is a line which mentions the below under steps – uses: actions/[email protected] | This action checks-out your GitHub repository to the GitHub Workspace in the runner machine so that you can run various actions against the code. This is usually the first step in any DevSecOps flow. |

More such actions or apps can be found in the GitHub marketplace and reused in the workflow. We will look at many more such actions or apps and use them in our workflow for different activities as part of automating the DevSecOps flow. Examples of using the same in your workflow steps can be found in the marketplace as shown below.
Example 2: Extend the above example to perform Deploy steps to Tomcat
name: CI and CD with Maven
on:
push:
branches: [ master ]
jobs:
Maven_Build_Deploy:
runs-on: self-hosted
steps:
- uses: actions/checkout@v3
- name: Build with Maven
run: mvn clean install
- name: Deploy to Tomcat
run: copy ${env:GITHUB_WORKSPACE}\target\HelloWorld-Maven.war E:\apache-tomcat-7.0.65\apache-tomcat-7.0.65\webapps\
Go to the Actions Tab and click on the job to view the log.

Example 3: Extend the above example to upload an artifact to GitHub
From the marketplace view on the right select the Upload a Build Artifact.


Copy and paste the snippet below the ‘mvn clean install’ command
- name: Upload a Build Artifact
uses: actions/[email protected]
with:
name: assets-for-upload
path: target/*.war
retention-days: 5
The advantage of uploading the build artifact to the GitHub repo is that it can be reused in another workflow.

Commit the changes. The workflow is run and the artifacts are uploaded.

To view the artifacts uploaded click on the Summary on the left. Look at the Artifacts section and click on the assets for the download link.


The Zip file contains the WAR file built.
Example 4: Code for downloading artifact to the runner machine
Add the below code from the marketplace for downloading the artifact to a directory in the runner machine. In this case, the WAR file which was uploaded in the previous step will be downloaded to a specific directory.
- name: Download the artifacts
uses: actions/[email protected]
with:
name: assets-for-upload
# Destination path
path: e:\temp\rel

Let’s now commit the code and watch the download.


The downloaded artifact can be referenced in some other workflow for some other deployment.
Example 5: Create a release in GitHub repository
To create a release we will follow these steps
- Archive the WAR file. Create a ZIP file containing the WAR file
- Create a GitHub Release (https://github.com/actions/create-release)
- Upload the asset to GitHub Release (https://github.com/actions/upload-release-asset)
The code for the above steps will be added from the marketplace. Add the code below the download artifact step.
- name: Archive the WAR file (Create ZIP file for Release)
uses: vimtor/action-zip@v1
with:
files: target/HelloWorld-Maven.war
dest: Hw-Maven-Repo.zip
- name: Create Github Release
id: create-new-release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: v${{ github.run_number }}
release_name: Release V${{ github.run_number }}
- name: Upload asset to Github Release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
upload_url: ${{ steps.create-new-release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`.
asset_path: ${{ github.workspace }}/Hw-Maven-Repo.zip
asset_name: Hw-Maven-Repo-v${{ github.run_number }}.zip
asset_content_type: application/zip



Angular Example – Build and Deployment Workflow
To run this example, ensure to install NodeJs and NPM on the runner machine. Angular CLI would also need to be installed.
Add the following code to the YML file in .github/workflows directory in the GitHub repository which contains the Angular Code
name: Angular Example
on: [push]
jobs:
Angular_Build_Deploy_Tomcat:
runs-on: angular-runner
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: npm install
- name: Build App
run: ng build --base-href=/angular/
- name: Deploy to Tomcat
run: copy ${env:GITHUB_WORKSPACE}\dist\vnNewApp\*.* E:\apache-tomcat-7.0.65\apache-tomcat-7.0.65\webapps\angular

Commit the YML file and view the workflow run.

Launch the application deployed to Tomcat using the URL http://localhost:8080/angular/

Docker Example – Build and Deployment Workflow
In this section, we will look at an example of Docker build and push to Docker Hub and JFrog Artifactory private registry.
Example 1:
I have the sample WAR file built and stored in my Linux build server machine. The same path as shown below has Dockerfile as well, which is needed for Docker build.

Let’s look at the GitHub Actions Workflow for Docker build and push.
name: Docker Build and Push
on:
push:
branches: [ master ]
jobs:
Docker_Build_Push:
runs-on: self-hosted
steps:
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Docker image Build and Push to Docker Hub
uses: docker/[email protected]
with:
# Path where code and Dockerfile is located
context: /home/ubuntu/example
push: true
tags: vniranjan1972/vnmaven:${{ github.run_number }}
In the above, I have used the Docker build and push action available in GitHub Marketplace. This action helps to build and push tags to Dockerhub.
In the last line associated with tags, I have specified ${{ github.run_number }}. This is the context that helps to access information about the workflow runs, runner environments, etc. More about how to use the contexts in the workflow can be found @ https://docs.github.com/en/actions/learn-github-actions/contexts#github-context

Commit the file and check the output and the image pushed to Dockerhub.

The image is now available in Docker Hub with tag number 23.

Example 2:
In this section, we will look at the Docker image build and push to JFrog Artifactory.
Here is the simple Dockerfile used and stored in my GitHub repository.
FROM vniranjan1972.jfrog.io/vn-docker-virtual/httpd
MAINTAINER V Niranjan
COPY index.html /var/www/html/
GitHub Actions Workflow
name: JFrog Artifactory Build and Push
on:
push:
branches: [ master ]
jobs:
Artifactory_Docker_Build_Push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Login to JFrog
uses: docker/[email protected]
with:
registry: vniranjan1972.jfrog.io
username: ${{ secrets.JFROG_USER }}
password: ${{ secrets.JFROG_PASSWORD }}
- name: Docker Image Build and push
uses: docker/[email protected]
with:
push: true
tags: vniranjan1972.jfrog.io/vn-docker-virtual/vntomcatnew1:latest
In the above workflow, I am using a JFrog Artifactory Virtual repository called vn-docker-virtual which contains a remote repository for downloading dependencies and a local repository for uploading the docker image.
Commit the above workflow and on PUSH, the workflow triggers.

JFrog Artifactory local repository with the latest image uploaded.

Further Reading => GitHub Advanced Security – A Complete Guide
GitHub Actions for GitHub Enterprise Server using Actions-sync
The actions from the GitHub marketplace or even GitHub.com are not normally available to use for workflows in the GitHub Enterprise Server (On-Prem version of GitHub). In such cases where users need to make use of GitHub Actions features, we need to MANUALLY sync the actions from GitHub.com.
We will look at the procedure to download specific actions and make them available to your GitHub Enterprise Server so that users can use the GitHub Actions feature.
To download the actions to be made available to your GitHub Enterprise Server, you should use the open-source utility from GitHub called as actions-sync. This will help to sync specific actions repositories from GitHub.com to your Enterprise server.
The latest version of actions-sync tool can be downloaded from https://github.com/actions/actions-sync/releases/
The workflow for achieving this using actions-sync would be as shown

EXAMPLE: The actions-sync command format (Linux)

• In the above command for the parameter –repo-name if the repository is to be named differently in the enterprise server then use it as actions/checkout:dest_org/checkout
• For the PAT token, the scope of the repo and workflow should be included.
• Repolist file format, if used should be as follows. Add all actions as needed in the file.
actions/checkout:dest_org/checkout
actions/upload-artifact:dest_org/upload-artifact
In your GitHub Actions workflow, reference the action as
uses: dest_org/checkout
Billing for GitHub Actions
GitHub Actions is free for public repositories and self-hosted runners. For private repositories, it includes 2000 free build minutes every month. For other plans, you could pay as per the details given in the link https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions
Recommended Reading => GitHub Projects – Review of New Beta Features
Conclusion
In this article, we have seen how GitHub Actions can be used for CI/CD and within GitHub itself, rather than using GitHub repos with any third-party integration.
We have also seen the concepts in GitHub Actions and how easy it is to set up custom pipelines or workflows using YAML files to perform Build, Create a Release, Upload artifacts to Release, and Deployment to Tomcat.
GitHub Actions are completely integrated into GitHub, and you need not launch any separate tool for the same. We can use this feature similarly to using other features of GitHub like Commits, Pull Requests, Wiki’s, Issues, etc.
In the next series of articles, I will focus on other integrations with Sonar, Artifactory, and Docker and also cover details on GitHub Actions Secrets & Environment variables, though I have covered some aspects of it in this article.









