#!/bin/bash set -e # Usage: deploy.sh [dockerfile|nixpacks|static] # Handles: Gitea repo creation, git push, Coolify app creation, deployment # Returns: production URL PROJECT_NAME="${1:?Usage: deploy.sh [dockerfile|nixpacks|static]}" BUILD_TYPE="${2:-nixpacks}" GITEA_URL="${GITEA_URL:?GITEA_URL not set}" GITEA_TOKEN="${GITEA_TOKEN:?GITEA_TOKEN not set}" COOLIFY_BASE_URL="${COOLIFY_BASE_URL:?COOLIFY_BASE_URL not set}" COOLIFY_ACCESS_TOKEN="${COOLIFY_ACCESS_TOKEN:?COOLIFY_ACCESS_TOKEN not set}" GITEA_API="${GITEA_URL}/api/v1" COOLIFY_API="${COOLIFY_BASE_URL}/api/v1" GITEA_USER="pankaj" echo "=== TenX Deploy: ${PROJECT_NAME} (build: ${BUILD_TYPE}) ===" # ── Step 1: Git init + commit ──────────────────────────────────────── if [ ! -d .git ]; then git init git checkout -b main 2>/dev/null || true fi git add -A git diff --cached --quiet 2>/dev/null || git commit -m "deploy: ${PROJECT_NAME}" --allow-empty # ── Step 2: Create Gitea repo (ignore if exists) ───────────────────── echo "[deploy] Creating Gitea repo..." REPO_RESPONSE=$(curl -sk -w "\n%{http_code}" -X POST "${GITEA_API}/user/repos" \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/json" \ -d "{\"name\":\"${PROJECT_NAME}\",\"private\":false,\"auto_init\":false}") HTTP_CODE=$(echo "${REPO_RESPONSE}" | tail -1) if [ "${HTTP_CODE}" = "201" ]; then echo "[deploy] Gitea repo created: ${GITEA_URL}/${GITEA_USER}/${PROJECT_NAME}" elif [ "${HTTP_CODE}" = "409" ]; then echo "[deploy] Gitea repo already exists" else echo "[deploy] Gitea repo creation returned ${HTTP_CODE} (continuing anyway)" fi # ── Step 3: Push to Gitea ──────────────────────────────────────────── GITEA_HOST=$(echo "${GITEA_URL}" | sed 's|https://||;s|http://||') REMOTE_URL="https://${GITEA_USER}:${GITEA_TOKEN}@${GITEA_HOST}/${GITEA_USER}/${PROJECT_NAME}.git" git remote remove origin 2>/dev/null || true git remote add origin "${REMOTE_URL}" GIT_SSL_NO_VERIFY=true git push -u origin main --force echo "[deploy] Code pushed to Gitea" # ── Step 4: Get Coolify server UUID ────────────────────────────────── echo "[deploy] Getting Coolify server..." SERVER_UUID=$(curl -sk -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ "${COOLIFY_API}/servers" | python3 -c "import sys,json; servers=json.load(sys.stdin); print(servers[0]['uuid'])" 2>/dev/null) if [ -z "${SERVER_UUID}" ]; then echo "[deploy] ERROR: Could not get Coolify server UUID" exit 1 fi echo "[deploy] Server: ${SERVER_UUID}" # ── Step 5: Get or create Coolify project ──────────────────────────── echo "[deploy] Getting Coolify project..." PROJECT_UUID=$(curl -sk -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ "${COOLIFY_API}/projects" | python3 -c " import sys,json projects=json.load(sys.stdin) for p in projects: if p.get('name','').lower() == 'tenx': print(p['uuid']) sys.exit(0) print('') " 2>/dev/null) if [ -z "${PROJECT_UUID}" ]; then echo "[deploy] Creating TenX project on Coolify..." PROJECT_UUID=$(curl -sk -X POST -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ "${COOLIFY_API}/projects" \ -d '{"name":"TenX","description":"TenX auto-deployed apps"}' | python3 -c "import sys,json; print(json.load(sys.stdin).get('uuid',''))" 2>/dev/null) fi echo "[deploy] Project: ${PROJECT_UUID}" # ── Step 6: Get first environment UUID ─────────────────────────────── ENV_UUID=$(curl -sk -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ "${COOLIFY_API}/projects/${PROJECT_UUID}" | python3 -c " import sys,json data=json.load(sys.stdin) envs=data.get('environments',[]) if envs: print(envs[0].get('id','')) else: print('') " 2>/dev/null) if [ -z "${ENV_UUID}" ]; then echo "[deploy] ERROR: No environment found in project" exit 1 fi echo "[deploy] Environment: ${ENV_UUID}" # ── Step 7: Create Coolify application ─────────────────────────────── echo "[deploy] Creating Coolify application..." REPO_FULL_URL="${GITEA_URL}/${GITEA_USER}/${PROJECT_NAME}.git" APP_RESPONSE=$(curl -sk -X POST -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ "${COOLIFY_API}/applications/public" \ -d "{ \"project_uuid\": \"${PROJECT_UUID}\", \"environment_name\": \"production\", \"server_uuid\": \"${SERVER_UUID}\", \"type\": \"public\", \"name\": \"${PROJECT_NAME}\", \"git_repository\": \"${REPO_FULL_URL}\", \"git_branch\": \"main\", \"build_pack\": \"${BUILD_TYPE}\", \"ports_exposes\": \"3000\", \"instant_deploy\": true }") APP_UUID=$(echo "${APP_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('uuid',''))" 2>/dev/null) if [ -z "${APP_UUID}" ]; then echo "[deploy] App creation response: ${APP_RESPONSE}" # Try to find existing app APP_UUID=$(curl -sk -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ "${COOLIFY_API}/applications" | python3 -c " import sys,json apps=json.load(sys.stdin) for a in apps: if a.get('name','') == '${PROJECT_NAME}': print(a['uuid']) sys.exit(0) print('') " 2>/dev/null) if [ -z "${APP_UUID}" ]; then echo "[deploy] ERROR: Could not create or find app" exit 1 fi echo "[deploy] Found existing app: ${APP_UUID}, triggering redeploy..." fi echo "[deploy] App UUID: ${APP_UUID}" # ── Step 7b: Fix git_repository URL (Coolify API strips base URL) ───── curl -sk -X PATCH -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ "${COOLIFY_API}/applications/${APP_UUID}" \ -d "{\"git_repository\": \"${REPO_FULL_URL}\"}" > /dev/null echo "[deploy] Git repository URL set: ${REPO_FULL_URL}" # ── Step 8: Trigger deployment ──────────────────────────────────────── echo "[deploy] Triggering deployment..." DEPLOY_RESPONSE=$(curl -sk -X POST -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d "{\"uuid\":\"${APP_UUID}\"}" \ "${COOLIFY_API}/deploy") DEPLOYMENT_UUID=$(echo "${DEPLOY_RESPONSE}" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('deployments',[{}])[0].get('deployment_uuid',''))" 2>/dev/null) echo "[deploy] Deployment UUID: ${DEPLOYMENT_UUID}" # ── Step 8b: Wait for deployment ───────────────────────────────────── echo "[deploy] Waiting for deployment to complete..." for i in $(seq 1 30); do sleep 15 if [ -n "${DEPLOYMENT_UUID}" ]; then DEP_STATUS=$(curl -sk -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ "${COOLIFY_API}/deployments/${DEPLOYMENT_UUID}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status','unknown'))" 2>/dev/null) else DEP_STATUS="unknown" fi APP_STATUS=$(curl -sk -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ "${COOLIFY_API}/applications/${APP_UUID}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status','unknown'))" 2>/dev/null) echo "[deploy] Deploy: ${DEP_STATUS} | App: ${APP_STATUS} (attempt ${i}/30)" if [ "${DEP_STATUS}" = "finished" ] || echo "${APP_STATUS}" | grep -q "running"; then echo "[deploy] Deployment successful!" break fi if [ "${DEP_STATUS}" = "failed" ]; then echo "[deploy] Deployment FAILED. Check Coolify dashboard for logs." exit 1 fi done # ── Step 9: Get the URL ────────────────────────────────────────────── FQDN=$(curl -sk -H "Authorization: Bearer ${COOLIFY_ACCESS_TOKEN}" \ "${COOLIFY_API}/applications/${APP_UUID}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('fqdn',''))" 2>/dev/null) if [ -z "${FQDN}" ]; then echo "[deploy] WARNING: No FQDN set — app may be accessible via Coolify dashboard only" echo "[deploy] App UUID: ${APP_UUID}" else echo "" echo "=== DEPLOYED ===" echo "URL: ${FQDN}" echo "Gitea: ${GITEA_URL}/${GITEA_USER}/${PROJECT_NAME}" echo "================" fi