GitHub Actions: Concepts, Features, and a Quick Tutorial

What Is GitHub Actions?

GitHub Actions is a platform for continuous integration / continuous delivery (CI/CD). It enables you to automate build, testing, and deployment pipelines. It also lets you run arbitrary code on a specified repository when an event occurs. Actions uses code packages in Docker containers that run on GitHub servers. They are compatible with all programming languages to ensure you can run them on public clouds as well as local servers. This is part of an extensive series of guides about CI/CD.

GitHub Actions Architecture and Concepts

GitHub Actions allows you to configure your workflow to be triggered once a specific event occurs in the repository. For example, when an issue is created or when a pull request is opened. 

A workflow contains one or several jobs running in parallel or sequential order. Each job runs inside a container or in a separate virtual machine (VM) runner. Additionally, each job includes one or several steps that run a predefined script or an action, a reusable extension that simplifies your workflow.

GitHub Actions workflow structure

Image Source: Github Actions

GitHub Actions Workflows

A GitHub Actions workflow is an automated process that runs one or several jobs. You can configure workflows by defining a YAML file, which is checked into the repository. This file runs when: 

  • Triggered by a specific event in the repository
  • Triggered manually
  • At a predefined schedule

You can find workflow definitions in the .github/workflows directory of each repository. A repository can include several workflows, each performing different tasks. You can use, for example, one workflow for building and testing pull requests, another workflow for deploying the application whenever a release is created, and an additional workflow for adding a label whenever a new issue is opened.

Learn more in our detailed guide to GitHub Actions Workflows (coming soon)

GitHub Actions Events

An event is a specific activity in a repository that triggers a workflow run. For example, activity can originate from GitHub when someone creates a pull request, opens an issue, or pushes a commit to a repository. You can also trigger a workflow run on a schedule, by posting to a REST API, or manually.

Workflow Triggers

A workflow trigger is an event that causes a workflow to run. Here are workflow trigger examples:

  • Events occurring in the workflow’s repository
  • Events occurring outside of GitHub and trigger a repository_dispatch event on GitHub
  • Manual 
  • Scheduled times

For instance, you can configure a workflow to run once a push is made to a default repository branch, once an issue is opened, and once a release is created.

GitHub Actions Jobs

A job in GitHub Actions is a series of workflow steps that run on a single runner. The steps can include actions to run or shell scripts for execution. Actions execute each step in order, as all steps in a job are interdependent. It executes every step on the same runner, enabling data sharing between steps. For instance, if you have a step to build an application, there might be a subsequent step to test the newly built application.

Jobs don’t have dependencies by default, but you can configure jobs to be dependent on other jobs and run in sequence. Otherwise, the jobs will execute in parallel. If a job has a dependency on another job, it must wait for that job to complete before running. There could be several build jobs, each for a different architecture, without any dependencies—however, a packaging job would be dependent on these jobs. The non-dependent build jobs run simultaneously, but the packaging job can only run when all the build jobs are complete.

GitHub Actions Matrix

You can use a matrix strategy to run multiple related jobs based on the same job definition. Different combinations of variables in the job definition automatically create different job runs. For instance, a matrix might be useful for testing code on different operating systems or in different versions of a programming language.

Actions

Actions are custom applications for GitHub Actions that perform complex but repetitive tasks. You might use actions to avoid writing too much repetitive code in a workflow. An action could pull a repository from GitHub, set up authentication measures to the cloud provider, or configure the right toolchain for the development environment. 

You can write an action from scratch or use an existing action available from the GitHub Marketplace in your workflow.

Runners

Runners are machines that have the GitHub Actions runner app installed. They wait for available jobs to execute. Once a runner picks up a job, it runs the actions specified by the job and reports the results to Github. You can host runners on your own server or machine or use GitHub-hosted runners. 

Workflow Dependency Caching

A workflow run can reuse the outputs and dependencies from other runs. Dependency and package management tools like Maven, npm, Yarn, and Gradle keep local caches of all downloaded dependencies.

Each job on a GitHub-hosted runner starts in a fresh environment, so it is necessary to download the dependencies for every new job. These downloads can lengthen the runtime, increase network utilization, and increase costs. GitHub allows you to accelerate the process of recreating dependency files by caching frequently used files in a workflow. 

You can cache job dependencies by using the cache action in GitHub. This action builds and restores caches identified using unique keys.

CI/CD with GitHub Actions

