Skip to content

DEPLOY — Deploy Branch #96

DEPLOY — Deploy Branch

DEPLOY — Deploy Branch #96

Workflow file for this run

name: DEPLOY — Deploy Branch
on:
workflow_call:
inputs:
environment:
description: "Target — Environment (used for Environment-scoped vars/secrets)"
required: true
type: string
component:
description: "Target — Component to deploy (triggers the matching webhook list)"
required: true
type: string
confirm:
description: "Confirm — Choose the exact deploy action (mobile-friendly)"
required: true
type: string
workflow_dispatch:
inputs:
environment:
description: "Target — Environment (used for Environment-scoped vars/secrets)"
required: true
type: choice
default: production
options:
- production
- preview
component:
description: "Target — Component to deploy (triggers the matching webhook list)"
required: true
type: choice
options:
- ui
- server
- website
- docs
confirm:
description: "Confirm — Choose the exact deploy action (mobile-friendly)"
required: true
type: choice
options:
- deploy production ui
- deploy production server
- deploy production website
- deploy production docs
- deploy preview ui
- deploy preview server
- deploy preview website
- deploy preview docs
permissions:
contents: read
concurrency:
group: deploy-${{ format('{0}/{1}', inputs.environment, inputs.component) }}
cancel-in-progress: false
jobs:
release_actor_guard:
name: Release actor guard
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Authorize release actor
uses: ./.github/actions/release-actor-guard
with:
team_slug: release-admins
trusted_actors: happier-release-bot[bot]
app_id: ${{ secrets.RELEASE_BOT_APP_ID }}
private_key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }}
deploy:
needs: [release_actor_guard]
runs-on: ubuntu-latest
if: ${{ needs.release_actor_guard.result == 'success' }}
environment: ${{ inputs.environment }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22.x
- name: Enforce trusted refs for manual dispatch
run: |
set -euo pipefail
if [ "${GITHUB_EVENT_NAME}" != "workflow_dispatch" ]; then
exit 0
fi
case "${GITHUB_REF_NAME}" in
dev|preview|main) ;;
*)
echo "Refusing workflow_dispatch from untrusted ref '${GITHUB_REF_NAME}'. Use dev, preview, or main." >&2
exit 1
;;
esac
- name: Resolve target (env + component)
id: target
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_ENV: ${{ inputs.environment }}
INPUT_COMPONENT: ${{ inputs.component }}
INPUT_CONFIRM: ${{ inputs.confirm }}
run: |
set -euo pipefail
# Called workflows inherit `github.event_name` from the caller (e.g. `push`), so we must accept it here.
if [ "$EVENT_NAME" != "workflow_dispatch" ] && [ "$EVENT_NAME" != "workflow_call" ] && [ "$EVENT_NAME" != "push" ]; then
echo "Unsupported event for deploy workflow: $EVENT_NAME" >&2
exit 1
fi
env_name="$INPUT_ENV"
component="$INPUT_COMPONENT"
expected="deploy ${env_name} ${component}"
if [ "$INPUT_CONFIRM" != "$expected" ]; then
echo "Confirmation mismatch." >&2
echo "Expected: $expected" >&2
echo "Got: $INPUT_CONFIRM" >&2
exit 1
fi
case "$env_name" in
production|preview) ;;
*)
echo "Unsupported environment: $env_name" >&2
exit 1
;;
esac
case "$component" in
ui|server|website|docs) ;;
*)
echo "Unsupported component: $component" >&2
exit 1
;;
esac
echo "environment=$env_name" >> "$GITHUB_OUTPUT"
echo "component=$component" >> "$GITHUB_OUTPUT"
{
echo "## Deploy trigger"
echo ""
echo "- ref: \`${GITHUB_REF_NAME}\`"
echo "- environment: \`$env_name\`"
echo "- component: \`$component\`"
} >> "$GITHUB_STEP_SUMMARY"
- name: Trigger deploy webhook(s)
env:
GH_TOKEN: ${{ github.token }}
CF_WEBHOOK_DEPLOY_CLIENT_ID: ${{ secrets.CF_WEBHOOK_DEPLOY_CLIENT_ID }}
CF_WEBHOOK_DEPLOY_CLIENT_SECRET: ${{ secrets.CF_WEBHOOK_DEPLOY_CLIENT_SECRET }}
DEPLOY_WEBHOOK_URL: ${{ vars.DEPLOY_WEBHOOK_URL != '' && vars.DEPLOY_WEBHOOK_URL || secrets.DEPLOY_WEBHOOK_URL }}
HAPPIER_UI_DEPLOY_WEBHOOKS: ${{ vars.HAPPIER_UI_DEPLOY_WEBHOOKS != '' && vars.HAPPIER_UI_DEPLOY_WEBHOOKS || secrets.HAPPIER_UI_DEPLOY_WEBHOOKS }}
HAPPIER_WEBSITE_DEPLOY_WEBHOOKS: ${{ vars.HAPPIER_WEBSITE_DEPLOY_WEBHOOKS != '' && vars.HAPPIER_WEBSITE_DEPLOY_WEBHOOKS || secrets.HAPPIER_WEBSITE_DEPLOY_WEBHOOKS }}
HAPPIER_DOCS_DEPLOY_WEBHOOKS: ${{ vars.HAPPIER_DOCS_DEPLOY_WEBHOOKS != '' && vars.HAPPIER_DOCS_DEPLOY_WEBHOOKS || secrets.HAPPIER_DOCS_DEPLOY_WEBHOOKS }}
HAPPIER_SERVER_API_DEPLOY_WEBHOOKS: ${{ vars.HAPPIER_SERVER_API_DEPLOY_WEBHOOKS != '' && vars.HAPPIER_SERVER_API_DEPLOY_WEBHOOKS || secrets.HAPPIER_SERVER_API_DEPLOY_WEBHOOKS }}
HAPPIER_SERVER_WORKER_DEPLOY_WEBHOOKS: ${{ vars.HAPPIER_SERVER_WORKER_DEPLOY_WEBHOOKS != '' && vars.HAPPIER_SERVER_WORKER_DEPLOY_WEBHOOKS || secrets.HAPPIER_SERVER_WORKER_DEPLOY_WEBHOOKS }}
run: |
set -euo pipefail
node scripts/pipeline/run.mjs deploy \
--deploy-environment "${{ steps.target.outputs.environment }}" \
--component "${{ steps.target.outputs.component }}" \
--repository "${{ github.repository }}" \
--ref-name "deploy/${{ steps.target.outputs.environment }}/${{ steps.target.outputs.component }}"