Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions .deployer/hooks/1-building.sh

This file was deleted.

24 changes: 0 additions & 24 deletions .deployer/hooks/3-finishing.sh

This file was deleted.

File renamed without changes.
48 changes: 48 additions & 0 deletions .deployer/scripts/cron.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env bash

set -euo pipefail

#
# Cron Script - Run scheduled tasks for supported frameworks
# ----
#
# This should be executed by cron on the remote server.
#
# Environment variables provided by runner script:
# DEPLOYER_RELEASE_PATH - Absolute path to the current release directory
# DEPLOYER_SHARED_PATH - Absolute path to the shared/ directory
# DEPLOYER_CURRENT_PATH - Absolute path to the current/ symlink
# DEPLOYER_DOMAIN - Site domain (example.com)
# DEPLOYER_BRANCH - Git branch currently deployed
# DEPLOYER_PHP - Absolute path to the PHP binary (e.g. /usr/bin/php8.4)
#

cd "${DEPLOYER_CURRENT_PATH}"

# ----
# Framework Detection
# ----

framework=""

if [[ -f artisan ]]; then
framework="laravel"
elif [[ -f bin/console ]]; then
framework="symfony"
elif [[ -f spark ]]; then
framework="codeigniter"
fi

# ----
# Scheduled Tasks
# ----

if [[ $framework == "laravel" ]]; then
"${DEPLOYER_PHP}" artisan schedule:run --no-interaction
elif [[ $framework == "symfony" ]]; then
# Process messages for up to 55 seconds then exit (allows cron to restart fresh)
"${DEPLOYER_PHP}" bin/console messenger:consume async --time-limit=55 --no-interaction
else
echo "Unsupported framework for cron.sh. Customize this script for your app." >&2
exit 1
fi
108 changes: 71 additions & 37 deletions .deployer/hooks/2-releasing.sh → .deployer/scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set -euo pipefail

#
# Releasing - Runs immediately after building and right before the new release is activated
# Deploy Script - Link shared resources, build, and prepare for release activation
# ----
#
# Environment variables provided by Deployer PHP:
Expand All @@ -18,8 +18,6 @@ set -euo pipefail
#
# You're automatically in the DEPLOYER_RELEASE_PATH directory at this point:

echo "→ Preparing release..."

# ----
# Framework Detection
# ----
Expand All @@ -35,34 +33,86 @@ elif [[ -f spark ]]; then
fi

# ----
# Laravel
# Shared Resources
# ----

# Laravel
if [[ $framework == "laravel" ]]; then

#
# Ensure shared data
# ----

echo "→ Ensuring shared data..."

echo "→ Ensuring shared storage directories..."
mkdir -p "${DEPLOYER_SHARED_PATH}/storage/"{app,framework,logs}
mkdir -p "${DEPLOYER_SHARED_PATH}/storage/framework/"{cache,sessions,views}
"${DEPLOYER_PHP}" artisan storage:link

echo "→ Linking shared storage..."
rm -rf "${DEPLOYER_RELEASE_PATH}/storage"
ln -sfn "${DEPLOYER_SHARED_PATH}/storage" "${DEPLOYER_RELEASE_PATH}/storage"

echo "→ Ensuring shared sqlite database..."
mkdir -p "${DEPLOYER_SHARED_PATH}/database"
touch "${DEPLOYER_SHARED_PATH}/database/database.sqlite"

echo "→ Linking shared database.sqlite..."
ln -sf "${DEPLOYER_SHARED_PATH}/database/database.sqlite" "${DEPLOYER_RELEASE_PATH}/database/database.sqlite"
fi

# Symfony (uncomment as needed)
# if [[ $framework == "symfony" ]]; then
# echo "→ Ensuring shared var directories..."
# mkdir -p "${DEPLOYER_SHARED_PATH}/var/"{log,sessions}
#
# echo "→ Linking shared var..."
# rm -rf "${DEPLOYER_RELEASE_PATH}/var"
# ln -sfn "${DEPLOYER_SHARED_PATH}/var" "${DEPLOYER_RELEASE_PATH}/var"
# fi

# CodeIgniter (uncomment as needed)
# if [[ $framework == "codeigniter" ]]; then
# echo "→ Ensuring shared writable directories..."
# mkdir -p "${DEPLOYER_SHARED_PATH}/writable/"{cache,logs,session,uploads}
#
# echo "→ Linking shared writable..."
# rm -rf "${DEPLOYER_RELEASE_PATH}/writable"
# ln -sfn "${DEPLOYER_SHARED_PATH}/writable" "${DEPLOYER_RELEASE_PATH}/writable"
# fi