GitHub Action supports continuous integration and deployment.

Continuous Integration with GitHub Actions

Continuous integration is a software development practice that involves frequent commits to a shared code repository. GitHub Actions provides continuous integration (CI) workflows that can build code in the repository and execute tests. A workflow can run on a GitHub-hosted VM or a self-hosted machine. 

You configure CI workflows to run in response to specific GitHub events—for instance, when a developer pushes new code to the repository. You can also use the repository dispatch webhook to schedule workflows or set triggers based on external events.

GitHub runs the CI tests, providing the results for all tests in a pull request. It lets you view any errors introduced to the branch by each change. Once a change has passed all the CI tests in the workflow, it is ready for review by team members, and you can merge it into the repository. If the commit fails a test, it is an indication of a breaking change. 

When setting up continuous integration in the Git repository, GitHub will analyze your code and recommend specific CI workflows based on your repository’s framework and language. For instance, GitHub suggests starter workflows that install the appropriate packages and run the tests (i.e., a Node.js package if you are using Node.js). You can use the GitHub-recommended starter workflow as is, customize it to your needs, or create a new custom workflow to run the continuous integration tests.

Selecting a workflow in GitHub Actions

Image Source: GitHub Actions

GitHub Actions helps you set up a CI workflow for your development project and can create workflows for the entire SDLC. You could set up actions to package, deploy, and release a project. 

Continuous Deployment with GitHub Actions

Continuous deployment is an extension of continuous integration and delivery that automates the process of publishing and deploying software releases. A CI/CD tool typically builds and tests the code automatically before deploying it as part of the continuous deployment process. 

You can configure GitHub Actions workflows to deploy software products. A workflow can verify that the code functions as expected by building the code in the repository and running tests before deployment.

You can schedule CD workflows to run in response to specific GitHub events, such as a developer pushing code to the repository’s default branch of your repository. Alternatively, workloads can run on set schedules, when triggered manually, or in response to external events.

GitHub Actions offers several features to help you control your deployments. Environments allow you to block jobs until they receive approval, restrict the branches that can trigger workflows, or restrict access to secrets. Concurrency lets you limit the CD pipeline to one in-progress and one pending deployment at a time. 

Related content: Read our guide to GitHub Actions vs. CircleCI (coming soon)

GitHub Actions Quick Start Tutorial

Using GitHub Actions requires a GitHub repository. The jobs in a workflow can automatically execute actions related to the repository and interact with the repository’s code too. 

Create Workflow

To create workflows in GitHub Actions:

  1. Create a new directory in your repository and name it .github/workflows if such a directory doesn’t already exist.
  2. In the new directory, click the Add File button on the top-right side of the window and select Create new file. Name the newly created file demo-github-actions-workflow.yml
  3. Paste the following code in the demo-github-actions-workflow.yml
    name: Demo GitHub Actions Workflow
    on: [push]
    jobs:
      Discover-GitHub-Actions-Workflows:
        runs-on: ubuntu-latest
        steps:
         —run: echo "${{ github.event_name }} event automatically triggered this job."
         —run: echo " A ${{ runner.os }} server hosted by GitHub has this job running"
         —run: echo "Details of your repository: repo-name: ${{ github.repository }} and branch name is${{ github.ref }} and your repository is ${{ github.repository }}."
         —name: Checking out the repository’s code
            uses: actions/checkout@v3
         —run: echo "The runner has cloned your ${{ github.repository }} repository."
         —run: echo "The workflow can now test your code with the runner."
         —name: List files in the repository
            run: |
              ls ${{ github.workspace }}
         —run: echo " This job has a ${{ job.status }} status."
    
  4. Click the Propose new file to create a pull-request for committing this file to the repository.  
  5.  Go to the bottom of the page and select the Create a new branch for this commit and start a pull request option.

When the yml file gets committed, the push event triggers the workflow described in it. The results of the workflow get shown in a different option.   

View Results of Workflow

To see the results after running a GitHub Actions workflow:

  1. Go to the repository’s main page and click Actions on the bar under the repository name.
  2. A sidebar on the left shows all the workflows on the page that opens. Click the one that displays Demo-GitHub-Actions-Workflow, the name of the workflow created for this tutorial.
  3. The list in the center shows the workflows that have run. Select the one that displays Create demo-github-actions-workflow.yml to see the results of the one created in the previous section, Create Workflow.
  4. Under the sidebar on the left that displays Jobs, select the one displaying Discover-GitHub-Actions-Workflows.
  5. The log that opens shows each step of the workflow and what output it caused.
  6. The steps for the echo statements in the workflow show the variables replaced with their respective values. Click on a step that displays List files in the repository, and it shows the files present in the repository.

