DEV Community

Cover image for How to deploy and remove Vercel Preview Deployment from GitHub Actions
Lucas Reis
Lucas Reis

Posted on

How to deploy and remove Vercel Preview Deployment from GitHub Actions

Recently I have started my journey learning about NextJS and the Vercel platform. As a experienced React Developer, I've developed several frontend applications in past 6 years with this library and it's really nice to see the whole React ecosystem building/following on what a company's says and interacts with the community. The future shines for React and any similarity to PHP is not a coincidence.

So let's get started. As I am building my startup, we decided to create the frontend + backend with NextJS. It's the best thing for our product, having a monolith with the backend and frontend included... and some other benefits like SSR and caching. Since we want to have fast iteration in the product, having a service like Vercel is helping us to build our product without caring about infrastructure (AWS, GCP). The prices are very modest, to be honest I think it's worthy to pay $20 for a full stack infrastructure with a included Postgres instance.

Instead of using their automatic build after pushing a commit to a branch, I've decided to deactivate this feature and trigger the builds from a GitHub Actions.

Step 1 - Gather the necessary ids

To interact with the Vercel API you need the projectId and teamId values. To obtain those values:

  • Go to the Vercel dashboard and select the team

Dashboard image

  • Click on settings

Settings image

  • Copy your team id

Team Id image

  • Select the project that you're working on by clicking in Overview

Overview image

  • Click in settings

Settings image

  • Copy your project id

Project id image

  • Create an admin token Create the admin token by visiting Tokens page. Don't forget to select Full Scope options. This is important because this token will be responsible to delete the deployments.

Admin token

Summarizing, you'll need 3 tokens from vercel:

Token Description Variable name
VERCEL_ORG_ID It's the team id VERCEL_ORG_ID
VERCEL_PROJECT_ID It's the project id VERCEL_PROJECT_ID
VERCEL_TOKEN It's the API key token VERCEL_TOKEN

Step 1 - Create the environment variables in GitHub Actions

Visit the repository settings and create the environment variables there.

GitHub Actions secrets

Step 2 - Setup the deploy_preview.yml workflow

  1. Go into your project, create a new workflow named deploy_preview.yml in the .github/workflows folder.
  2. Paste the following workflow content:
name: Vercel Preview Deployment

env:
  VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
  VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
  VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

permissions:
  contents: read
  statuses: write
  pull-requests: write

on:
  pull_request:
    types:
      - opened
      - synchronize

jobs:
  deploy-preview:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Extract branch name
        shell: bash
        run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
        id: extract_branch

      - name: Hash branch name
        uses: pplanel/hash-calculator-action@v1.3.1
        id: hash_branch
        with:
          input: ${{ steps.extract_branch.outputs.branch }}
          method: MD5

      - name: Install Vercel CLI
        run: npm install --global vercel@latest

      - name: Cache dependencies
        uses: actions/cache@v2
        id: cache-npm
        with:
          path: ~/.npm
          key: npm-${{ hashFiles('package-lock.json') }}
          restore-keys: npm-

      - name: Install dependencies
        if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
        run: npm ci --ignore-scripts

      - name: Pull Vercel Environment Information
        run: vercel pull --yes --environment=preview --token=$VERCEL_TOKEN

      - name: Deploy Project Artifacts to Vercel
        id: vercel
        env:
          META_TAG: ${{ steps.hash_branch.outputs.digest }}-${{ github.run_number }}-${{ github.run_attempt}}
        run: |
          vercel --version
          vercel pull --yes --environment=preview --token=$VERCEL_TOKEN
          vercel build --token=$VERCEL_TOKEN
          vercel deploy --prebuilt --archive=tgz --token=$VERCEL_TOKEN --meta base_hash=${{ env.META_TAG }}

          vercel ls --token=$VERCEL_TOKEN --meta base_hash=${{ env.META_TAG }} &> vercel-output
          url=$(cat vercel-output | grep http | awk '{print $2}')
          echo "New preview URL: $url"
          echo "META_TAG=$META_TAG"
          echo "VERCEL_URL=$url" >> "$GITHUB_OUTPUT"

      - uses: mshick/add-pr-comment@v2
        with:
          message: |
            Your build has completed!

            [Preview deployment](${{ steps.vercel.outputs.VERCEL_URL }})

Enter fullscreen mode Exit fullscreen mode