# .env (framework-agnostic)
if [[ -f "${DEPLOYER_SHARED_PATH}/.env" ]]; then
echo "→ Linking shared .env..."
ln -sf "${DEPLOYER_SHARED_PATH}/.env" "${DEPLOYER_RELEASE_PATH}/.env"
fi

# ----
# Build
# ----

echo "→ Building release..."

if [[ -f composer.json ]]; then
echo "→ Installing Composer dependencies..."

composer_bin="$(command -v composer || true)"
"${DEPLOYER_PHP}" "${composer_bin}" install --no-interaction --no-dev --optimize-autoloader
fi

if [[ -f package.json ]]; then
echo "→ Installing frontend dependencies..."
bun install --frozen-lockfile

echo "→ Building frontend assets..."
bun run build
fi

# ----
# Release Preparation
# ----

shared_db="${DEPLOYER_SHARED_PATH}/database/database.sqlite"
touch "${shared_db}"
# Laravel
if [[ $framework == "laravel" ]]; then

release_db="${DEPLOYER_RELEASE_PATH}/database/database.sqlite"
if [ ! -e "${release_db}" ] && [ ! -L "${release_db}" ]; then
ln -s "${shared_db}" "${release_db}"
fi
echo "→ Creating storage symlink..."
"${DEPLOYER_PHP}" artisan storage:link

echo "→ Ensuring app key exists..."
php artisan key:generate || true
"${DEPLOYER_PHP}" artisan key:generate || true

#
# Run migrations
Expand All @@ -80,16 +130,8 @@ if [[ $framework == "laravel" ]]; then

fi

# ----
# Symfony
# ----
# Uncomment as needed

# Symfony (uncomment as needed)
# if [[ $framework == "symfony" ]]; then
# # Ensure shared data
# echo "→ Ensuring shared data..."
# mkdir -p "${DEPLOYER_SHARED_PATH}/var/"{cache,log,sessions}
#
# # Run migrations
# echo "→ Running migrations..."
# "${DEPLOYER_PHP}" bin/console doctrine:migrations:migrate --no-interaction
Expand All @@ -99,16 +141,8 @@ fi
# "${DEPLOYER_PHP}" bin/console cache:clear
# fi

# ----
# CodeIgniter
# ----
# Uncomment as needed

# CodeIgniter (uncomment as needed)
# if [[ $framework == "codeigniter" ]]; then
# # Ensure shared data
# echo "→ Ensuring shared data..."
# mkdir -p "${DEPLOYER_SHARED_PATH}/writable/"{cache,logs,session,uploads}
#
# # Run migrations
# echo "→ Running migrations..."
# "${DEPLOYER_PHP}" spark migrate --all
Expand Down
67 changes: 67 additions & 0 deletions .deployer/scripts/supervisor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env bash

set -euo pipefail

#
# Supervisor Script - Run long-lived workers for supported frameworks
# ----
#
# This should be executed by supervisord on the remote server.
#
# Environment variables provided by runner script:
# DEPLOYER_RELEASE_PATH - Absolute path to the current release directory
# DEPLOYER_SHARED_PATH - Absolute path to the shared/ directory
# DEPLOYER_CURRENT_PATH - Absolute path to the current/ symlink
# DEPLOYER_DOMAIN - Site domain (example.com)
# DEPLOYER_BRANCH - Git branch currently deployed
# DEPLOYER_PHP - Absolute path to the PHP binary (e.g. /usr/bin/php8.4)
#
# The --max-time/--time-limit flags ensure graceful restart
# (matches default stopwaitsecs=3600).
#

cd "${DEPLOYER_CURRENT_PATH}"

# ----
# Framework Detection
# ----

framework=""

if [[ -f artisan ]]; then
framework="laravel"
elif [[ -f bin/console ]]; then
framework="symfony"
elif [[ -f spark ]]; then
framework="codeigniter"
fi

# ----
# Workers
# ----

if [[ $framework == "laravel" ]]; then
#
# Why exec is required:
# Without exec, the process tree looks like:
# supervisord -> bash (tracked) -> php (actual worker)
# Supervisord only tracks bash. When it sends SIGTERM to stop the program,
# the signal goes to bash, not PHP. PHP never gets a chance to gracefully
# finish the current message before shutting down.
#
# With exec, bash is replaced by PHP:
# supervisord -> php (tracked directly)
# Now SIGTERM goes directly to PHP, allowing graceful shutdown within
# the stopwaitsecs window (default 3600s).
#
exec "${DEPLOYER_PHP}" artisan queue:work --sleep=3 --tries=3 --max-time=3600
elif [[ $framework == "symfony" ]]; then
#
# Why exec is required:
# See Laravel notes above.
#
exec "${DEPLOYER_PHP}" bin/console messenger:consume async --time-limit=3600
else
echo "Unsupported framework for supervisor.sh. Customize this script for your app." >&2
exit 1
fi