Files
2026-07-13 13:11:15 +08:00

161 lines
4.4 KiB
Bash
Executable File

#!/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."