GitHub Actions Repository Dispatch
Janne Kemppainen |There are lots and lots of events that can be used to trigger GitHub Actions. But if you want to control your actions programmatically from the outside you will need to use repository dispatch. In this post I will go through the essential things you need to know to trigger actions programmatically.
I assume that you have a basic understanding of GitHub Actions. If you need a refresher or are new to the subject I recommend that you check out my Gentle Introduction to GitHub Actions first.
Repository dispatch is a way to send named events to your GitHub repository with an optional data payload that can be accessed in the Actions workflows. The dispatch event must contain an event type argument which determines if the action should run or not. We can configure to workflow to run on multiple events, and they can have custom names.
Configuration
To use repository dispatch in your workflow you need to configure the trigger in the workflow YAML file. You need to define the repository_dispatch
event and set the types
that you want it to react to.
on:
repository_dispatch:
types: [build, release]
The types are custom names for the webhook event and you can define them freely. If you set multiple types the action is triggered when any one of them is received.
Note that you can still use your existing trigger configurations in the workflow and add the repository_dispatch
event as an extra. If you want to trigger the action manually from the GitHub UI you can use the workflow dispatch event.
The configuration needs to be in the default branch of your repository, so you cannot trigger the workflow from other branches. You are still free to check out any branch you wish within the workflow. So you could specify a non-default branch in the event payload and provide that to the actions/checkout step.
Triggering
The repository dispatch events are triggered by sending a POST
request to the following address:
https://api.github.com/repos/{owner}/{repo}/dispatches
Replace {owner}
and {repo}
with the correct values for your repository. Here is an example on how you can trigger the event from the command line with curl
:
curl -X POST \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token <token>" \
--data '{"event_type": "build", "client_payload": { "version": "1.2.3"}}' \
https://api.github.com/repos/jannekem/actions-playground/dispatches
You need to provide a personal access token in the authorization header to authenticate the request. Follow these instructions in the GitHub docs to create your token and replace <token>
in the command with your actual token. You also need to set the Accept
header to the value you see in the example.
Note: The authorization header must be in the
Authorization: token abc123...
format, not the bearer token formatAuthorization: Bearer abc123
!
The request body must contain the event_type
entry which must match with one of the event types you defined in the workflow file. If the event type doesn’t match any configuration then nothing happens and your request passes silently. The API does not tell if a workflow was triggered.
If you need to do it from a Python script you could use the requests library:
import os
import requests
TOKEN = os.environ.get("GITHUB_TOKEN")
OWNER = os.environ.get("GITHUB_OWNER")
REPO = os.environ.get("GITHUB_REPO")
VERSION = os.environ.get("VERSION")
headers = {
"Accept": "application/vnd.github.v3+json",
"Authorization": f"token {TOKEN}",
}
data = {
"event_type": "build",
"client_payload": {
"version": VERSION
}
}
requests.post(
f"https://api.github.com/repos/{OWNER}/{REPO}/dispatches",
data=data,
headers=headers
)
The above script would get argument values from environment variables and then create a POST request to the GitHub API endpoint.
Access data in a workflow
You can easily access the data that is sent as the client payload. All received values are available through the github.event.client_payload
object. In the previous example we sent a version string as the payload. It can be forwarded to an action step in the same way you would access other variables.
with:
version: ${{ github.event.client_payload.version }}
I already mentioned that there is a limitation where the workflow can only be triggered from the default branch. You can overcome this by defining the branch or commit manually.
- name: Checkout
uses: actions/checkout@v2
with:
ref: ${{ github.event.client_payload.ref }}
Then define the branch, tag, or SHA in the request payload:
{
"event_type": "my-event",
"client_payload": {
"ref": "my_branch"
}
}
Access data from JavaScript
If you are building your own action with JavaScript, it is possible to access the payload data directly. Use the @actions/github package to access the context of the running action:
const { context } = require("@actions/github");
const action = context.payload.action;
const version = context.payload.client_payload.version;
The context payload contains the action
name that was used to trigger the workflow. The value is equal to the event_type
field that you send in the repository dispatch event.
The client payload is available via context.payload.client_payload
and it contains the payload object.
One possible use case is to accept input parameters from both the workflow arguments and the repository dispatch event. For example this code would default to the workflow input and fall back to the dispatch payload :
const core = require("@actions/core");
const { context } = require("@actions/github");
const version = core.getInput("version") || context.payload.client_payload.version
Now you’re free to do whatever you want with the value!
Conclusion
If you try to go through the official documentation it can be a little difficult to understand how the repository dispatch event works. Hopefully this post has made things clearer to you!
Discuss on Twitter
Learn how to use the repository_dispatch event to trigger GitHub Actions programmatically https://t.co/zdxWMenZOj
— Janne Kemppainen (@pakstech) November 21, 2020
Previous post
Schedule Netlify Builds with GitHub ActionsNext post
Import ES6 Modules in Node.js