#!/usr/bin/env bash # Trigger a Dokploy Compose deploy and wait until it finishes. # Required env: # DOKPLOY_URL e.g. https://panel.example.com (panel origin, no /api) # DOKPLOY_API_KEY x-api-key value # DOKPLOY_COMPOSE_ID target compose id # Optional env: # DEPLOY_TITLE deployment title (default: Gitea deploy) # DEPLOY_TIMEOUT_SEC total wait seconds (default: 900) # DEPLOY_POLL_SEC poll interval (default: 10) set -euo pipefail : "${DOKPLOY_URL:?DOKPLOY_URL is required}" : "${DOKPLOY_API_KEY:?DOKPLOY_API_KEY is required}" : "${DOKPLOY_COMPOSE_ID:?DOKPLOY_COMPOSE_ID is required}" # Panel origin only: strip trailing slash and accidental OpenAPI /api suffix. DOKPLOY_URL="${DOKPLOY_URL%/}" DOKPLOY_URL="${DOKPLOY_URL%/api}" DOKPLOY_URL="${DOKPLOY_URL%/}" DEPLOY_TITLE="${DEPLOY_TITLE:-Gitea deploy}" DEPLOY_TIMEOUT_SEC="${DEPLOY_TIMEOUT_SEC:-900}" DEPLOY_POLL_SEC="${DEPLOY_POLL_SEC:-10}" echo "Dokploy API base: ${DOKPLOY_URL}/api" api() { local method="$1" local path="$2" shift 2 local url="${DOKPLOY_URL}/api${path}" local response http_code body # Body then HTTP status on the last line (no -f so 4xx/5xx still return a body). response="$( curl -sS -w $'\n%{http_code}' -X "$method" \ -H "accept: application/json" \ -H "content-type: application/json" \ -H "x-api-key: ${DOKPLOY_API_KEY}" \ "$url" \ "$@" )" || { echo "Dokploy API request failed (curl transport error)." >&2 echo " method: ${method}" >&2 echo " url: ${url}" >&2 exit 1 } http_code="$(printf '%s' "$response" | tail -n1)" body="$(printf '%s' "$response" | sed '$d')" if [[ ! "$http_code" =~ ^2[0-9][0-9]$ ]]; then echo "Dokploy API error." >&2 echo " method: ${method}" >&2 echo " url: ${url}" >&2 echo " status: ${http_code}" >&2 echo " body:" >&2 printf '%s\n' "$body" >&2 exit 1 fi printf '%s' "$body" } echo "Triggering Dokploy compose.deploy for ${DOKPLOY_COMPOSE_ID}..." api POST "/compose.deploy" \ -d "$(jq -n \ --arg composeId "$DOKPLOY_COMPOSE_ID" \ --arg title "$DEPLOY_TITLE" \ '{composeId: $composeId, title: $title}')" >/dev/null echo "Waiting for deployment to finish (timeout ${DEPLOY_TIMEOUT_SEC}s)..." deadline=$((SECONDS + DEPLOY_TIMEOUT_SEC)) last_status="" while (( SECONDS < deadline )); do payload="$(api GET "/deployment.allByCompose?composeId=${DOKPLOY_COMPOSE_ID}")" latest="$(echo "$payload" | jq -c 'if type=="array" then .[0] else . end')" if [[ -z "$latest" || "$latest" == "null" ]]; then echo "No deployment records yet; retrying..." sleep "$DEPLOY_POLL_SEC" continue fi status="$(echo "$latest" | jq -r '.status // .deploymentStatus // empty')" created_at="$(echo "$latest" | jq -r '.createdAt // .created_at // empty')" title="$(echo "$latest" | jq -r '.title // .titleLog // empty')" if [[ "$status" != "$last_status" ]]; then echo "Deployment status=${status:-unknown} title=${title:-n/a} createdAt=${created_at:-n/a}" last_status="$status" fi case "${status,,}" in done|success|successful|finished) echo "Dokploy deployment succeeded." exit 0 ;; error|failed|failure) echo "Dokploy deployment failed." >&2 echo "$latest" | jq . >&2 || true exit 1 ;; esac sleep "$DEPLOY_POLL_SEC" done echo "Timed out waiting for Dokploy deployment after ${DEPLOY_TIMEOUT_SEC}s." >&2 api GET "/deployment.allByCompose?composeId=${DOKPLOY_COMPOSE_ID}" | jq . >&2 || true exit 1