This workflow is a basic workflow which will be executed whenever a pull request is created or synchronized (receives a new commit). The steps executed are:

  1. Checkout the PR content into the working directory.
  2. Get the branch name.
  3. Create a unique hash for the branch name. This is important because Vercel allow meta tags into builds, this will help us to identify later when we have to remove all preview deployments from a certain branch.
  4. Install Vercel CLI.
  5. Check the cache for npm modules (faster builds)
  6. Install dependencies if needed
  7. Pull the environment variables defined from Vercel
  8. Build and deploy artifacts. Pay attention to the META_TAG variable. This is important because it will be used a metadata to identify every preview deployment.
  9. Comment the preview URL.

Within this steps, you'll create automatic preview links on every push to your branch.

Step 3 - Setup the remove_deploy_preview.yml workflow and script

This workflow will be mandatory in the case you want to delete all the previews builds that the project has generated.

Bash script to remove the builds from Vercel

In your project root folder, create the scripts/delete-deployment-preview.sh file.

#!/bin/bash
# Set the pipefail option.
set -o pipefail

# Get the Vercel API endpoints.
GET_DEPLOYMENTS_ENDPOINT="https://api.vercel.com/v6/deployments"
DELETE_DEPLOYMENTS_ENDPOINT="https://api.vercel.com/v13/deployments"

# Create a list of deployments.
deployments=$(curl -s -X GET "$GET_DEPLOYMENTS_ENDPOINT/?projectId=$VERCEL_PROJECT_ID&teamId=$VERCEL_ORG_ID" -H "Authorization: Bearer $VERCEL_TOKEN ")

# Filter the deployments list by meta.base_hash === meta tag.
filtered_deployments=$(echo $deployments | jq --arg META_TAG "$META_TAG" '[.deployments[] | select(.meta.base_hash | type == "string" and contains($META_TAG)) | .uid] | join(",")')
filtered_deployments="${filtered_deployments//\"/}" # Remove double quotes

# Clears the values from filtered_deployments
IFS=',' read -ra values <<<"$filtered_deployments"

echo "META_TAG ${META_TAG}"
echo "Filtered deployments ${filtered_deployments}"

# Iterate over the filtered deployments list.
for uid in "${values[@]}"; do
    echo "Deleting ${uid}"

    delete_url=${DELETE_DEPLOYMENTS_ENDPOINT}/${uid}?teamId=${VERCEL_ORG_ID}
    echo $delete_url

    # Make DELETE a request to the /v13/deployments/{id} endpoint.
    curl -X DELETE $delete_url -H "Authorization: Bearer $VERCEL_TOKEN"

    echo "Deleted!"
done

Enter fullscreen mode Exit fullscreen mode

Don't forget to run chmod:
chmod a+x ./scripts/delete-deployment-preview.sh

Deployment workflow

Create the remove_deploy_preview.yml into the .github/workflows folder and paste the following content:


name: Remove deploy preview

permissions:
  contents: read
  statuses: write
  pull-requests: write

env:
  VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
  VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
  VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

on:
  pull_request:
    types:
      - closed

jobs:
  delete-deployments:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Extract branch name
        shell: bash
        run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
        id: extract_branch

      - name: Hash branch name
        uses: pplanel/hash-calculator-action@v1.3.1
        id: hash_branch
        with:
          input: ${{ steps.extract_branch.outputs.branch }}
          method: MD5

      - name: Call the delete-deployment-preview.sh script
        env:
          META_TAG: ${{ steps.hash_branch.outputs.digest }}
        run: |
          bash ./scripts/delete-deployment-preview.sh

Enter fullscreen mode Exit fullscreen mode

This workflow will run when a existent PR is closed or merged. So be aware that this job will possibly run without deleting any previews.

The workflow steps are the following:

  1. Checkout the PR contents into the working space.
  2. Get pull request branch name.
  3. Create a hash for it.
  4. Execute the bash script that we've created earlier with the META_TAG environment variable.

The script will make a GET request to the https://api.vercel.com/v6/deployments endpoint and will fetch all the preview deployments that you have. Then, we use jq to create a list of uid that matches with the meta.base_hash that we passed earlier when we created a new preview.

If there's any available deployment, we delete it. If none, it's all good, no need to worry (unless you don't have any at all).

Delete deployment preview

That's all folks, I hope you can sort this out. Leave a comment if you liked and follow me (all about my complains) on Twitter.

dev_reis on Twitter
dev_reis on Instagram

Top comments (0)