Menu Octopus Deploy

GitHub Reusable Workflows: The basics and a quick tutorial

What are GitHub Actions reusable workflows?

GitHub Actions is GitHub’s CI/CD platform, integrated with the GitHub repository and version control system. Reusable workflows are pre-defined, modular workflows that can be invoked within other workflows to enhance efficiency and maintainability. They eliminate repetitive code by allowing you to create components that can be used across multiple repositories or within different workflows in the same repository.

By encapsulating common tasks, reusable workflows enable developers to focus on the unique aspects of their projects while ensuring that standard operations are executed reliably. This approach aligns with best practices in software development, such as the DRY (Don’t Repeat Yourself) principle.

What are the benefits of reusable workflows?

Here are a few key benefits of the reusable workflows feature in GitHub Actions:

  • Avoid redundancy: Reusable workflows can simplify maintenance. If multiple projects require a similar sequence of CI/CD steps, you can encapsulate this sequence into a reusable workflow. Instead of duplicating these steps in each project’s workflow, you reference the reusable workflow, ensuring changes are made only once.
  • Speed up workflow creation: When setting up workflows for new projects, instead of writing each step from scratch, you can call upon these reusable workflows. This also fosters an environment where workflows are iteratively improved.
  • Enhance security: Reusable workflows can be secured by implementing strict access controls, and these controls are replicated to every project that uses the workflows. By defining a set of reusable actions or workflows and limiting who can edit them, organizations can institute a controlled and secure CI/CD environment.
  • Automating compliance: Reusable workflows can encapsulate best practices and mandatory checks that ensure code and deployments meet predefined compliance criteria. For example, a reusable workflow can include steps for code quality checks, security scanning, license compliance verification, and audit logging.

Related content: Read our guide to GitHub actions workflow

Composite action vs. reusable workflows: What are the differences?

While both composite actions and reusable workflows aim to modularize and simplify GitHub Actions, they serve different purposes and offer distinct advantages.

Composite actions bundle multiple steps into a single action. This allows you to create complex actions from simpler ones. Composite actions are stored in a repository and can be referenced just like any other GitHub Action. They are suited for packaging repeatable sequences of steps that you want to reuse across different workflows.

Reusable workflows allow entire workflows to be reused within other workflows. This feature is particularly useful for standardizing complex CI/CD pipelines across multiple projects. Reusable workflows are defined in a YAML file and can be invoked from other workflows within the same repository or even across different repositories.

While composite actions are best for creating reusable sets of steps, reusable workflows are more suited for standardizing entire CI/CD pipelines across multiple projects. Each of these features operates at a different level of the GitHub Actions architecture.

Components of a reusable workflow

Triggering event

The triggering event is a crucial component of a reusable workflow, as it determines when the workflow should be executed. Common triggering events include push events, pull requests, and scheduled intervals. By defining these triggers accurately, developers can ensure that workflows are executed at appropriate times, such as after code commits or at specific times of day.

Input definition

The input definition includes parameters that can be passed to the workflow when it is invoked, allowing for customization without changing the workflow’s internal code. These inputs can be anything from version numbers to specific feature flags that might need to be toggled during the workflow execution.

Defining inputs in a reusable workflow grants greater flexibility and control over how the workflow operates. It enables developers to tailor the workflow’s behavior based on the specific requirements of each project or scenario.

Passing named secrets

Passing named secrets securely within reusable workflows is crucial for maintaining the security and integrity of sensitive project information. Named secrets typically include tokens, API keys, and credentials required during the workflow execution. GitHub provides mechanisms to store these secrets securely and access them when needed in a workflow.

Using named secrets ensures that sensitive data remains confidential and is not exposed in the codebase. When setting up reusable workflows, it’s essential to define how these secrets will be passed and accessed, ensuring that they remain protected yet accessible when required, thus enhancing the security of your CI/CD processes.

Tutorial: Creating and calling reusable workflows

These instructions are adapted from the GitHub documentation.

Using inputs and secrets in a reusable workflow

To define and use inputs and secrets in a reusable workflow, follow these steps:

1. Define inputs and secrets

In the reusable workflow file, specify the inputs and secrets that will be passed from the calling workflow:

on:
  workflow_call:
    inputs:
      log-level:
        required: false
        type: string
        default: 'info'
    secrets:
      DB_HOST:
        required: true
      DB_USER:
        required: true
      DB_PASSWORD:
        required: true

2. Reference inputs and secrets

Use the defined inputs and secrets within the jobs of the reusable workflow:

jobs:
  trigger-reusable-workflow:
    uses: ./.github/workflows/reusable-workflow.yml
    with:
      api-key: ${{ secrets.API_KEY }}
      config-path: '.github/reusable-config.yml'

3. Pass inputs and secrets from the caller workflow

In the calling workflow, use the with keyword for inputs and secrets keyword for secrets to pass values to the reusable workflow:

jobs:
  call-workflow-passing-data:
    uses: my-company/data-science-team/ml-repo/.github/workflows/app-build-workflow.yml@dev
    with:
      config-path: .github/config-values.yaml
    secrets:
      api_session_token: ${{ secrets.SESSION_TOKEN }}

Calling a reusable workflow

The uses keyword allows you to reference the reusable workflow file in a job within the calling workflow. You can reference workflows in the same repository or in different repositories:

jobs:
  call-workflow-passing-data:
    uses: my-company/data-science-team/ml-repo/.github/workflows/app-build-workflow.yml@dev

For workflows in the same repository, you can use a relative path:

jobs:
  my--workflow:
    uses: ./.github/workflows/data-model-workflow.yml

Passing inputs and secrets to a reusable workflow

To pass named inputs and secrets to a reusable workflow, use the with and secrets keywords:

1. Passing named inputs

Ensure that the data type of the input value matches the type specified in the reusable workflow:

jobs:
  deploy-app:
    uses: my-org/deploy-repo/.github/workflows/deploy-workflow.yml@v1
    with:
      deploy-config: configs/deploy-settings.yml
    secrets:
      apiToken: ${{ secrets.apiToken }}

2. Inheriting secrets

Workflows within the same organization or enterprise can inherit secrets:

jobs:
  call-perform-data-cleaning:
    uses: my-org/deploy-repo/.github/workflows/deploy-workflow.yml@v1
    with:
      config-path: .github/v1/cleaner.yml
    secrets: inherit

Using a matrix strategy with a reusable workflow

A matrix strategy allows for running multiple jobs with different configurations. This is useful for testing across different environments or configurations. Here is how to use the matrix context to define variables and pass them to the reusable workflow:

jobs:
  QA-StagingArea-Deployment:
    strategy:
      matrix:
        target: [qa, staging-area]
    uses: my-org/deploy-repo/.github/workflows/deploy-workflow.yml@v1
    with:
      target: ${{ matrix.target }}

This example runs two jobs, one for each value in the target variable, effectively deploying to qa, and staging-area environments using the reusable workflow.

Help us continuously improve

Please let us know if you have any feedback about this page.

Send feedback

Categories:

Next article
GitHub Actions steps