Note: GitHub provides pre-built workflows that users can use as a template and customize per their needs. GitHub suggests the right starter workflow based on what libraries, languages, and frameworks are in the repository code.

Related content: Go beyond the basics with our full GitHub Actions Tutorial (coming soon)

GitHub Actions Best Practices

Here are some tips for using GitHub Actions.

Use Minimal Actions

An action’s virtual machine has high bandwidth and is relatively fast, but complex actions take longer to set up and execute, resulting in more time spent waiting. GitHub Actions has limited virtual machine plans—the free plan has a cap of 2000 free minutes in a given month. 

When setting up a workflow or action, you might not feel that a few seconds make a big difference—however, these seconds add up depending on the events triggering the actions and workflows. An important best practice when creating new actions is to try to keep them as minimal as possible.

For instance, you should use light Docker images for actions that run in containers—e.g., alpine, alpine-node. Keep the installations to a minimum to reduce the action’s running time from boot to completion. 

Keeping actions light is important regardless of whether you create a standalone action or a full CI/CD workflow. GitHub Actions sets up and runs each action in a clean environment for every run, so it has to download and install all the dependencies every time.

Avoid Unnecessary Dependency Downloads

Another way to reduce the running time is to avoid installing or downloading dependencies wherever possible. You can use several methods to minimize dependency downloads, although these are all based on two main strategies. 

The first approach is to publish an entire node module folder. This strategy is suitable for publishing standalone actions in Node-based projects. The second approach is to leverage the caching mechanism in GitHub wherever possible. This strategy is suitable for standalone actions as well as actions running within a CI workflow.

Avoid Hardcoding Secrets

An important feature of GitHub Actions is secret management. You store encrypted secrets within the repository settings, providing them as environment variables or inputs to your actions whenever you choose. GitHub Actions automatically redacts secrets logged accidentally or intentionally. However, the GitHub documentation also recommends that you avoid logging secrets because this automatic redaction capability is not fully effective, especially for secrets containing structured data.

The key takeaway of this approach is to avoid manually hardcoding any secrets into public or private workflows. You should set secrets manually in your repository’s settings and use step inputs or environment variables to access them.

Store Authorship Details in the Action Metadata

You can encourage authors of actions to take ownership of their code by specifying the action author in the metadata—this data resides in a YML file defining the action. This metadata can include many details about each action, including its required inputs, branding, entry point, outputs, and author. 

There are two main use cases for including the action’s author in the metadata file. First, when you have public actions, it is important to attribute each action to the correct author. In addition to giving authors credit for their work, it allows others who are using the actions to identify and refer to the author with any questions. 

The second use case applies to private actions with an organization. The issue of credit is less relevant because no one outside the company will see it. However, the internal team still needs to know who is responsible for each action—the author maintains and answers questions about the action. 

Combine GitHub Actions with Codefresh to Support GitOps and Kubernetes Deployments

GitHub actions is a very powerful platform but it is focused mostly on CI and does not support GitOps and native Kubernetes deployments. Codefresh is created specifically for GitOps and Cloud native applications and includes native support for using GitHub Actions for the CI part of the Software lifecycle.

This means that you can get the best of both worlds by keeping all your CI workflows in GitHub Actions, while using Codefresh for advanced features such as:

  • Application dashboards
  • Git source managements
  • Configuration drift management
  • Kubernetes environment dashboards
  • Topology views

In case you are new to Codefresh – we have made it our mission since 2014 to help teams accelerate their pace of innovation. Codefresh recently released a completely rebuilt GitOps CI/CD toolset. Powered by Argo, Codefresh now combines the best of open source with an enterprise-grade runtime allowing you to fully tap the power of Argo Workflows, Events, CD, and Rollouts. It provides teams with a unified GitOps experience to build, test, deploy, and scale their applications.

See Our Additional Guides on Key CI/CD Topics

Together with our content partners, we have authored in-depth guides on several other topics that can also be useful as you explore the world of CI/CD.

The World’s Most Modern CI/CD Platform

A next generation CI/CD platform designed for cloud-native applications, offering dynamic builds, progressive delivery, and much more.

Check It Out