Deploy to Now from your CMS via a GitHub Action
Learn how to automatically rebuild and redeploy your website to ZEIT Now using a GitHub Action when some content is changed in your CMS.
I recently made a website for a client using Next.js that I wanted to host on ZEIT Now. I used Contentful for the content, and wanted the end result to be a static website for better performances, since the content shouldn’t change very often. Lastly, the build step involved a custom build.sh
script because of the project’s unconventional structure :
_build/
: The directory containing the final code to deploy, created and populated by thebuild.sh
script
For this specific use case involving a custom build step and a custom build output directory, AFAIK it’s not possible to use Now for GitHub since it requires the output to be placed in a public/
directory, which is the directory that will be served. Because of this requirement, Now’s Deploy Hooks were a no go too.
Netlify has a Publish directory option that seem to solve this problem… but I really wanted to use Now.
So how to automatically rebuild and redeploy this app to production – in the cloud – whenever edits are made in Contentful?
The solution I ended up using involves :
- A GitHub Action triggered on
repository_dispatch
, to automatically rebuild and redeploy in the cloud by simply calling a URL - A Contentful Webhook, to run the GitHub Action whenever some content is changed by my client in the CMS
Note: This article demonstrates how to setup a Webhook with Contentful since it’s the CMS I used for this project, but the steps should be similar in other CMSs.
Setup the GitHub Action
The GitHub Action will simply use the now
CLI to deploy the code. It’ll need a ZEIT token to pass to the CLI so it doesn’t ask to log in during the deployment.
1) Go to your repo on GitHub, click on the Actions
tab, and select the Simple workflow
starter workflow. Then replace the code with this :
2) Go to your ZEIT account and create a new token. Copy the generated value since we’ll need it in a second.
Back in your GitHub repo, go to Settings
and then Secrets
. Add a new secret named ZEIT_TOKEN
(which is the identifier that is used in the Action’s source code) with the value you’ve copied before.
That’s it! Our GitHub Action is ready to use.
Setup the Contenful Webhook
Now go to your Contentful space, click on Settings
(in the top bar) and then Webhooks
:
Click on the Add Webhook
button at the top right :
Name
Give it a Name
. I went with Build & Deploy to Production
so it matches my GitHub Action’s name, and since it’s explicit enough about what it does.
URL
The URL
should match the following format : https://api.github.com/repos/:owner/:repo/dispatches
. Just replace :owner
with your username and :repo
with your repository’s name :
Make sure the method is set to POST
.
Triggers
You probably want your GitHub Action to be triggered only when content is published or unpublished, but not when Content Types are modified or when a draft is saved. Thus, under Triggers
select Select specific triggering events
and check only the relevant events :
Headers
GitHub requires a specific value for the Accept
header because the repository_dispatch
event we’re using in our GitHub Action is currently available for preview (which means it can change at anytime “without advance notice” so it’s not recommended to use it in production, unless you know what you’re doing).
The User-Agent
header is always required by GitHub (you can put your username).
The Authorization
header is required for Contentful to be allowed to trigger our GitHub Action. It should be in the form token <github-token>
. You can create a GitHub token in your account’s settings (make sure to select the whole repo
scope). Then add it as a secret header so it isn’t visible to anyone that has access to Contentful (remember that this token can read and write your repos !) :
Note: If your repo is public, I think the repo > public_repo
scope should be enough but I haven’t tested (if anyone has, please leave a comment).
Payload
Finally, under Payload
select Customize the webhook payload
and add the following JSON as required by GitHub :
Here’s the code for copy / paste purposes :
{
"event_type": "contentful.content.publish_unpublish"
}
As long as it’s not empty, it doesn’t matter what the event_type
field contains if you don’t need to use this value anywhere else. Just know that it will be passed to your GitHub Action, in case you need it there.
Test that everything works!
Save your Webhook! Then, go to the Content
tab and update any entry. You’ll see that a new Workflow instance has been created in the Actions
tab of your GitHub repo 🎉 :
You can click on it to follow the progress. Once it reaches the Deploy
step, you’ll see a new deployment appear in your ZEIT project! This deployment will then be automatically promoted to production since we passed the --prod
argument to now
in our GitHub Action.
And voilà! 🥳