name: deploy-custom on: push: branches: [custom] jobs: deploy: runs-on: linux-amd64 steps: - name: Checkout run: | set -euo pipefail rm -rf $GITHUB_WORKSPACE/repo mkdir -p $GITHUB_WORKSPACE/repo git clone --depth 1 --branch custom gitea@giteassh.buzzbee.dev:BuzzbeeSCD/openchamber.git $GITHUB_WORKSPACE/repo - name: Show revision run: git -C $GITHUB_WORKSPACE/repo rev-parse --short HEAD - name: Stage new build (atomic — live dir untouched) run: | set -euo pipefail SHA=$(git -C $GITHUB_WORKSPACE/repo rev-parse --short HEAD) STAMP=$(date +%Y%m%d-%H%M%S) NEWDIR=/opt/app/deploy/builds/${SHA}-${STAMP} mkdir -p "$NEWDIR" touch "$NEWDIR/.stage-start" tar -C $GITHUB_WORKSPACE/repo --exclude=.git -cf - . | tar -C "$NEWDIR" -xf - echo "$NEWDIR" > $GITHUB_WORKSPACE/newdir echo "staged $NEWDIR" - name: Install dependencies run: | set -euo pipefail NEWDIR=$(cat $GITHUB_WORKSPACE/newdir) cd "$NEWDIR" && bun install --frozen-lockfile - name: Build web run: | set -euo pipefail NEWDIR=$(cat $GITHUB_WORKSPACE/newdir) cd "$NEWDIR" && bun run build:web - name: Verify dist (fresh, non-empty — stale/partial fails here) run: | set -euo pipefail NEWDIR=$(cat $GITHUB_WORKSPACE/newdir) DIST="$NEWDIR/packages/web/dist/index.html" test -f "$DIST" test -s "$DIST" test "$DIST" -nt "$NEWDIR/.stage-start" rm -f "$NEWDIR/.stage-start" echo "dist verified: $(stat -c '%s bytes, %y' "$DIST")" - name: Swap current symlink (single atomic op) run: | set -euo pipefail NEWDIR=$(cat $GITHUB_WORKSPACE/newdir) readlink /opt/app/deploy/current > $GITHUB_WORKSPACE/prevdir ln -sfn "$NEWDIR" /opt/app/deploy/current echo "swapped: $(cat $GITHUB_WORKSPACE/prevdir) -> $NEWDIR" - name: Restart service run: sudo systemctl restart openchamber-custom - name: Health-check (auto-rollback on failure) run: | set -euo pipefail NEWDIR=$(cat $GITHUB_WORKSPACE/newdir) PREVDIR=$(cat $GITHUB_WORKSPACE/prevdir) SHA=$(git -C $GITHUB_WORKSPACE/repo rev-parse HEAD) ok=0 for i in $(seq 1 24); do CODE=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3001/ || true) if [ "$CODE" = "200" ]; then ok=1; break; fi sleep 5 done if [ "$ok" = "1" ]; then echo "healthy on $NEWDIR — pruning old builds" ls -dt /opt/app/deploy/builds/*/ 2>/dev/null | tail -n +3 | xargs -r rm -rf exit 0 fi echo "HEALTH CHECK FAILED — rolling back to $PREVDIR" ln -sfn "$PREVDIR" /opt/app/deploy/current sudo systemctl restart openchamber-custom sleep 15 RCODE=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3001/ || true) MSG="OpenChamber deploy FAILED (health $RCODE after rollback to $PREVDIR)" if [ "$RCODE" = "200" ]; then MSG="$MSG — rollback healthy"; else MSG="$MSG — ROLLBACK ALSO UNHEALTHY, manual intervention needed"; fi /opt/app/.local/bin/openchamber-notify-deploy.sh "$SHA" "$MSG" "deploy-bot" exit 1 - name: Notify on successful deploy run: | SHA=$(git -C $GITHUB_WORKSPACE/repo rev-parse HEAD) MSG=$(git -C $GITHUB_WORKSPACE/repo log -1 --format=%s) AUTHOR=$(git -C $GITHUB_WORKSPACE/repo log -1 --format=%an) /opt/app/.local/bin/openchamber-notify-deploy.sh "$SHA" "$MSG" "$AUTHOR" - name: Notify on failed deploy if: failure() run: | SHA=$(git -C $GITHUB_WORKSPACE/repo rev-parse HEAD || echo unknown) /opt/app/.local/bin/openchamber-notify-deploy.sh "$SHA" "OpenChamber deploy FAILED before health-check (see Actions log)" "deploy-bot"