#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd -P)" LABEL="" PROJECT_ID="" PUBLIC_URLS="" usage() { cat <<'EOF' Usage: scripts/github-workflows/deploy-vercel-app.sh \ --label "Docs app" \ --project-id PROJECT_ID \ --public-urls "https://example.com https://www.example.com" Deploys one Vercel project to production from the current checkout: 1. configures Vercel Authentication to protect preview deployments only 2. runs vercel pull/build/deploy --prod with the project root taken from the Vercel project settings 3. verifies each public production URL responds with HTTP 2xx/3xx 4. appends a deployment summary to GITHUB_STEP_SUMMARY when set Requires VERCEL_TOKEN and VERCEL_ORG_ID in the environment and the vercel CLI on PATH. Run from a production-layout checkout (a main publish commit). EOF } die() { echo "error: $*" >&2 exit 1 } while [ "$#" -gt 0 ]; do case "$1" in --label) [ "$#" -ge 2 ] || die "--label requires a value" LABEL="$2" shift ;; --project-id) [ "$#" -ge 2 ] || die "--project-id requires a value" PROJECT_ID="$2" shift ;; --public-urls) [ "$#" -ge 2 ] || die "--public-urls requires a value" PUBLIC_URLS="$2" shift ;; -h|--help) usage exit 0 ;; *) die "unknown argument: $1" ;; esac shift done [ -n "$LABEL" ] || die "--label is required" [ -n "$PROJECT_ID" ] || die "--project-id is required" [ -n "$PUBLIC_URLS" ] || die "--public-urls is required" [ -n "${VERCEL_TOKEN:-}" ] || die "VERCEL_TOKEN must be set" [ -n "${VERCEL_ORG_ID:-}" ] || die "VERCEL_ORG_ID must be set" command -v vercel >/dev/null 2>&1 || die "vercel CLI is required" command -v curl >/dev/null 2>&1 || die "curl is required" cd "$REPO_ROOT" configure_project_protection() { local response_file local status response_file="$(mktemp)" if ! status="$( curl --silent --show-error --location --max-time 30 \ --request PATCH \ --header "Authorization: Bearer $VERCEL_TOKEN" \ --header "Content-Type: application/json" \ --output "$response_file" \ --write-out "%{http_code}" \ --data '{"ssoProtection":{"deploymentType":"preview"}}' \ "https://api.vercel.com/v9/projects/$PROJECT_ID?teamId=$VERCEL_ORG_ID" )"; then status="000" fi if [ "$status" -lt 200 ] || [ "$status" -ge 300 ]; then echo "$LABEL Vercel Authentication update failed with HTTP $status" >&2 cat "$response_file" >&2 rm -f "$response_file" exit 1 fi rm -f "$response_file" echo "$LABEL Vercel Authentication set to preview deployments only." } check_public_url() { local public_url="$1" local public_status="000" local attempt for attempt in 1 2 3 4 5; do if ! public_status="$(curl --silent --show-error --location --max-time 30 --output /dev/null --write-out "%{http_code}" "$public_url")"; then public_status="000" fi if [ "$public_status" -ge 200 ] && [ "$public_status" -lt 400 ]; then echo "$LABEL public URL check passed: $public_url returned HTTP $public_status" return 0 fi if [ "$attempt" -lt 5 ]; then echo "$LABEL public URL check waiting for $public_url; attempt $attempt returned HTTP $public_status" sleep 5 fi done echo "$LABEL public URL check failed: $public_url returned HTTP $public_status" >&2 return 1 } configure_project_protection rm -rf .vercel export VERCEL_ORG_ID export VERCEL_PROJECT_ID="$PROJECT_ID" echo "Using Vercel project root from project settings for $LABEL." vercel pull --yes --environment=production --token="$VERCEL_TOKEN" vercel build --prod --token="$VERCEL_TOKEN" deployment_output="$(vercel deploy --prebuilt --prod --token="$VERCEL_TOKEN")" echo "$deployment_output" deployment_url="$(printf '%s\n' "$deployment_output" | tail -n 1)" for public_url in $PUBLIC_URLS; do check_public_url "$public_url" done if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then { echo "### $LABEL" echo echo "Public production URLs:" for public_url in $PUBLIC_URLS; do echo "- $public_url" done echo echo "Raw Vercel deployment URL: $deployment_url" echo echo "> Raw Vercel deployment URLs may require Vercel Authentication. Use the public production URLs above for release testing and sharing." echo } >> "$GITHUB_STEP_SUMMARY" fi echo "$LABEL deployed to Vercel production."