Mastering GitHub Actions: Creating Reusable Workflows
In modern DevOps practices, the "Don't Repeat Yourself" (DRY) principle is essential for maintaining clean and efficient CI/CD pipelines. As your project grows, you might find yourself copying and pasting the same job configurations across multiple repositories or workflow files. GitHub Actions provides a powerful feature called Reusable Workflows to solve this exact problem.
Reusable workflows allow you to define a standardized process once and call it from multiple other workflows. This reduces maintenance overhead, ensures consistency across teams, and simplifies the management of complex CI/CD logic.
Understanding the Architecture
In a reusable workflow setup, there are two primary components:
- The Reusable (Called) Workflow: The template file that contains the jobs and logic.
- The Caller Workflow: The workflow that triggers or "calls" the reusable template.
[ Caller Workflow ]
|
|-- triggers on: push/pull_request
|
|-- calls: .github/workflows/reusable-build.yml
|
V
[ Reusable Workflow ]
|-- runs-on: ubuntu-latest
|-- steps: [ Checkout, Setup Java, Build ]
The workflow_call Trigger
To make a workflow reusable, you must use the workflow_call trigger in the on section of your YAML file. This tells GitHub that this specific workflow is designed to be invoked by other workflows.
Defining a Reusable Workflow
Here is an example of a reusable workflow designed to build a Java application using Maven. This file would typically be stored in .github/workflows/maven-build.yml.
name: Reusable Maven Build
on:
workflow_call:
inputs:
java-version:
required: true
type: string
maven-command:
required: false
type: string
default: 'clean install'
secrets:
SONAR_TOKEN:
required: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: ${{ inputs.java-version }}
distribution: 'temurin'
- name: Build with Maven
run: mvn ${{ inputs.maven-command }}
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
How to Call a Reusable Workflow
Once you have defined your template, you can call it from a Caller Workflow. The caller workflow uses the uses keyword at the job level rather than the step level.
name: Main CI Pipeline
on:
push:
branches: [ main ]
jobs:
call-build-workflow:
uses: ./.github/workflows/maven-build.yml
with:
java-version: '17'
maven-command: 'clean package'
secrets:
SONAR_TOKEN: ${{ secrets.GLOBAL_SONAR_TOKEN }}
Important Path Rules
- Local Files: Use
./.github/workflows/filename.ymlif the reusable workflow is in the same repository. - Remote Files: Use
{owner}/{repo}/.github/workflows/{filename}.yml@{ref}to call a workflow from another repository (e.g.,my-org/shared-actions/.github/workflows/build.yml@v1).
Passing Inputs and Secrets
Reusable workflows can accept inputs and secrets to make them dynamic.
- Inputs: Used for non-sensitive data like version numbers, environment names, or boolean flags. Defined under
inputsin theworkflow_callsection. - Secrets: Used for sensitive data like API keys or database passwords. These must be explicitly passed from the caller to the reusable workflow using the
secretskeyword. - Inheriting Secrets: You can use
secrets: inheritin the caller workflow to automatically pass all secrets to the reusable workflow without listing them individually.
Real-World Use Cases
Reusable workflows are highly beneficial in the following scenarios:
- Standardized Java Builds: Ensure every microservice in your organization uses the same version of Maven, Java, and security scanning tools.
- Multi-Environment Deployment: Create one deployment workflow and call it multiple times with different inputs for "Staging", "QA", and "Production".
- Compliance and Security: Force all repositories to run a specific security audit workflow before merging code.
Common Mistakes to Avoid
- Nesting Limits: GitHub allows you to nest reusable workflows up to 4 levels deep. Exceeding this will cause an error.
- Environment Context: Remember that
envvariables defined at the top level of a caller workflow are not automatically available in the reusable workflow. You must pass them asinputs. - Checkout Step: You must still include the
actions/checkoutstep inside the reusable workflow if you need access to the repository's code. - Permissions: If the reusable workflow is in a different repository, ensure the repository settings allow access to "Internal" or "Public" workflows.
Interview Notes for DevOps Engineers
- Question: What is the difference between a Composite Action and a Reusable Workflow?
- Answer: Composite Actions are for grouping multiple steps into one action, while Reusable Workflows allow you to reuse entire jobs and can be seen in the GitHub UI as separate workflow runs. Reusable workflows also support secrets more natively.
- Question: How do you handle secrets when calling a workflow from another repository?
- Answer: You can pass them individually using the
secretsblock or usesecrets: inheritif both repositories belong to the same organization and have the appropriate access. - Question: Can a reusable workflow contain multiple jobs?
- Answer: Yes, a reusable workflow can define multiple jobs, and they will all be executed when called by the caller workflow.
Summary
Creating reusable workflows is a milestone in mastering GitHub Actions. By leveraging the workflow_call trigger, you can build a library of standardized CI/CD templates that promote consistency and ease of maintenance. Whether you are managing a single large project or hundreds of microservices, reusability is the key to scaling your automation effectively.
In the next lesson, we will explore Managing Environments and Deployment Gates to add manual approvals to our reusable pipelines.