How to Trigger a Webhook on a Schedule Using GitHub Actions
Recently I added a feature to the speaking page on this site: a list of the most popular episodes of The Laravel Podcast for this week.
However, this site is powered by a static generator, so the data on that page will go out of date pretty soon after each deploy.
I considered setting up a local cron job on my server to run the deploy script once a day, which is certainly my easiest option. But I didn't want to duplicate my deploy script in cron that I had already configured in my host, Laravel Forge.
Thankfully, Forge gives you an easy webhook to trigger your existing deploy script, so I figured that'd be my cleanest option.
The plan
I'll want to call my webhook, which we'll approximate as https://forge.laravel.com/webhooks/my-webhook-yay
, once every day.
First, I set up a new GitHub Action workflow in my project. I created a YAML file for the workflow at .github/workflows/deploy-on-schedule.yml
, with the following basic contents:
name: Deploy Every Day
To learn more about how this works, check out GitHub's official documentation on using GitHub Actions.
How to call a webhook URL from a GitHub Action workflow
There are two main ways to call a URL from a GitHub Action workflow: with curl, and with a published GitHub Action. I want you to see how simple it is to call curl yourself, but it's no faster than the GitHub Action, so use whichever is more comfortable for you.
Calling a URL with curl
You can call any arbitrary shell code directly from your workflow, so you can build a curl command directly in your action:
jobs:
webhook:
name: Ping webhook
runs-on: ubuntu-latest
steps:
- name: Use curl to ping webhook
run: |
curl -n "https://forge.laravel.com/webhooks/my-webhook-yay"
If you want to add headers or extra content to the request, you can flesh out your curl command as much as you want, passing \
at the end of each line:
jobs:
webhook:
name: Ping webhook
runs-on: ubuntu-latest
steps:
- name: Use curl to ping webhook
run: |
curl -n "https://forge.laravel.com/webhooks/my-webhook-yay" \
--header 'Content-Type: application/json' \
--data '{"some-datadata":"here"}'
Calling a webhook with webhook-action
There's also a GitHub Action dedicated to calling external URLs, joelwmale/webhook-action
.
Here's the syntax for what we're doing here:
jobs:
webhook:
name: Ping webhook
runs-on: ubuntu-latest
steps:
- name: Use webhook action to ping webhook
uses: joelwmale/webhook-action@2.3.2
with:
url: https://forge.laravel.com/webhooks/my-webhook-yay
If you want to learn more about how to use this action, including how to pass headers and data, check out this introductory post.
How to schedule a GitHub Action to run regularly
Now that we've built out the ability to call a webhook from our workflow, how do we call a workflow on our own schedule?
If you're familiar with GitHub Actions, you're likely familiar with the on
property, which allows you to define what events trigger this workflow running. Normally, we'd attach it to Git events—push
to a certain branch, for example.
But we can also define it on a schedule, using the same syntax we use for cron:
on:
schedule:
- cron: "0 0 * * *"
The above schedule will run our workflow once a day, at the end of the day.
You can take a look at the GitHub Actions docs for schedule if you'd like to learn more.
Putting the Pieces Together
So let's put these together into a single workflow file:
name: Deploy Every Day
on:
schedule:
- cron: "0 0 * * *"
jobs:
webhook:
name: Ping webhook
runs-on: ubuntu-latest
steps:
- name: Use curl to ping webhook
run: |
curl -n "https://forge.laravel.com/webhooks/my-webhook-yay"
Or, if you want to use the Action:
name: Deploy Every Day
on:
schedule:
- cron: "0 0 * * *"
jobs:
webhook:
name: Ping webhook
runs-on: ubuntu-latest
steps:
- name: Use webhook action to ping webhook
uses: joelwmale/webhook-action@2.3.2
with:
url: https://forge.laravel.com/webhooks/my-webhook-yay
Two more tricks, and a caveat
That's it for building out our main workflow! But I have two more tricks to share that helped me in building this action.
Trick 1: Running your workflow manually using workflow_dispatch
If you're building a workflow that is only triggered in certain circumstances (whether it's a given push, or on a schedule), you may want to manually trigger it some times, especially when you're first building it out. But how?
There's another event (defined under the on:
property of our config) that will serve us in this circumstance: workflow_dispatch
. There's a lot of work you can do to customize workflow_dispatch, but for now let's just enable it without parameters:
name: Deploy Every Day
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
jobs:
webhook:
name: Ping webhook
runs-on: ubuntu-latest
steps:
- name: Use curl to ping webhook
run: |
curl -n "https://forge.laravel.com/webhooks/my-webhook-yay"
Now that we have that entry there in our YAML, we can manually trigger a run of this workflow. Open up your repo in GitHub; choose the "Actions" tab, and choose your relevant workflow in the left section. You'll now see a banner saying "This workflow has a workflow_dispatch
event trigger.", with a "Run workflow" button next to it. You can use this button to manually trigger runs of this workflow!
Trick 2: Passing secrets into your call
Let's say you want to extract the specific URL out of your code and instead store it in GitHub secrets. Let's take a quick look at how you'd do that.
First, for the GitHub Action, which is simple:
jobs:
webhook:
name: Ping webhook
runs-on: ubuntu-latest
steps:
- name: Use webhook action to ping webhook
uses: joelwmale/webhook-action@2.3.2
with:
url: ${{ secrets.webhook_url }}
It's a bit more complex to pass an environment variable into bash, but it's still quite manageable:
jobs:
webhook:
name: Ping webhook
runs-on: ubuntu-latest
steps:
- name: Use curl to ping webhook
env:
WEBHOOK_URL: ${{ secrets.webhook_url }}
run: |
curl -n "$WEBHOOK_URL"
Caveat: Forge specifically
While I'm using Laravel Forge as the context here, this post is really just about how to schedule GitHub Actions workflows and how to call URLs within them. However, if you are using Forge, Tightenite Guillermo Cava Nuñez pointed out that Forge has its own GitHub Action.
Additionally, the Forge documentation points out how to use the Forge CLI to run more than just deploys in your GitHub Action workflows, if you're interested.
The end
That's it! I hope you learned something useful!
Comments? I'm @stauffermatt on Twitter
Tags: github actions • laravel forge