name: Deploy MineGeo to Dokploy on: push: branches: - master jobs: deploy: # This label must map to a Docker job image in the Gitea act_runner config. runs-on: ubuntu-latest steps: - name: Check out the pushed commit uses: actions/checkout@v4 - name: Upload source and wait for Dokploy build shell: bash env: DOKPLOY_API_KEY: ${{ secrets.DOKPLOY_API_KEY }} DOKPLOY_APPLICATION_ID: ${{ secrets.DOKPLOY_APPLICATION_ID }} run: | set -eu umask 077 # Pin the deployment origin; runner variables and .env cannot override it. readonly DOKPLOY_URL='https://dokploy.minegeo.site' : "${DOKPLOY_API_KEY:?Add the DOKPLOY_API_KEY Actions secret.}" : "${DOKPLOY_APPLICATION_ID:?Add the DOKPLOY_APPLICATION_ID Actions secret.}" temp_root="${RUNNER_TEMP:-/tmp}" mkdir -p "$temp_root" auth_file="$(mktemp "$temp_root/minegeo-dokploy-auth.XXXXXX")" archive_file="$(mktemp "$temp_root/minegeo-dokploy-source.XXXXXX")" response_file="$(mktemp "$temp_root/minegeo-dokploy-response.XXXXXX")" deployment_file="$(mktemp "$temp_root/minegeo-dokploy-status.XXXXXX")" metrics_file="$(mktemp "$temp_root/minegeo-dokploy-metrics.XXXXXX")" error_file="$(mktemp "$temp_root/minegeo-dokploy-errors.XXXXXX")" headers_file="$(mktemp "$temp_root/minegeo-dokploy-headers.XXXXXX")" cleanup() { rm -f "$auth_file" "$archive_file" "$response_file" "$deployment_file" "$metrics_file" "$error_file" "$headers_file" } trap cleanup EXIT # Keep the API key out of curl's command-line arguments and workflow logs. printf 'x-api-key: %s\n' "$DOKPLOY_API_KEY" > "$auth_file" unset DOKPLOY_API_KEY echo "[Dokploy] Workflow revision: $(git rev-parse HEAD)" curl --version | head -n 2 node scripts/dokploy-diagnostics.mjs environment "$DOKPLOY_URL" dokploy_request() { label="$1" body_file="$2" shift 2 : > "$body_file" : > "$headers_file" : > "$metrics_file" : > "$error_file" echo "[Dokploy] Starting $label at $(date -u '+%Y-%m-%dT%H:%M:%SZ')" >&2 if curl --silent --show-error \ --header "@$auth_file" \ --dump-header "$headers_file" \ --output "$body_file" \ --write-out '%{http_code}\nremote_ip=%{remote_ip} remote_port=%{remote_port} local_ip=%{local_ip}\ndns=%{time_namelookup}s connect=%{time_connect}s tls=%{time_appconnect}s first_byte=%{time_starttransfer}s total=%{time_total}s\nssl_verify_result=%{ssl_verify_result} redirects=%{num_redirects} uploaded=%{size_upload}B downloaded=%{size_download}B\n' \ "$@" > "$metrics_file" 2> "$error_file"; then curl_exit=0 else curl_exit=$? fi node scripts/dokploy-diagnostics.mjs request "$label" "$curl_exit" \ "$metrics_file" "$error_file" "$headers_file" "$body_file" "$auth_file" >&2 http_code="$(head -n 1 "$metrics_file")" if [ "$curl_exit" -ne 0 ]; then echo "[Dokploy] $label failed: curl exit $curl_exit, HTTP ${http_code:-000}." >&2 return 1 fi case "$http_code" in 2??) ;; *) echo "[Dokploy] $label failed: HTTP ${http_code:-000}." >&2; return 1 ;; esac } # Only committed files from this revision are uploaded. This excludes # .git metadata, local .env files, caches, and untracked workspace data. git archive --format=zip --output="$archive_file" HEAD echo "[Dokploy] Source archive size: $(wc -c < "$archive_file") bytes" dokploy_request "API preflight GET /api/deployment.all" "$deployment_file" --get \ --data-urlencode "applicationId=$DOKPLOY_APPLICATION_ID" \ --connect-timeout 10 --max-time 30 \ "$DOKPLOY_URL/api/deployment.all" previous_ids="$(node scripts/dokploy-deployment-state.mjs snapshot "$deployment_file")" || { node scripts/dokploy-diagnostics.mjs request "API preflight response parsing" parse-error \ "$metrics_file" "$error_file" "$headers_file" "$deployment_file" "$auth_file" >&2 echo "Dokploy returned an unexpected deployment list; source was not uploaded." >&2 exit 1 } dokploy_request "Source upload POST /api/application.dropDeployment" "$response_file" \ --form-string "applicationId=$DOKPLOY_APPLICATION_ID" \ --form "zip=@$archive_file;type=application/zip" \ --connect-timeout 15 --max-time 1800 \ "$DOKPLOY_URL/api/application.dropDeployment" echo "Dokploy accepted the source archive; waiting for the VPS build and deployment." attempt=0 poll_failures=0 while [ "$attempt" -lt 360 ]; do attempt=$((attempt + 1)) if dokploy_request "Deployment status GET /api/deployment.all (attempt $attempt/360)" "$deployment_file" --get \ --data-urlencode "applicationId=$DOKPLOY_APPLICATION_ID" \ --connect-timeout 10 --max-time 30 \ "$DOKPLOY_URL/api/deployment.all"; then poll_failures=0 else poll_failures=$((poll_failures + 1)) if node scripts/dokploy-deployment-state.mjs retry "$curl_exit" "$http_code" "$poll_failures"; then echo "Transient status lookup failure ($poll_failures/6); the accepted build may still be running. Retrying only the GET." sleep 10 continue fi exit 1 fi status="$(DOKPLOY_PREVIOUS_DEPLOYMENT_IDS="$previous_ids" node scripts/dokploy-deployment-state.mjs status "$deployment_file")" || { node scripts/dokploy-diagnostics.mjs request "Deployment status response parsing" parse-error \ "$metrics_file" "$error_file" "$headers_file" "$deployment_file" "$auth_file" >&2 echo "Dokploy returned an unexpected deployment status; inspect the response diagnostics above." >&2 exit 1 } case "$status" in done) echo "Dokploy build and deployment completed successfully." exit 0 ;; error|cancelled|canceled) echo "Dokploy reported a failed deployment; inspect that deployment's logs in Dokploy." >&2 exit 1 ;; *) if [ $((attempt % 3)) -eq 0 ]; then echo "Dokploy build status: $status." fi ;; esac sleep 10 done echo "Timed out waiting for Dokploy to finish; inspect the deployment in Dokploy." >&2 exit 1