Creating Reusable Workflows
1. Defining Reusable Workflow
| Property | Description | Values |
|---|---|---|
| name | Name of the workflow | string |
| on | Triggers for the workflow | workflow_call |
| inputs | Inputs that can be passed to the workflow | object |
| outputs | Outputs that can be returned from the workflow | object |
| jobs | Jobs to run in the workflow | object |
Example: Defining a reusable workflow
name: "Reusable Workflow"
on:
workflow_call:
inputs:
environment:
required: true
type: string
outputs:
result:
value: ${{ jobs.deploy.outputs.result }}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to environment
run: echo "Deploying to ${{ inputs.environment }}"
id: deploy
- name: Set output
run: echo "result=success" >> $GITHUB_OUTPUT
id: set_output
2. Calling Reusable Workflows
| Parameter | Description | Example |
|---|---|---|
| uses | The path to the reusable workflow file | actions/reusable-workflow@v1 |
| with | Input parameters to pass to the reusable workflow | environment: production |
| secrets | Secrets to pass to the reusable workflow | api_key: ${{ secrets.API_KEY }} |
Example: Calling a Reusable Workflow
jobs:
call-workflow:
uses: octocat/my-reusable-workflow@v1
with:
environment: production
timeout: 30m
secrets:
api_key: ${{ secrets.API_KEY }}
Note: Reusable workflows must be stored in the same repository or a public repository.
Warning: Ensure that all secrets used in the reusable workflow are properly scoped and accessible to the calling workflow.
3. Passing Inputs
| Input | Description | Type | Required |
|---|---|---|---|
| name | The name of the input parameter | string | Yes |
| description | A description of what the input is used for | string | No |
| required | Whether the input is required or not | boolean | No |
| default | The default value if the input is not provided | string | No |
| options | A list of valid values for the input | array | No |
Example: Using Inputs in a Workflow
name: Reusable Workflow
on:
workflow_call:
inputs:
environment:
description: 'The environment to deploy to'
required: true
type: string
options:
- production
- staging
debug:
description: 'Enable debug mode'
required: false
type: boolean
default: false
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to ${{ inputs.environment }}
run: |
echo "Deploying to ${{ inputs.environment }}"
if ${{ inputs.debug }}; then
echo "Debug mode enabled"
fi
4. Defining Input Types
| Input Type | Description | Example |
|---|---|---|
| string | Text value, default is empty string | name: 'environment' |
| number | Numeric value, default is 0 | timeout: 30 |
| boolean | True or false, default is false | debug: true |
| environment | Environment name, must match an existing environment | environment: production |
| choice | One of a predefined list of values | mode: ['build', 'test', 'deploy'] |
| file | Path to a file, must be a valid path | config-file: 'config.yaml' |
Example: Defining Inputs in a Reusable Workflow
name: Reusable Workflow
on:
workflow_call:
inputs:
environment:
description: 'Environment to deploy to'
required: true
type: string
debug:
description: 'Enable debug mode'
required: false
type: boolean
default: false
timeout:
description: 'Timeout in seconds'
required: false
type: number
default: 30
5. Setting Required Inputs
| Input | Description | Type | Required |
|---|---|---|---|
| name | The name of the input parameter | string |
true |
| description | A description of what the input is used for | string |
false |
| required | Whether the input is required or not | boolean |
false |
| default | The default value if the input is not provided | string |
false |
| options | A list of valid values for the input | array |
false |
Example: Defining Required Inputs
name: "Reusable Workflow"
inputs:
environment:
description: "The environment to deploy to"
required: true
type: string
branch:
description: "The branch to deploy from"
required: false
type: string
default: "main"
6. Setting Default Input Values
| Property | Description | Default Value | Example |
|---|---|---|---|
| inputs.<input_name>.default | Defines the default value for an input parameter if no value is provided. | None | |
Example: Using Default Values in Workflow
name: Reusable Workflow with Defaults
on:
workflow_call:
inputs:
environment:
description: 'Environment to deploy to'
type: string
default: 'staging'
debug:
description: 'Enable debug mode'
type: boolean
default: false
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to ${{ inputs.environment }}
run: |
echo "Deploying to ${{ inputs.environment }}"
if ${{ inputs.debug }}; then
echo "Debug mode enabled"
fi
Note: Default values are only used when the calling workflow does not provide a value for the input. If an input is required and no default is set, it must be provided by the caller.
7. Using Secrets in Reusable Workflows
| Secret | Usage | Notes |
|---|---|---|
| GITHUB_TOKEN | secrets.GITHUB_TOKEN |
Automatically provided by GitHub, no need to define |
| CUSTOM_SECRET | secrets.CUSTOM_SECRET |
Must be defined in repository or organization settings |
Example: Using a Secret in a Reusable Workflow
name: Reusable Workflow with Secrets
on:
workflow_call:
secrets:
API_KEY:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Use Secret
run: |
echo "API Key is: ${{ secrets.API_KEY }}"
Note: Secrets are passed as inputs to reusable workflows and are not accessible in the calling workflow's context.
8. Returning Outputs
| Property | Description | Example |
|---|---|---|
| outputs | Defines the outputs that a reusable workflow can return to the calling workflow. | |
Example: Defining Outputs in a Reusable Workflow
name: Reusable Workflow with Outputs
on:
workflow_call:
outputs:
job-status:
description: "Status of the job"
value: ${{ jobs.job1.result }}
jobs:
job1:
runs-on: ubuntu-latest
steps:
- name: Run a step
run: echo "Hello World"
Example: Using Outputs in a Calling Workflow
name: Using Reusable Workflow Outputs
on:
workflow_dispatch:
jobs:
call-workflow:
uses: octocat/my-reusable-workflow@v1
with:
input: "value"
outputs:
job-status: ${{ jobs.call-workflow.outputs.job-status }}
9. Accessing Caller Context
| Property | Description | Example |
|---|---|---|
| github.event | Full event payload from the caller workflow | {"ref": "refs/heads/main", "repository": {"name": "my-repo"}} |
| github.event_name | Name of the event that triggered the workflow | push |
| github.workflow | Name of the workflow that triggered the call | Deploy to Production |
| github.actor | User who triggered the workflow | octocat |
| github.run_id | Unique identifier for the current workflow run | 123456789 |
| github.run_number | Sequential number of the current workflow run | 1 |
Example: Using caller context in a reusable workflow
name: Reusable Workflow Example
on:
workflow_call:
inputs:
environment:
type: string
required: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to ${{ inputs.environment }}
run: |
echo "Deploying to ${{ inputs.environment }}"
echo "Triggered by ${{ github.actor }} on branch ${{ github.event.ref }}"
Note: The
github.event object contains all the data from the original event that triggered the workflow call, including repository details and branch information.10. Nesting Reusable Workflows
Reusable workflows in GitHub Actions can be nested to create complex, modular CI/CD pipelines. This allows you to compose workflows from other workflows, enabling better organization and code reuse.
| Property | Description | Example |
|---|---|---|
| uses | Specifies the reusable workflow to use. Can be a local path or a reference to another repository. | uses: ./.github/workflows/reusable-workflow.yml |
| with | Parameters to pass into the reusable workflow. | with: { environment: prod } |
| secrets | Secrets to pass into the reusable workflow. | secrets: { token: ${{ secrets.GITHUB_TOKEN }}} |
Example: Nesting Reusable Workflows
name: Main Workflow
on:
push:
branches: [ main ]
jobs:
build-and-test:
uses: ./.github/workflows/reusable-build.yml
with:
environment: prod
secrets:
token: ${{ secrets.GITHUB_TOKEN }}
Note: When nesting workflows, the parent workflow's context (e.g.,
github.ref, github.sha) is passed to the child workflow. You can override these values using with if needed.
Warning: Nested workflows do not inherit the
permissions of the parent workflow. You must explicitly set permissions in each nested workflow.
11. Versioning Reusable Workflows
| Version Type | Description | Usage | Notes |
|---|---|---|---|
| Tagged Versions | Using Git tags to version workflows | uses: owner/repo@v1.2.3 |
Recommended for stable releases |
| Branch References | Using branch names to reference workflows | uses: owner/repo@main |
Not recommended for production due to instability |
| Commit SHAs | Using full commit hashes to reference workflows | uses: owner/repo@abc123def456 |
Most stable but least flexible |
Example: Using Tagged Version
name: My Workflow
on:
push:
branches: [ main ]
jobs:
build:
uses: octocat/my-reusable-workflow@v1.2.3
Note: When using tagged versions, ensure the tag exists in the repository to avoid failures.
Warning: Using branch references (like
main) can lead to unexpected behavior if the workflow changes without a version bump.
12. Sharing Across Repositories
GitHub Actions workflows can be shared across repositories using Reusable Workflows. These allow you to define a workflow in one repository and call it from another, promoting code reuse and consistency.
| Feature | Description | Notes |
|---|---|---|
| reusable workflow | A workflow defined in one repository that can be called from another. | Can be stored in a different repository than the one using it. |
| workflow_call | Trigger that enables a workflow to be called from another workflow. | Must be defined in the reusable workflow file. |
| workflow_dispatch | Enables manual triggering of a reusable workflow. | Can be used with inputs to customize behavior. |
Example: Reusable Workflow Definition
name: Reusable Workflow
on:
workflow_call:
inputs:
environment:
required: true
type: string
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to ${{ inputs.environment }}
run: |
echo "Deploying to ${{ inputs.environment }}"
Example: Using the Reusable Workflow
name: Use Reusable Workflow
on:
push:
branches: [ main ]
jobs:
deploy:
uses: owner/repo/.github/workflows/deploy.yml@v1
with:
environment: production
Note: Reusable workflows must be stored in the
.github/workflows directory of the repository where they are defined.
Warning: When using reusable workflows, ensure that the calling repository has appropriate permissions to access the workflow in the source repository.
13. Testing Reusable Workflows
Example: Testing a Reusable Workflow
name: Test Reusable Workflow
on:
pull_request:
branches: [ main ]
jobs:
test-workflow:
uses: ./.github/workflows/reusable-workflow.yml
with:
environment: test
| Property | Description | Values |
|---|---|---|
| uses | Path to the reusable workflow file | .github/workflows/reusable-workflow.yml |
| with.environment | Environment variable passed to the workflow | test |
Note: Reusable workflows can be tested locally using the
act tool or by running them in a test environment.
Warning: Ensure that all inputs and secrets used in the reusable workflow are properly mocked or provided during testing.