Setting Up Webhooks for GitHub Actions

Quick Guide on How to Trigger a GitHub Action via Webhook

August 27, 2019

GitHub Actions are GitHub’s Continous Integration (CI) solution used to automate building, packaging, and testing of software projects. In this post we will be walking through how to set-up a GitHub Action that is triggerable by an external service via the GitHub Webhook API.

The primary use-case we are solving for is that where the data used by an application is not co-located with the code. Examples of this might be:

  • Triggering a GitHub Action to build and publish an updated version of a static asset. Eg: A static site with content from a headless CMS API like Prismic, Contentful, Ghost, or other data source.
  • Triggering a GitHub Action to deploy an new version to production after a manual approval, that is not accompanied by a code change, but wired-up to Slack, Discord, or other Software.

Getting Started

To setup a webhook we’ll need the following:

  1. GitHub Action - to build, test, or deploy an application
    • An example configuration is provided below.
  2. Access Token to the GitHub repository
  3. Source that invokes the Webhook

GitHub Action Set Up

Below is what a typical GitHub Action YAML configuration file may look like.

name: Webhook Example
on: repository_dispatch jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    
    - name: On my_custom_webhook do ABC...
      if: github.event.action == 'my_custom_webhook'
      run: |
        echo "Hello From my_custom_webhook...doing ABC"
        
    - name: On my_custom_webhook_2 do XYZ...
      if: github.event.action == 'my_custom_webhook_2'
      run: |
        echo "Hello From my_custom_webhook_2...doing XYZ"

The single requirement is the on value of the target workflow must include the value: repository_dispatch. The respository_dispatch value can be part of a list of values, or standalone.

If the repository is only ever expected to respond to a single webhook type then there is no need to define a predicate to check the github.event.action of the build. All invocations will be processed by this workflow.

However, we may want to respond to different webhooks within the same repository. To distinguish between different webhook sources we need to define a predicate that checks github.event.action for a value we define. We can then define different run steps for each of the different webhook types. In the example snippet above not that we have defined support for my_custom_webhook and my_custom_webhook_2.

Next we are ready to feed our custom value into github.event.action in the GitHub Action by calling the GitHub API. Let’s aquire an access token so that we can formulate the appropriate request.

Obtain an Access Token

Before we can trigger our Action via a webhook, we need to obtain an access token.

Follow this guide here: Creating a Personal Access Token for the Command Line . Only repo persmission should be needed to trigger the GitHub Action.

Once the access token has been obtained it can be used to invoke the GitHub API to trigger the GitHub Action.

Triggering the GitHub Action

We are finally ready to trigger our GitHub Action. We’ll be using curl to illustrate the required payload.

The request we need to make it to https://api.github.com/repos/:owner/:repo/dispatches. Where :owner is the account that owns the repository, and :repo is the name of target repository with the configured GitHub Action.

The request headers will need to include: - Accept: application/vnd.github.everest-preview+json - Authorization: token $TOKEN where $TOKEN represents our access token aquired in the previous section.

Lastly, we need to include a JSON body with an event_type key. The value of event_type will be set in github.event.action that we used in our GitHub Action configuration.

Putting it all together the request looks as follows:

curl -X POST https://api.github.com/repos/:owner/:repo/dispatches \
-H 'Accept: application/vnd.github.everest-preview+json' \
-H 'Authorization: token $TOKEN' \
--data '{"event_type": "$CUSTOM_ACTION_NAME"}'

Note that CUSTOM_ACTION_NAME corresponds to my_custom_webhook and my_custom_webhook_2 in our example workflow YAML above. The value can be any string.

At this point running the curl command should cause a GitHub Action workflow to run for the target repository on GitHub.

Conclusion

This post has been a short guide on how to configure a GitHub Action workflow to respond to custom webhook requests via the GitHub API. Having GitHub Actions be triggerable from ourside of the typical git workflow can be a valuable tool in the automation of common processes.

Additional Guidance and Considerations

Many folks may have noticed that triggering a GitHub Action via an API call is possible, but not directly applicable without extra infrastructure since the invoking party needs to keep secrets, use custom headers, and post a custom JSON body. On top of that many sources for webhooks(eg: Prismic, Ghost, etc.) may not allow you to define much more than a URL. All this quickly rules out direct API access from some third-party to GitHub.

One solution for this is to configure a lightweight application that can broker the request. Keeping in mind that you’ll need to provision, secure, and maintain the additional resource.

Another route would be to use something like AWS API Gateway and AWS Lambda to create an on-demand task to keeps the custom GitHub API request without the need to maintain and secur an additional server.

Best of luck!

Questions and feedback are welcome. Find me on Twitter: @bctellez

Further Reading & References