GitHub Action - Deploy to Vercel
This GitHub action automatically triggers a Vercel deployment when commits are pushed on the remote repository.
Table of contents
- Workflow file(s)
- Configuring the action
- Understanding the action
- Triggering the action remotely (using
workflow_dispatch
)
Workflow file(s)
There are 2 (slightly) different workflows files, one for staging and one for production:
.github/workflows/deploy-vercel-production.yml
.github/workflows/deploy-vercel-staging.yml
Configuring the action
Required GitHub secrets
List of necessary requirements for NRN
Deploy to Vercel
automations to work properly.
VERCEL_TOKEN
: Used to trigger Vercel deployments from GitHub actions.- Create the Vercel secret at https://vercel.com/account/tokens and name it (e.g: “GitHub Actions - NRN app”).
- Create the
VERCEL_TOKEN
as Github secret for your app.
Understanding the action
Stages
We use two different stages. Each stage is meant to use a different configuration.
staging
:
When a commit is pushed on a branch (except those pushed on master
or main
), it automatically starts a new Vercel deployment, using the related staging configuration file. You can choose which customer you deploy by changing the symbolic link vercel.json
file. Changing the symlink changes which “CUSTOMER_REF” gets automatically deployed.
This is the default behaviour, but you may change it to match your desired workflow instead.
production
:
Commits pushed to the master
(or main
) branch will automatically deploy the “CUSTOMER_REF” specified in vercel.json
to Vercel, but it will use the production configuration file.
Those events are triggered by any pushed commit, but also merged pull-requests.
GitHub Actions Jobs workflow
The workflows are different depending on the stage (staging vs production). In staging, there are a lot more things happening, like creating a custom domain alias using the git branch name, LightHouse reports, etc.
Workflow details:
This workflow is slightly different depending on the stage, this is an overview. See each file for an in-depth workflow.
setup-environment
: Configures the deployment environment, install dependencies (like node, npm, etc.) that are requirements for the upcoming jobsstart-*-deployment
: (either staging or production)- Resolve customer to deploy from github event input (falls back to resolving it from vercel.json file)
- Resolve $VERCEL_DEPLOYMENT_URL
- Get stdout from deploy command (stderr prints build steps and stdout prints deployment url, which is what we are really looking for)
- Set the deployment url that will be included in the eventual PR comment
- Create a deployment alias based on the branch name, and link it to the deployment (so that each branch has its own domain automatically aliased to the latest commit)
await-for-vercel-deployment
: Waits for the Vercel deployment to reach “READY” state, so that other actions will be applied on a domain that is really online- Once finished, runs several jobs in parallel:
send-webhook-callback-once-deployment-ready
: Send a HTTP call to the webhook url that’s provided in the customer configuration file (vercel.*.json)run-2e2-tests
: Runs E2E tests against the Vercel deploymentrun-lighthouse-tests
: Runs LightHouse reports in parallel of E2E tests
- Once finished, runs several jobs in parallel:
Triggering the action remotely (using workflow_dispatch
)
Motivations
What’s the point of triggering a GitHub Action remotely through an HTTP call, or through the GUI?
At Unly, we use the
workflow_dispatch
feature to trigger a Vercel deployment through our Customer Success UI, so that they may deploy the platform of our customers without technical assistance.Use cases are numerous, you could also want to chain call your workflows. For instance, one workflow might call another. (see Invoking the workflow through a GitHub Action section)
The possibilities are limitless, you don’t have to use workflow_dispatch
, but it might very well be quite a nice feature for your business!
Introduction
It is possible to trigger a GitHub Action through an HTTP event. This is called a workflow dispatch
event.
Example:
on:
# There are several ways to trigger Github actions - See https://help.github.com/en/actions/reference/events-that-trigger-workflows#example-using-a-single-event for a comprehensive list:
# - "push": Triggers each time a commit is pushed
# - "pull_request": Triggers each time a commit is pushed within a pull request, it makes it much easier to write comments within the PR, but it suffers some strong limitations:
# - There is no way to trigger when a PR is merged into another - See https://github.community/t/pull-request-action-does-not-run-on-merge/16092?u=vadorequest
# - It won't trigger when the PR is conflicting with its base branch - See https://github.community/t/run-actions-on-pull-requests-with-merge-conflicts/17104/2?u=vadorequest
push: # Triggers on each pushed commit
branches-ignore:
- 'master'
# Allow manual trigger via a button in github or a HTTP call - See https://docs.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow#manually-running-a-workflow
# XXX Read more about how to use it with NRN in .github/WORKFLOW_DISPATCH.md
workflow_dispatch:
inputs:
customer:
description: 'Customer to deploy (airtable "ref")'
required: true
When you configure the option workflow_dispatch
as trigger for a GitHub Action, a few things happen:
- It can be triggered through the GitHub Actions UI, when the workflow is selected, and the user has at least
write
access to the repository - It can be triggered through an HTTP event.
- It can take inputs, which can be provided on both the UI and the HTTP request payload.
- On the above example,
customer
is a required input that is expected for the action to run.
- On the above example,
Accessing the inputs in our GitHub Action
All inputs are available within $
variable. Because this input has been explicitly required using required: true
, the $
value cannot be empty.
In order to use a fallback value (useful when the input isn’t required, e.g: required: false
), we can use this bash trick:
CUSTOMER_REF_TO_DEPLOY="${MANUAL_TRIGGER_CUSTOMER:-$(cat vercel.json | jq --raw-output '.build.env.NEXT_PUBLIC_CUSTOMER_REF')}"
If MANUAL_TRIGGER_CUSTOMER
is empty, then we’ll resolve its fallback value from the vercel.json
file and extract the build.env.NEXT_PUBLIC_CUSTOMER_REF
value.
Full example
jobs:
say_hello:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Say hello customer
run: |
# Resolving customer to deploy based on the github event input, when using manual deployment triggerer through "workflow_dispatch" event
# Falls back to the customer specified in the vercel.json file, which is most useful when deployment is triggered through "push" event
MANUAL_TRIGGER_CUSTOMER="$"
echo "MANUAL_TRIGGER_CUSTOMER: " $MANUAL_TRIGGER_CUSTOMER
echo "MANUAL_TRIGGER_CUSTOMER=$MANUAL_TRIGGER_CUSTOMER" >> $GITHUB_ENV
CUSTOMER_REF_TO_DEPLOY="${MANUAL_TRIGGER_CUSTOMER:-$(cat vercel.json | jq --raw-output '.build.env.NEXT_PUBLIC_CUSTOMER_REF')}"
echo "Customer to deploy: " $CUSTOMER_REF_TO_DEPLOY
echo "CUSTOMER_REF_TO_DEPLOY=$CUSTOMER_REF_TO_DEPLOY" >> $GITHUB_ENV
In the above example, we try to resolve MANUAL_TRIGGER_CUSTOMER
from the github customer
input. If it’s not set, we fall back to reading the build.env.NEXT_PUBLIC_CUSTOMER_REF
value of the vercel.json
file.
This is very handy to allow a user to use the GitHub UI to specify a customer to deploy, while using a proper fallback value resolved from the default customer to deploy (vercel.json
).
How to trigger the workflow using an external HTTP request?
Authentication
Authentication is always required when fetching data for a private repository. (see below example) Also, you might want to be authenticated to avoid hitting rate limits.
Resolving the workflow id
of the workflow you want to trigger
Each GitHub workflow has an id, and this id changes for every repository (forked repository will have different workflow ids as the source repository).
You’ll need this workflow id to be able to trigger the workflow from an external HTTP request.
Beware, your workflow id will change if you rename the workflow file.
GET https://api.github.com/repos/{owner}/{repo}/actions/workflows
Simple example
https://api.github.com/repos/UnlyEd/next-right-now/actions/workflows
Bash example
Without authentication:
curl -s \
-X GET \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/UnlyEd/next-right-now/actions/workflows | jq '.workflows[] | select(.path==".github/workflows/deploy-vercel-staging.yml") | .id'
With authentication:
curl -s \
-X GET \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token <YOUR_GITHUB_TOKEN>" \
https://api.github.com/repos/UnlyEd/next-right-now/actions/workflows | jq '.workflows[] | select(.path==".github/workflows/deploy-vercel-staging.yml") | .id'
Because Next Right Now is a public repository, you will not need to provide a token when accessing this read-only endpoint.
Invoking the workflow trough an HTTP call
Authentication
You’ll need to provide your credentials through the Authorization
HTTP header:
{
"Accept": "application/vnd.github.v3+json",
"Authorization": "token <TOKEN>"
}
This
personal access token
needs therepo (FULL)
andworkflow
permissions to be granted access.
Request body
You have to provide a request body, such as:
{
"ref": "master",
"inputs": {
"customer": "customer2"
}
}
- ref: A git reference, it can be a tag, a branch or a SHA commit.
- inputs: An object containing previously configured inputs.
Bash example
curl -s \
-X POST \
-d '{ "ref": "master", "inputs": { "customer": "customer2" }}' \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token <YOUR_GITHUB_TOKEN>" \
https://api.github.com/repos/UnlyEd/next-right-now/actions/workflows/3754866/dispatches
If it returns a 204
status code, it worked.
Invoking the workflow through a GitHub Action
There are several existing GitHub Actions available on the Marketplace.