From 7a2d5ded200f7fee72ceda1edd01a5a6be5b0a78 Mon Sep 17 00:00:00 2001 From: DevOps Date: Sun, 21 Jun 2026 21:35:15 +0200 Subject: [PATCH] feat: add deploy-now workflow as dispatch-only fallback --- .gitea/workflows/deploy-now.yaml | 209 +++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 .gitea/workflows/deploy-now.yaml diff --git a/.gitea/workflows/deploy-now.yaml b/.gitea/workflows/deploy-now.yaml new file mode 100644 index 0000000..04bc614 --- /dev/null +++ b/.gitea/workflows/deploy-now.yaml @@ -0,0 +1,209 @@ +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 "========================================"