Building Composite Actions
1. Creating Composite Action
Composite Actions allow you to combine multiple steps into a single reusable action. They are defined in a action.yml file and can be used in workflows.
| Field | Description | Required | Example |
|---|---|---|---|
| name | The name of the action | Yes | My Composite Action |
| description | A description of what the action does | No | Performs a set of steps in sequence |
| inputs | Inputs that can be passed to the action | No | { 'input1': { 'required': true, 'default': 'value' } } |
| outputs | Outputs that the action can produce | No | { 'output1': { 'value': '${{ steps.step1.outputs.output1 }}' } } |
| runs | Defines how the action runs | Yes | { 'using': 'composite', 'steps': [...] } |
Example: Basic Composite Action
name: 'My Composite Action'
description: 'A simple composite action'
inputs:
greeting:
description: 'The greeting to use'
required: false
default: 'Hello'
outputs:
result:
description: 'The result of the action'
value: ${{ steps.step1.outputs.result }}
runs:
using: 'composite'
steps:
- name: 'Say Greeting'
shell: bash
run: |
echo "${{ inputs.greeting }} World!"
echo "result=Hello World!" >> $GITHUB_OUTPUT
2. Defining Action Inputs
| Property | Description | Required | Type |
|---|---|---|---|
| name | The name of the input parameter | Yes | string |
| description | A description of the input parameter | No | string |
| required | Whether the input is required | No | boolean |
| default | The default value if not provided | No | any |
| options | Valid values for the input (for enum-like behavior) | No | array of strings |
Example: Defining Inputs in action.yml
name: 'My Composite Action'
description: 'A sample composite action'
inputs:
environment:
description: 'The environment to deploy to'
required: true
default: 'staging'
debug:
description: 'Enable debug mode'
required: false
default: 'false'
target:
description: 'Target deployment type'
required: false
options: ['web', 'mobile', 'api']
default: 'web'
3. Defining Action Outputs
| Property | Description | Example |
|---|---|---|
| outputs | Defines the outputs that an action can return. | |
Example: Defining Outputs in action.yml
name: 'Composite Action Example'
description: 'A composite action with outputs'
inputs:
input-value:
description: 'Input value for processing'
required: true
outputs:
processed-result:
description: 'The processed result from the action'
value: ${{ steps.process.outputs.result }}
runs:
using: 'composite'
steps:
- name: Process Input
id: process
run: |
echo "result=processed_value" >> $GITHUB_OUTPUTS
shell: bash
Note: The
value field in outputs is evaluated at runtime and can reference steps or other action properties.4. Using Runs Composite
| Property | Description | Values |
|---|---|---|
| runs | Defines the composite action's execution logic | using: "composite" |
| runs.steps | List of steps to execute in the composite action | Array of step objects |
| runs.steps.uses | Reference to an action or script to run | String, e.g., actions/checkout@v4 |
| runs.steps.with | Input parameters to pass to the action or script | Object with key-value pairs |
| runs.steps.env | Environment variables to set for the step | Object with key-value pairs |
| runs.steps.id | Unique identifier for the step | String |
| runs.steps.name | Display name for the step | String |
Example: Using Runs Composite
name: "My Composite Action"
runs:
using: "composite"
steps:
- name: "Checkout Code"
uses: actions/checkout@v4
with:
repository: my-repo/my-project
- name: "Setup Node"
uses: actions/setup-node@v4
with:
node-version: "20"
5. Executing Multiple Steps
Composite actions can execute multiple steps in sequence using the runs property. Each step is defined as a list of actions to run in the composite action.
| Step | Description | Configuration |
|---|---|---|
| runs.steps | Defines the steps to execute in the composite action | steps: array of step objects |
| runs.steps[].uses | Specifies the action to run in this step | uses: <action> |
| runs.steps[].with | Passes input parameters to the action | with: object with key-value pairs |
| runs.steps[].env | Sets environment variables for the step | env: object with key-value pairs |
Example: Executing Multiple Steps
name: "Composite Action with Multiple Steps"
description: "A composite action that runs multiple steps"
inputs:
greeting:
description: "Greeting to use in the output"
required: true
default: "Hello"
outputs:
result:
description: "The result of the composite action"
value: ${{ steps.step1.outputs.result }}
runs:
using: "composite"
steps:
- name: "Step 1: Print Greeting"
id: step1
uses: actions/checkout@v4
with:
greeting: ${{ inputs.greeting }}
- name: "Step 2: Run Script"
id: step2
uses: actions/github-script@v7
with:
script: |
const result = `Greeting was: ${{ inputs.greeting }}`;
console.log(result);
return result;
Note: Steps in a composite action are executed sequentially, and each step can depend on the previous one. The
id field allows referencing outputs from earlier steps.
Key Points
- Each step in a composite action is defined under
runs.steps - Steps can use other actions via the
usesproperty - Inputs and environment variables can be passed to each step using
withandenv - Steps execute in order, and outputs from one step can be used in another
6. Setting Shell for Steps
| Property | Values | Description |
|---|---|---|
| shell | bash, sh, pwsh, powershell, python |
Specifies the shell to use for running commands in a step. Defaults to bash on Linux, sh on macOS, and powershell on Windows. |
Example: Using PowerShell on Windows
steps:
- name: Run PowerShell script
shell: powershell
run: |
Write-Host "Hello from PowerShell"
$env:MY_VAR = "test"
Example: Using Python Shell
steps:
- name: Run Python script
shell: python
run: |
import os
print("Current directory:", os.getcwd())
7. Passing Inputs to Steps
| Input | Description | Type | Required |
|---|---|---|---|
| name | The name of the input parameter | string |
Yes |
| description | A description of the input parameter | string |
No |
| required | Whether the input is required | boolean |
No |
| default | The default value if not provided | string |
No |
Example: Using Inputs in a Composite Action
name: 'Composite Action Example'
inputs:
greeting:
description: 'The greeting to use'
required: true
default: 'Hello'
name:
description: 'The name to greet'
required: false
default: 'World'
runs:
using: 'composite'
steps:
- name: Greet
run: |
echo "${{ inputs.greeting }}, ${{ inputs.name }}!"
shell: bash
8. Setting Output Values
| Property | Description | Example |
|---|---|---|
| outputs | Defines the outputs that a composite action can return. | |
Example: Setting Output Values in a Composite Action
name: "Composite Action with Outputs"
description: "A composite action that sets and returns outputs"
inputs:
message:
description: "Input message"
required: true
outputs:
result:
description: "The processed message"
value: ${{ steps.process.outputs.message }}
runs:
using: "composite"
steps:
- name: Process Message
id: process
run: |
echo "message=Processed: ${{ inputs.message }}" >> $GITHUB_OUTPUT
shell: bash
Note: Output values are set using the
GITHUB_OUTPUT file in composite actions.9. Using Environment Variables
| Variable | Value | Description |
|---|---|---|
| GITHUB_ACTION_PATH | /home/runner/work/my-repo/my-repo |
Path to the action directory |
| GITHUB_ENV | /home/runner/work/my-repo/my-repo/GITHUB_ENV |
File to write environment variables to |
| GITHUB_OUTPUT | /home/runner/work/my-repo/my-repo/GITHUB_OUTPUT |
File to write outputs to |
Example: Setting an environment variable in a composite action
name: 'Set Environment Variable'
runs:
using: 'composite'
steps:
- name: Set environment variable
run: echo "MY_VAR=value" >> $GITHUB_ENV
shell: bash
Example: Reading an environment variable in a composite action
name: 'Read Environment Variable'
runs:
using: 'composite'
steps:
- name: Use environment variable
run: echo "The value is $MY_VAR"
shell: bash
10. Handling Errors
| Property | Description | Values |
|---|---|---|
| on-failure | Defines action to take when a step fails | continue, abort |
| continue-on-error | Allows a step to continue even if it fails | true, false |
Example: Using continue-on-error
steps:
- name: Install dependencies
id: install
run: npm install
continue-on-error: true
- name: Run tests
if: steps.install.outcome == 'success'
run: npm test
Example: Handling failure with on-failure
jobs:
build:
steps:
- name: Build
run: |
echo "Building..."
exit 1
on-failure: |
echo "Build failed, running cleanup"
rm -rf build/
Note:
on-failure is only supported in composite actions and cannot be used in regular job steps.
Error Handling Best Practices
- Use
continue-on-error: truefor optional steps that shouldn't halt the workflow - Implement
on-failurefor composite actions to handle step failures gracefully - Log errors with descriptive messages to aid debugging
11. Using Pre and Post Steps
Pre and post steps are used to run setup or cleanup operations before or after a composite action runs.
| Step Type | Description | Usage |
|---|---|---|
| pre | Runs before the composite action's main steps | pre: 'run: echo "Running pre-step" |
| post | Runs after the composite action's main steps | post: 'run: echo "Running post-step" |
Example: Using pre and post steps in a composite action
name: 'Example Composite Action'
description: 'A composite action with pre and post steps'
inputs:
greeting:
description: 'Greeting to use'
required: false
default: 'Hello'
runs:
using: 'composite'
steps:
- name: Pre-step
uses: actions/github-script@v6
with:
script: |
console.log('Running pre-step');
- name: Main action
run: echo "${{ inputs.greeting }} World!"
shell: bash
- name: Post-step
uses: actions/github-script@v6
with:
script: |
console.log('Running post-step');
12. Sharing Composite Actions
| Aspect | Description | Details |
|---|---|---|
| Repository Location | Where to store composite actions | Store in a GitHub repository, typically under .github/workflows or as a reusable component in a dedicated repo. |
| Publishing Method | How to share composite actions | Use GitHub Marketplace or publish as a reusable workflow in a public repository. |
| Versioning | How to version composite actions | Use semantic version tags (e.g., v1.0.0) to manage releases and updates. |
| Documentation | What to include in documentation | Include a README.md with usage examples, parameters, and configuration options. |
| Access Control | Who can use the action | Actions in public repositories are accessible to everyone; private actions require appropriate permissions. |
Example: Using a Shared Composite Action
name: Use Shared Composite Action
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Use Composite Action
uses: owner/repo/action-name@v1.0.0
with:
input-value: "example"
Note: Composite actions must be published in a repository with proper permissions to be used by others.
Warning: Ensure that composite actions are well-documented and tested before sharing to avoid breaking workflows.
13. Versioning Composite Actions
| Version Type | Description | Usage |
|---|---|---|
| Major | Breaking changes that require updates to the composite action usage | actions/checkout@v3 |
| Minor | Backward-compatible features or enhancements | actions/checkout@v3.0 |
| Patch | Backward-compatible bug fixes | actions/checkout@v3.0.0 |
Example: Using a specific version in a workflow
jobs:
build:
steps:
- name: Use composite action
uses: my-org/my-repo@v2.1.0
Note: It is recommended to pin to a specific version or tag to ensure stability and prevent unexpected behavior from updates.