A universal action that supports dispatching workflows with either the
workflow_dispatch or repository_dispatch event. Additionally, this action
can be configured to discover the Run ID of a dispatched workflow through a
efficient and accurate correlation algorithm.
The latter algorithm was designed as a workaround for a technical limitation that prevents the dispatch APIs from returning a Run ID.
There was a need for this action as currently available actions...
- Support the
workflow_dispatchorrepository_dispatchevent, but not both - Use Run ID extraction algorithms that are either API-intensive or unreliable on repositories that experience a high velocity of workflows
This GitHub Action is a fork of
codex-/return-dispatch. This
action supported the ability to extract a Run ID, but exclusively supported the
workflow_dispatch method. I decided to fork this action as it had an intuitive
code-base and excellent testing philosophy.
From a compatibility and performance perspective, this GitHub Action
superseedes
codex-/return-dispatch, as it
additionally supports the repository_dispatch method and uses a more efficient
algorithm to extract the Run ID for a dispatched workflow
steps:
- uses: lasith-kg/dispatch-workflow@v3
id: workflow-dispatch
name: 'Dispatch Workflow using workflow_dispatch Method'
with:
dispatch-method: workflow_dispatch
repo: repository-name
owner: repository-owner
ref: refs/heads/main # or main
workflow: automation-test.yml # Or Workflow ID
token: ${{ secrets.TOKEN }} # GitHub Token With Relevant Permissions
workflow-inputs: |
{
"string-type": "placeholder",
"number-type": "1", // Workaround for 'Number' types
"boolean-type": "true" // Workaround for 'Boolean' types
}steps:
- uses: lasith-kg/dispatch-workflow@v3
id: repository-dispatch
name: 'Dispatch Workflow using repository_dispatch Method'
with:
dispatch-method: repository_dispatch
repo: repository-name
owner: repository-owner
event-type: deploy # Event To Trigger From Workflow
token: ${{ secrets.TOKEN }} # GitHub Token With Relevant Permissions
workflow-inputs: |
{
"string-type": "placeholder",
"nested": { // Supports Nesting
"number-type": 1, // Supports Native 'Number' types
"boolean-type": true // Supports Native 'Boolean' types
}
}# .github/workflows/automation-test.yml [refs/heads/main]
name: Workflow Name
on:
workflow_dispatch:
inputs:
string-type:
description: An input of type 'String'
required: true
type: string
number-type:
description: An input of type 'Number'
type: number
boolean-type:
description: An input of type 'Boolean'
type: boolean
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Echo Inputs
run: |
echo "${{ inputs.string-type }}" # "placeholder"
if [[ "${{ inputs.number-type }}" -gt -1 ]]; then echo "π’"; fi # π’
if [[ "${{ inputs.boolean-type }}" == "true" ]]; then echo "π’"; fi # π’name: Workflow Name
on:
repository_dispatch:
types:
- deploy
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Echo Inputs
run: |
echo "${{ github.event.client_payload.string-type }}" # "placeholder"
if [[ "${{ github.event.client_payload.nested.number-type }}" -gt -1 ]]; then echo "π’"; fi # π’
if [[ "${{ github.event.client_payload.nested.boolean-type }}" == "true" ]]; then echo "π’"; fi # π’Workflow discovery is disabled by default, but can be enabled with the
discover: true configuration. When enabled for repository_dispatch, the
receiving workflow must be modified to intercept the Distinct ID.
steps:
- uses: lasith-kg/dispatch-workflow@v3
id: dispatch-with-discovery
name: "Dispatch Workflow With Discovery"
with:
...
discover: true
- id: echo-run-id-url
name: "Echo Run ID and Run URL"
run: |
echo "${{ steps.dispatch-with-discovery.outputs.run-id }}"
echo "${{ steps.dispatch-with-discovery.outputs.run-url }}"On September 26, 2022, GitHub introduced the ability to set
dynamic names for workflow runs.
The new run-name attribute will accept expressions, thus allowing us to inject
the Distinct ID into the queryable view.
The run-name expression below injects the Distinct ID into the queryable
view, returning a placeholder value N/A if one is not available.
name: Workflow Name
run-name: >
Workflow Name [${{
github.event.client_payload.distinct_id &&
github.event.client_payload.distinct_id || 'N/A' }}]
on:
repository_dispatch:
types:
- deployOn February 19, 2026, GitHub
announced
that the response from the createWorkflowDispatch API would now include the ID
of the dispatched workflow. Under the 2022-11-28 API version this behaviour is
activated by passing return_run_details: true into the request payload. From
the 2026-03-10 API version onwards it becomes the default and the flag no
longer needs to be passed.
When using lasith-kg/dispatch-workflow@v3, the workflow_dispatch invocation
method no longer requires you to expose a distinct ID via the run-name
attribute for workflow discovery.
name: Workflow Name
on:
workflow_dispatch:Dispatching a Workflow requires an authenticated GITHUB_TOKEN. The required
permissions for this GITHUB_TOKEN depends on the following factors...
- Dispatch Method:
repository_dispatch,workflow_dispatch - Discovery:
true,false - Repository Visiblity: Private, Public
There are also multiple methods of generating GITHUB_TOKEN. If you are
dispatching a workflow from the current repository, a GitHub Actions
Token would be the most secure option. If you are dispatching a workflow to a
remote repository, I would personally recommend a GitHub App Token.
GitHub App Tokens are ephemeral (valid for 1 hour) and have fine grained access
control over permissions and repositories. Additionally they are not bound to a
particular developers identity, unlike a Personal Access Token.
- Fine Grained Tokens
- Personal Access Tokens (Classic)
- I would strongly advise using this as they are not as secure as it's fine-grained replacement and can potentially be configured without an expiry time.
The below table shows the neccessary permissions for all the unique combinations of these factors. If using a Fine Grained Token, ensure that the permissions correspond to the repository that contains the workflow you are attempting to dispatch.
| Mode | Fine Grained Tokens | Personal Access Token (Classic) |
|---|---|---|
repository_dispatch |
contents: write |
Private: repo / Public: public_repo |
repository_dispatch + discover: true |
contents: write + actions: read |
Private: repo / Public: public_repo |
workflow_dispatch |
actions: write |
Private: repo / Public: public_repo |
workflow_dispatch + discover: true |
actions: write |
Private: repo / Public: public_repo |
| Name | Description | Required | Default |
|---|---|---|---|
dispatch-method |
The method that will be used for dispatching GitHub workflows: repository_dispatch, workflow_dispatch |
true |
|
repo |
Repository of the workflow to dispatch | true |
|
owner |
Owner of the given repository | true |
|
token |
GitHub API token for making API requests | true |
|
ref |
If the selected dispatch method is workflow_dispatch, the git reference for the workflow. The reference can be a branch or tag name |
conditional |
|
workflow |
If the selected dispatch method is workflow_dispatch, the ID or the workflow file name to dispatch |
conditional |
|
event-type |
If the selected dispatch method is repository_dispatch, what event type will be triggered in the repository. |
conditional |
|
workflow-inputs |
A JSON object that contains extra information that will be provided to the dispatch call | false |
'{}' |
discover |
A flag to enable the discovery of the Run ID from the dispatched workflow | false |
false |
starting-delay-ms |
The delay, in milliseconds, before executing the function for the first time. | false |
200 |
max-attempts |
The maximum number of times to attempt read-only GitHub API requests. | false |
5 |
time-multiple |
The starting-delay-ms is multiplied by the time-multiple to increase the delay between reattempts. |
false |
2 |
By default, this GitHub Action has no outputs. However, when discovery mode is
enabled, the Run ID and Run URL become exposed as outputs. With the Run ID,
you can create some powerful automation where the parent workflow can wait for
the status of the child workflow using the
codex-/await-remote-run GitHub
Action.
| Name | Description |
|---|---|
run-id |
The Run ID of the workflow that was dispatched |
run-url |
The URL of the workflow that was dispatched |
steps:
- uses: lasith-kg/dispatch-workflow@v3
id: wait-repository-dispatch
name: 'Dispatch Using repository_dispatch Method And Wait For Run-ID'
with:
dispatch-method: 'repository_dispatch'
event-type: 'deploy'
repo: ${{ github.event.repository.name }}
owner: ${{ github.repository_owner }}
token: ${{ secrets.GITHUB_TOKEN }}
discover: true
- name: Await Run ID ${{ steps.wait-repository-dispatch.outputs.run-id }}
uses: codex-/await-remote-run@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
repo: ${{ github.event.repository.name }}
owner: ${{ github.repository_owner }}
run_id: ${{ steps.wait-repository-dispatch.outputs.run-id }}
run_timeout_seconds: 300 # Optional
poll_interval_ms: 5000 # OptionalThis action supports the ability to provide workflow inputs for both the
repository_dispatch and workflow_dispatch method. However, both methods have
their unique limitations.
Source: peter-evans/repository-dispatch # Client Payload
The Create a repository dispatch event API call allows a maximum of 10 top-level properties in the workflow inputs JSON. If you use more than that you will see an error message like the following.
No more than 10 properties are allowed; 14 were supplied.
For example, this payload will fail because the github object has more than
10 top-level properties.
workflow-inputs: ${{ toJson(github) }}A simple work-around is that you can simply wrap the payload in a single top-level property. The following payload will succeed.
workflow-inputs: '{"github": ${{ toJson(github) }}}'Additionally, there is a limitation on the total data size of the client-payload. A very large payload may result in the following error
client_payload is too large
The Create a workflow dispatch event API call also sets the maximum number of top-level properties in the workflow inputs JSON to 10. Any default properties configured in the workflow file will be considered towards this count when inputs are omitted.
An additional requirement is that all top-level properties must be a
string. Any inputs represented as a number or boolean will get
rejected. Therefore values of these types must be wrapped in quotes to
successfully dispatch the workflow.
# Invalid β
- uses: lasith-kg/dispatch-workflow@v3
id: workflow-dispatch
name: 'Dispatch Using workflow_dispatch Method'
with:
dispatch-method: 'workflow_dispatch'
...
workflow-inputs: |
{
"foo": true,
"bar: 1
}
# Valid π’
- uses: lasith-kg/dispatch-workflow@v3
id: workflow-dispatch
name: 'Dispatch Using workflow_dispatch Method'
with:
dispatch-method: 'workflow_dispatch'
...
workflow-inputs: |
{
"foo": "true",
"bar: "1"
}When interacting with the GitHub REST API, it's beneficial to handle potential flakiness by employing exponential backoff. This action allows users to customize this behavior through optional parameters, although the default values work well for most scenarios.
starting-delay-ms: The initial delay, in milliseconds, before the first API call attempt.max-attempts: The maximum number of times to attempt read-only GitHub API requests.time-multiple: The factor by which thestarting-delay-msis multiplied for each reattempt, influencing the delay duration.
- uses: lasith-kg/dispatch-workflow@v3
id: custom-backoff
name: 'Dispatch with custom exponential backoff parameters'
with:
...
starting-delay-ms: 150
max-attempts: 3
time-multiple: 1.5If you have enabled discovery and use workflow_dispatch to invoke a child
workflow, remove the run-name attribute and distinct_id input from the child
workflow.
Upgrade the parent workflow first, then the child. Once on
@v3the parent stops sendingdistinct_id. If the child hasn't been updated yet, its run name renders asChild Workflow [N/A]β purely cosmetic, with no impact on behaviour.
name: Parent Workflow
jobs:
do-work:
steps:
- - uses: lasith-kg/dispatch-workflow@v2
+ - uses: lasith-kg/dispatch-workflow@v3
id: workflow-dispatch
name: 'Dispatch Workflow using workflow_dispatch Method'
with:
dispatch-method: workflow_dispatch
workflow: child-workflow.yml
...name: Child Workflow
- run-name: Child Workflow [${{ inputs.distinct_id && inputs.distinct_id || 'N/A' }}]
on:
workflow_dispatch:
- inputs:
- distinct_id:
- description: 'Distinct ID'
- required: false