name: Deploy Now run-name: 🚀 Deploy Now by @${{ gitea.actor }} on: workflow_dispatch: jobs: deploy: name: Deploy Nexus runs-on: ubuntu-latest env: DEPLOY_PATH: /home/projekte_bao/openclaw/data/openclaw/workspace/nexus ENV_TMPFILE: /tmp/nexus-deploy-env ENV_POSTGRES_PASSWORD: ${{ secrets.ENV_POSTGRES_PASSWORD }} ENV_JWT_KEY: ${{ secrets.ENV_JWT_KEY }} ENV_OPENCLAW_TOKEN: ${{ secrets.ENV_OPENCLAW_TOKEN }} steps: - name: Checkout uses: actions/checkout@v4 with: ref: main fetch-depth: 0 fetch-tags: true - name: Resolve Version id: version run: | set -euo pipefail if [ ! -f VERSION ]; then echo "ERROR: VERSION file not found" exit 1 fi VERSION=$(cat VERSION | tr -d '[:space:]') if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then echo "ERROR: Invalid semver in VERSION: $VERSION" exit 1 fi GIT_REF=$(git rev-parse --short HEAD) echo "Deploy version: v${VERSION} git:${GIT_REF}" echo "version=${VERSION}" >> "$GITEA_OUTPUT" - name: Prepare .env (secrets + host .env → temp file) run: | set -euo pipefail HOST_OWNER_PASSWORD="" if [ -f "${DEPLOY_PATH}/.env" ]; then HOST_OWNER_PASSWORD=$(grep '^OWNER_PASSWORD=' "${DEPLOY_PATH}/.env" | cut -d= -f2- || true) fi if [ -z "${HOST_OWNER_PASSWORD}" ]; then echo "ERROR: OWNER_PASSWORD not found in ${DEPLOY_PATH}/.env" exit 1 fi cat > "${ENV_TMPFILE}" < /tmp/nexus-deploy-script.sh << 'DEPLOYSCRIPT' #!/bin/sh set -e trap 'rm -f /tmp/nexus-deploy-env' EXIT cat > /tmp/nexus-deploy-env docker compose --env-file /tmp/nexus-deploy-env down --remove-orphans 2>/dev/null || true docker rm -f nexus-postgres-1 nexus-api-1 nexus-web-1 2>/dev/null || true PG_VOL=$(docker volume ls -q --filter name=nexus-postgres 2>/dev/null | head -1) if [ -n "$PG_VOL" ]; then echo "Checking postgres WAL integrity..." docker run --rm -v "$PG_VOL:/var/lib/postgresql/data" --entrypoint sh postgres:17-alpine -c "pg_resetwal -f /var/lib/postgresql/data && echo WAL reset OK" 2>&1 || echo "pg_resetwal failed (may be benign)" else echo "Postgres volume not found - will be created fresh" fi echo "Deploying all services" docker compose --env-file /tmp/nexus-deploy-env build docker compose --env-file /tmp/nexus-deploy-env up -d --force-recreate echo "Waiting for services to become healthy (up to 180s)..." for i in $(seq 1 36); do STATUS=$(docker compose --env-file /tmp/nexus-deploy-env ps -a 2>/dev/null | tail -n +2) if echo "$STATUS" | grep -q 'unhealthy'; then echo " [$i/36] Unhealthy containers - failing fast" docker compose --env-file /tmp/nexus-deploy-env ps -a docker compose --env-file /tmp/nexus-deploy-env logs --tail=30 exit 1 elif echo "$STATUS" | grep -q 'starting'; then echo " [$i/36] Still starting..." sleep 5 else echo "All containers healthy" docker compose --env-file /tmp/nexus-deploy-env ps -a exit 0 fi done echo "Timeout waiting for services" docker compose --env-file /tmp/nexus-deploy-env ps -a docker compose --env-file /tmp/nexus-deploy-env logs --tail=20 exit 1 DEPLOYSCRIPT docker run --rm \ -v "${DEPLOY_PATH}:/workspace/nexus" \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /tmp/nexus-deploy-script.sh:/deploy.sh:ro \ -w /workspace/nexus \ -i \ docker:cli \ sh /deploy.sh < "${ENV_TMPFILE}" rm -f /tmp/nexus-deploy-script.sh echo "OK deployed" - name: Clean up temp .env if: always() run: | if [ -f "${ENV_TMPFILE}" ]; then shred -u "${ENV_TMPFILE}" 2>/dev/null || rm -f "${ENV_TMPFILE}" echo "OK cleaned" fi - name: Health Check run: | echo "Health check..." RETRY=0 MAX=6 WAIT=1 while [ $RETRY -lt $MAX ]; do RETRY=$((RETRY + 1)) if curl -sf --max-time 10 https://nexus.noveria.net/health; then echo "" echo "OK Health check passed (attempt $RETRY/$MAX)" exit 0 fi echo "Attempt $RETRY/$MAX failed, waiting ${WAIT}s..." sleep $WAIT NEXT=$((WAIT + RETRY)) [ $NEXT -le 15 ] && WAIT=$NEXT || WAIT=15 done echo "ERROR Health check failed after $MAX attempts" exit 1 - name: Smoke Test run: | PASS=0 FAIL=0 BASE="https://nexus.noveria.net" check() { local path="$1" label="$2" expected="${3:-200}" local code code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "${BASE}${path}") printf " %-25s HTTP %s" "${label}:" "${code}" if [ "$code" = "$expected" ]; then echo " OK" PASS=$((PASS + 1)) else echo " FAIL (expected $expected)" FAIL=$((FAIL + 1)) fi } check "/dashboard" "Dashboard" 200 check "/health" "Health API" 200 check "/api/v1/operations/snapshot" "Operations API (auth)" 401 echo "" echo "Results: $PASS passed, $FAIL failed" if [ "$FAIL" -gt 0 ]; then echo "ERROR Smoke test failed" exit 1 fi echo "OK Smoke test passed" - name: Summary if: always() run: | echo "========================================" echo " Deploy Summary" echo "========================================" echo " Version: v${{ steps.version.outputs.version }}" echo " Git ref: main" echo " Service: all" echo " Trigger: Manual" echo " Status: ${{ job.status }}" echo "========================================"