Files
ladill-qr-plus/deploy/deploy.sh
T
isaaccladandCursor cd6571f199
Deploy Ladill QR Plus / deploy (push) Failing after 1s
Extract Ladill QR Plus as standalone app at qr.ladill.com.
Utility QR types only (URL, WiFi, link list, business, app download) with
SSO, Billing API integration, public /q resolver, and qr-plus:import for
platform migration. vCard and commerce types stay on the platform.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 21:31:24 +00:00

214 lines
6.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Fast on-host release deploy (same model as climpme/web/deploy/deploy.sh).
set -Eeuo pipefail
APP_ROOT="${LADILL_APP_ROOT:-/var/www/ladill-qr-plus}"
RELEASES_DIR="$APP_ROOT/releases"
SHARED_DIR="$APP_ROOT/shared"
CURRENT_LINK="$APP_ROOT/current"
RELEASE_ARCHIVE="${LADILL_RELEASE_ARCHIVE:-/tmp/ladill-release.tgz}"
KEEP_RELEASES="${LADILL_KEEP_RELEASES:-5}"
STAMP="$(date +%Y%m%d%H%M%S)"
NEW_RELEASE="$RELEASES_DIR/$STAMP"
log() {
printf '[%s] %s\n' "$(date '+%F %T')" "$*"
}
bootstrap_shared_env() {
local candidate=""
if [ -f "$SHARED_DIR/.env" ]; then
return 0
fi
for candidate in "$CURRENT_LINK/.env" "$APP_ROOT/.env"; do
if [ -f "$candidate" ]; then
cp -fL "$candidate" "$SHARED_DIR/.env"
log "Bootstrapped shared .env from $candidate"
return 0
fi
done
return 1
}
ensure_writable_paths() {
local paths=("$@")
[ "${#paths[@]}" -gt 0 ] || return 0
chmod -R ug+rwX "${paths[@]}" 2>/dev/null || true
if command -v find >/dev/null 2>&1; then
find "${paths[@]}" -type d -exec chmod ug+rwx {} + 2>/dev/null || true
find "${paths[@]}" -type d -exec chmod g+s {} + 2>/dev/null || true
fi
}
run_artisan() {
local command="$1"
if [ -f "$NEW_RELEASE/artisan" ]; then
(cd "$NEW_RELEASE" && php artisan ${command})
fi
}
uses_sqlite() {
[ -f "$SHARED_DIR/.env" ] && grep -Eq '^DB_CONNECTION=sqlite([[:space:]]*)$' "$SHARED_DIR/.env"
}
sqlite_database_setting() {
[ -f "$SHARED_DIR/.env" ] || return 1
grep -E '^DB_DATABASE=' "$SHARED_DIR/.env" | tail -n 1 | cut -d= -f2- | sed -e 's/^"//' -e 's/"$//' -e "s/^'//" -e "s/'$//"
}
prepare_sqlite_database() {
local configured_path=""
local db_name=""
local shared_sqlite_path=""
local current_sqlite_path=""
local release_sqlite_path=""
configured_path="$(sqlite_database_setting || true)"
[ -n "$configured_path" ] || configured_path="database/database.sqlite"
if [[ "$configured_path" = /* ]]; then
shared_sqlite_path="$configured_path"
mkdir -p "$(dirname "$shared_sqlite_path")"
else
db_name="$(basename "$configured_path")"
shared_sqlite_path="$SHARED_DIR/database/$db_name"
current_sqlite_path="$CURRENT_LINK/$configured_path"
release_sqlite_path="$NEW_RELEASE/$configured_path"
mkdir -p "$SHARED_DIR/database" "$(dirname "$release_sqlite_path")"
if [ ! -f "$shared_sqlite_path" ]; then
if [ -f "$current_sqlite_path" ]; then
cp -fL "$current_sqlite_path" "$shared_sqlite_path"
log "Bootstrapped shared sqlite database from $current_sqlite_path"
elif [ -f "$APP_ROOT/$configured_path" ]; then
cp -fL "$APP_ROOT/$configured_path" "$shared_sqlite_path"
log "Bootstrapped shared sqlite database from $APP_ROOT/$configured_path"
else
touch "$shared_sqlite_path"
log "Created shared sqlite database at $shared_sqlite_path"
fi
fi
rm -f "$release_sqlite_path"
ln -sfn "$shared_sqlite_path" "$release_sqlite_path"
ensure_writable_paths "$SHARED_DIR/database"
return 0
fi
if [ ! -f "$shared_sqlite_path" ]; then
touch "$shared_sqlite_path"
log "Created shared sqlite database at $shared_sqlite_path"
fi
ensure_writable_paths "$(dirname "$shared_sqlite_path")"
}
log "Preparing release $STAMP"
[ -f "$RELEASE_ARCHIVE" ] || { echo "Release archive not found: $RELEASE_ARCHIVE" >&2; exit 1; }
mkdir -p "$RELEASES_DIR" "$SHARED_DIR" "$NEW_RELEASE"
tar -xzf "$RELEASE_ARCHIVE" -C "$NEW_RELEASE"
chmod -R u+rwX "$NEW_RELEASE" 2>/dev/null || true
log "Linking shared paths"
mkdir -p "$SHARED_DIR/storage/"{app/public,app/private,framework/{cache/data,sessions,testing,views},logs}
mkdir -p "$SHARED_DIR/bootstrap-cache"
ensure_writable_paths "$SHARED_DIR/storage" "$SHARED_DIR/bootstrap-cache"
if bootstrap_shared_env; then
ln -sfn "$SHARED_DIR/.env" "$NEW_RELEASE/.env"
else
echo "Missing deployment environment file. Expected $SHARED_DIR/.env or an existing $CURRENT_LINK/.env / $APP_ROOT/.env to bootstrap from." >&2
exit 1
fi
rm -rf "$NEW_RELEASE/storage"
ln -sfn "$SHARED_DIR/storage" "$NEW_RELEASE/storage"
mkdir -p "$NEW_RELEASE/bootstrap"
rm -rf "$NEW_RELEASE/bootstrap/cache"
ln -sfn "$SHARED_DIR/bootstrap-cache" "$NEW_RELEASE/bootstrap/cache"
ensure_writable_paths "$NEW_RELEASE/storage" "$NEW_RELEASE/bootstrap/cache"
if uses_sqlite; then
log "Preparing shared sqlite database"
prepare_sqlite_database
if id -u www-data >/dev/null 2>&1; then
chgrp www-data "$SHARED_DIR/database" 2>/dev/null || true
find "$SHARED_DIR/database" -type f -exec chgrp www-data {} + 2>/dev/null || true
find "$SHARED_DIR/database" -type d -exec chgrp www-data {} + 2>/dev/null || true
fi
fi
log "Installing PHP dependencies"
if [ -f "$NEW_RELEASE/composer.json" ]; then
if [ "$(id -u)" -eq 0 ]; then
export COMPOSER_ALLOW_SUPERUSER=1
fi
export COMPOSER_HOME="${COMPOSER_HOME:-/home/deploy/.composer}"
(
cd "$NEW_RELEASE"
composer install \
--no-dev \
--prefer-dist \
--no-interaction \
--no-progress \
--optimize-autoloader \
--classmap-authoritative
)
fi
log "Running migrations"
if ! run_artisan "migrate --force"; then
log "Migration failed — clearing shared bootstrap cache"
run_artisan "optimize:clear" || true
exit 1
fi
log "Switching current release"
ln -sfnT "$NEW_RELEASE" "$CURRENT_LINK"
log "Optimizing Laravel"
if [ -L "$CURRENT_LINK" ] && [ -f "$CURRENT_LINK/artisan" ]; then
(
cd "$CURRENT_LINK"
php artisan storage:link || true
php artisan optimize:clear || true
php artisan config:cache || true
php artisan route:cache || true
php artisan view:cache || true
)
fi
log "Reloading services"
if command -v systemctl >/dev/null 2>&1; then
systemctl reload php8.4-fpm 2>/dev/null || sudo -n systemctl reload php8.4-fpm
systemctl reload nginx 2>/dev/null || sudo -n systemctl reload nginx
fi
log "Restarting queues"
if [ -L "$CURRENT_LINK" ] && [ -f "$CURRENT_LINK/artisan" ]; then
(cd "$CURRENT_LINK" && php artisan queue:restart) || true
fi
if command -v supervisorctl >/dev/null 2>&1; then
supervisorctl restart ladill-qr-plus-worker:* 2>/dev/null || true
fi
log "Cleaning old releases"
mapfile -t OLD_RELEASES < <(ls -1dt "$RELEASES_DIR"/* 2>/dev/null | tail -n "+$((KEEP_RELEASES + 1))" || true)
if [ "${#OLD_RELEASES[@]}" -gt 0 ]; then
chmod -R u+rwX "${OLD_RELEASES[@]}" 2>/dev/null || true
rm -rf "${OLD_RELEASES[@]}" 2>/dev/null || true
fi
log "Deploy completed: $STAMP"