Manually Trigger A GitHub Actions Workflow

Currently, the GitHub UI doesn’t provide any mechanism to manually trigger a GitHub Actions workflow. The exception being that you can re-run a failed workflow.

Recently at Pixite, we created a new GitHub Actions workflow to help update the contents of our app’s home screen on a daily basis. This setup is easy to do with GitHub Actions, and is serving it’s purpose as expected.

However, re ran into the challenge of wanting to run our workflow outside of its pre-scheduled time.

Since there isn’t any means of triggering a workflow from within the current GitHub UI, we had to explore how to manually trigger a GitHub Actions workflow.

Repository Dispatch Events

The solution to this problem comes in the form of sending a repository dispatch event using the GitHub api. The repository_dispatch event is a webhook event which can be treated as a trigger for a GitHub Actions workflow.

By externally triggering a repository_dispatch event, we can run our desired workflow on command.

Scheduling a GitHub Actions workflow

To illustrate how we can manually trigger a GitHub actions workflow, we can walk through a simple example from my sandbox project: https://github.com/n8ebel/GitHubActionsAutomationSandbox

To start, we can define a trivial workflow which prints a message to the terminal. We’ll schedule this workflow to run every 5 minutes.

name: Do Something That Needs Scheduled

on:
  schedule:
    - cron:  '*/5 * * * *'

jobs:
  build:
    name: Run Some Scheduled Thing
    runs-on: ubuntu-latest
    steps:

      - name: Do Something
        run: echo Doing Something...

Now, we can walk through the steps for how we can manually trigger this workflow.

Triggering A repository_dispatch Event Using Curl

To manually trigger the repository_dispatch event, we need to interact with the following GitHub api endpoint:

POST /repos/:owner/:repo/dispatches

Using the repository name (GitHubActionsAutomationSandbox), along with my GitHub username (n8ebel), we can build the full path for the endpoint we’ll be interacting with:

https://api.github.com/repos/n8ebel/GitHubActionsAutomationSandbox/dispatches

To make the POST request to this endpoint, we need to do several things:

  1. Add a custom media type in the Accept header
  2. Authenticate the call using an Authorization header and a personal access token with repo permissions for the repository we’re working with
  3. Specify an event_type in the POST body

Adding the custom media type

The following custom media type is required to make the call to the /repos/:owner/:repo/dispatches endpoint:

application/vnd.github.everest-preview+json

To add this to our curl command, we will add an Accept header as follows:

-H "Accept: application/vnd.github.everest-preview+json"

Authenticating the POST request

To authenticate the request, you’ll need to use, or generate, a new personal access token that has access to the repository you’re working with. That token must have the repo scope provided to it.

To understand how to do that, you can follow the steps outlined in the GitHub documentation.

Once you have your token, we’ll update our curl command by adding an Authorization header as follows:

-H "Authorization: token your-token-here"

Adding an event_type

The last part of building our request is to define the event_type property in the POST body.

event_typeStringRequired webhook event name

In this example, we’ll name our event “do-something”.

To add our POST body in JSON format, we can use the following snippet:

--data '{"event_type": "do-something"}'

Building the final curl command

With all of our command components defined, we can build our final curl command like this:

curl -H "Accept: application/vnd.github.everest-preview+json" \
    -H "Authorization: token <your-token-here>" \
    --request POST \
    --data '{"event_type": "do-something"}' \
    https://api.github.com/repos/n8ebel/GitHubActionsAutomationSandbox/dispatches

When we run this command, a webhook event will be received by our repository. To manually trigger a GitHub actions workflow from this webhook event, we can update our action to respond to the repository_dispatch trigger.

Responding to the repository_dispatch event in a GitHub Actions workflow

Responding to the repository_dispatch trigger in our workflow requires a small update as seen in the following snippet:

name: Do Something That Needs Scheduled

on:
  repository_dispatch:
    types: do-something
  schedule:
    - cron:  '*/5 * * * *'

jobs:
  ...

In the on: block of our workflow configuration, we’ve added repository_dispatch. Additionally, we’ve passed a type which matches the event_type we specified in our curl command.

At this point, we’ve done it! We can now manually trigger our GitHub actions workflow using curl from the command line.

If we do not specify the types property of the repository_dispatch trigger, our workflow will run in response to any repository_dispatch event. Specifying the type enables us to control which workflows are run when we send the repository_dispatch event.

Sending data to your triggered workflow

At this point, our GitHub actions workflow is only using the event_type property of the repository_dispatch event. However, that event also has a client_payload property we can use to add additional data with which to customize our workflow.

client_payloadObjectA JSON field to pass additional data

With this client_payload property, we can pass configuration values, text, etc.

Let’s imagine we want to send some simple text with our repository_dispatch event and then print that text out during our workflow.

To start, we can update the body of our POST request to include a client_payload JSON object that includes a text property as in the following example:

{
  "event_type": "do-something",
  "client_payload": {
    "text": "a title"
  }
}

We can add this updated POST body JSON to our existing curl command to end up with something like the following:

curl -H "Accept: application/vnd.github.everest-preview+json" \
    -H "Authorization: token <your-token-here>" \
    --request POST \
    --data '{"event_type": "do-something", "client_payload": { "text": "a title"}}' \
    https://api.github.com/repos/n8ebel/GitHubActionsAutomationSandbox/dispatches

Now, when our workflow receives this event, it will contain this additional data which we can then use within the workflow.

For example, to print out the value of our client_payload.text property, we can add an additional workflow step which accesses that property using the following syntax:

github.event.client_payload.text

The full task to print this value during the execution of our workflow might look something like this:

- name: Do Something Based On Triggered Event Data
        run: 'echo "Event text: ${{ github.event.client_payload.text }}"'

When the repository_dispatch event is received, and this step is run, we will see the passed text value printed out to the workflow output as in this screenshot:

The full workflow will now look something like the following:

name: Do Something That Needs Scheduled

on:
  repository_dispatch:
    types: do-something
  schedule:
    - cron:  '*/5 * * * *'

jobs:
  build:
    name: Run Some Scheduled Thing
    runs-on: ubuntu-latest
    steps:

      - name: Do Something
        run: echo Doing Something...

      - name: Do Something Based On Triggered Event Data
        run: 'echo "Triggered event text: ${{ github.event.client_payload.text }}"'

FAQ

Can you manually trigger GitHub Actions?

Yes. Using the GitHub api, repository dispatch events, and workflow dispatch events.

What events trigger GitHub Actions workflows?

There are three event types that will trigger your workflow. Webhook events (things like commit and push), scheduled events, and external events via repository dispatch and workflow dispatch events.

Conclusion

In this post, we’ve walked through how to manually trigger a GitHub Actions workflow using curl from the command line.

We saw how we could update an existing workflow, running on a schedule, to respond to repository_dispatch events so they can be triggered manually.

Finally, we explored how to pass additional data to our workflows using the client_payload property of the repository_dispatch event enabling us to dynamically control the output of our workflows based on what data we send when manually triggering the workflow.

In a future post, we’ll explore a more practical example of how the client_payload property could be a helpful tool in our CI pipeline.