Skip to content

Instantly share code, notes, and snippets.

@giobi
Last active June 30, 2025 15:12
Show Gist options
  • Save giobi/9a3c43757e6a34620f4c371fe135ce60 to your computer and use it in GitHub Desktop.
Save giobi/9a3c43757e6a34620f4c371fe135ce60 to your computer and use it in GitHub Desktop.
Laravel app updater from remote git
#!/bin/bash
# --- Configurazione (leggi da .env) ---
# Questo script Bash si aspetta di essere eseguito dalla root dell'applicazione Laravel
# o che APP_ROOT sia configurato correttamente.
# Assicurati che il file .env sia nella directory APP_ROOT.
# Percorso assoluto della root dell'applicazione
APP_ROOT="$(dirname "$(dirname "$(readlink -f "$0")")")" # Assumendo script in APP_ROOT/scripts/
# Percorsi delle directory chiave
RELEASES_DIR="$APP_ROOT/releases"
PUBLIC_STORAGE_DIR="$APP_ROOT/publicstorage" # Corrisponde a __DIR__ . '/publicstorage' nel tuo PHP
CURRENT_SYMLINK="$APP_ROOT/current"
ENV_FILE="$APP_ROOT/.env"
DEPLOY_LOCK_FILE="$APP_ROOT/deploy.lock"
DEPLOY_LOG_FILE="$APP_ROOT/deploy.log"
# Variabili lette da .env
GIT_REPO=""
GIT_BRANCH="main" # Default come nel tuo script PHP
DEPLOY_TOKEN=""
APP_URL=""
# Utente e gruppo del webserver - DA CONFIGURARE
WEBSERVER_USER="www-data"
WEBSERVER_GROUP="www-data"
# Versione dello script (dal tuo PHP)
VERSION="25.5.8"
# --- Funzioni di Utility ---
# Funzione per loggare messaggi (corrisponde a logMessage in PHP)
log_message() {
local message="$1"
echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" | tee -a "$DEPLOY_LOG_FILE"
# Aggiorna il file deploy.lock con lo stato corrente
if [ -f "$DEPLOY_LOCK_FILE" ]; then
# Richiede 'jq' per manipolare JSON
if command -v jq &> /dev/null; then
jq --arg msg "$message" '.status = $msg' "$DEPLOY_LOCK_FILE" > "$DEPLOY_LOCK_FILE.tmp" && mv "$DEPLOY_LOCK_FILE.tmp" "$DEPLOY_LOCK_FILE"
else
echo "Avviso: 'jq' non è installato. Impossibile aggiornare lo stato in deploy.lock." | tee -a "$DEPLOY_LOG_FILE"
fi
fi
}
# Funzione per uscire in caso di errore
exit_on_error() {
log_message "ERRORE: $1"
# Rimuovi il file di blocco in caso di errore
if [ -f "$DEPLOY_LOCK_FILE" ]; then
rm "$DEPLOY_LOCK_FILE"
log_message "Rimosso file di blocco ($DEPLOY_LOCK_FILE) a causa di errore."
fi
exit 1
}
# Funzione per caricare le variabili d'ambiente dal file .env
load_env() {
if [ ! -f "$ENV_FILE" ]; then
exit_on_error ".env file not found at $ENV_FILE"
fi
# Leggi il file .env e imposta le variabili
# Questo approccio è più robusto di 'source' per variabili con spazi o caratteri speciali
while IFS='=' read -r key value; do
if [[ ! "$key" =~ ^# && -n "$key" ]]; then
# Rimuovi spazi bianchi e virgolette
key=$(echo "$key" | xargs)
value=$(echo "$value" | xargs | sed 's/^"//;s/"$//;s/^'\''//;s/'\''$//')
case "$key" in
"GIT_REPO") GIT_REPO="$value" ;;
"GIT_BRANCH") GIT_BRANCH="$value" ;;
"DEPLOY_TOKEN") DEPLOY_TOKEN="$value" ;;
"APP_URL") APP_URL="$value" ;;
esac
fi
done < "$ENV_FILE"
if [ -z "$GIT_REPO" ]; then
exit_on_error "GIT_REPO not set in .env. Please configure it."
fi
if [ -z "$APP_URL" ]; then
log_message "APP_URL not set in .env, something could be wrong."
# exit_on_error "APP_URL not set in .env." # Commentato come nel tuo script PHP
fi
if [ -z "$GIT_BRANCH" ]; then
log_message "GIT_BRANCH not set in .env, defaulting to 'main'."
GIT_BRANCH="main"
fi
}
# --- Inizio del Deployment ---
log_message "Inizio del processo di deployment (versione script: $VERSION)."
log_message "By giobi.com"
# Carica le variabili d'ambiente
load_env
log_message "Git repository: $GIT_REPO"
log_message "Git branch: $GIT_BRANCH"
log_message "App URL: $APP_URL"
# Controllo del file di blocco
if [ -f "$DEPLOY_LOCK_FILE" ]; then
log_message "File di blocco del deploy ($DEPLOY_LOCK_FILE) già esistente. Deployment annullato."
exit 0 # Esci senza errore, come nel tuo script PHP se il lock esiste e non viene rimosso
fi
# 1. Creazione della nuova directory di release
TIMESTAMP=$(date +%Y%m%d%H%M%S)
NEW_RELEASE_DIR="$RELEASES_DIR/$TIMESTAMP"
log_message "Creazione della nuova directory di release: $NEW_RELEASE_DIR"
mkdir -p "$NEW_RELEASE_DIR" || exit_on_error "Impossibile creare la directory di release."
# 2. Assicurati che publicstorage esista
log_message "Verifica e creazione della directory publicstorage: $PUBLIC_STORAGE_DIR"
mkdir -p "$PUBLIC_STORAGE_DIR" || exit_on_error "Impossibile creare la directory publicstorage."
# 3. Genera deploy.lock
log_message "Creazione del file di blocco ($DEPLOY_LOCK_FILE)..."
if command -v jq &> /dev/null; then
# Ottieni l'IP remoto (se disponibile, altrimenti placeholder)
# Nota: REMOTE_ADDR non è disponibile in un ambiente CLI.
# Se questo script è chiamato da un webhook, il controller PHP dovrebbe passare l'IP.
# Per ora, useremo un placeholder o il nome host.
DEPLOYER_IP="N/A (CLI)"
if [ -n "$REMOTE_ADDR" ]; then # Se l'IP remoto è passato come variabile d'ambiente
DEPLOYER_IP="$REMOTE_ADDR"
fi
# Ottieni l'utente corrente
CURRENT_USER=$(whoami)
jq -n \
--arg timestamp "$(date '+%Y-%m-%d %H:%M:%S')" \
--arg deployer "$CURRENT_USER" \
--arg ip "$DEPLOYER_IP" \
--arg git_repo "$GIT_REPO" \
--arg git_branch "$GIT_BRANCH" \
--arg app_url "$APP_URL" \
--arg status "deploying" \
'{timestamp: $timestamp, deployer: $deployer, ip: $ip, git_repo: $git_repo, git_branch: $git_branch, app_url: $app_url, status: $status}' > "$DEPLOY_LOCK_FILE" \
|| exit_on_error "Impossibile creare il file di blocco ($DEPLOY_LOCK_FILE)."
else
# Fallback se jq non è installato
echo "timestamp=$(date '+%Y-%m-%d %H:%M:%S')" > "$DEPLOY_LOCK_FILE"
echo "status=deploying" >> "$DEPLOY_LOCK_FILE"
log_message "Avviso: 'jq' non è installato. Il file deploy.lock è stato creato in formato semplice."
fi
log_message "File di blocco creato: $DEPLOY_LOCK_FILE"
# 4. Clonare il repository nella nuova directory
log_message "Clonazione del repository ($GIT_REPO:$GIT_BRANCH) in $NEW_RELEASE_DIR..."
git clone -b "$GIT_BRANCH" --single-branch "$GIT_REPO" "$NEW_RELEASE_DIR" || exit_on_error "Errore durante il clone del repository. Controlla la configurazione Git e i permessi."
# 5. Assicurarsi che le directory richieste in storage/framework esistano
# Nota: Dopo il clone, queste directory potrebbero già esistere, ma assicurarsi che siano scrivibili.
log_message "Verifica e creazione delle directory storage/framework..."
FRAMEWORK_DIR="$NEW_RELEASE_DIR/storage/framework"
SESSIONS_DIR="$FRAMEWORK_DIR/sessions"
VIEWS_DIR="$FRAMEWORK_DIR/views"
CACHE_DIR="$FRAMEWORK_DIR/cache"
LOGS_DIR="$NEW_RELEASE_DIR/storage/logs"
BOOTSTRAP_CACHE_DIR="$NEW_RELEASE_DIR/bootstrap/cache"
for dir in "$FRAMEWORK_DIR" "$SESSIONS_DIR" "$VIEWS_DIR" "$CACHE_DIR" "$LOGS_DIR" "$BOOTSTRAP_CACHE_DIR"; do
if [ ! -d "$dir" ] && [ ! -L "$dir" ]; then # Controlla se non è una directory e non è un symlink
mkdir -p "$dir" || exit_on_error "Impossibile creare la directory: $dir"
log_message "Creata directory: $dir"
fi
done
# 6. Creare link simbolici per .env e storage/app/public
log_message "Creazione dei link simbolici per .env e storage..."
# Rimuovi .env e storage clonati dal repo per creare i symlink
rm -f "$NEW_RELEASE_DIR/.env" || log_message "Avviso: Impossibile rimuovere $NEW_RELEASE_DIR/.env"
rm -rf "$NEW_RELEASE_DIR/storage" || log_message "Avviso: Impossibile rimuovere $NEW_RELEASE_DIR/storage"
ln -sfn "$ENV_FILE" "$NEW_RELEASE_DIR/.env" || exit_on_error "Impossibile creare symlink per .env."
ln -sfn "$PUBLIC_STORAGE_DIR" "$NEW_RELEASE_DIR/storage" || exit_on_error "Impossibile creare symlink per storage."
# Nota: php artisan storage:link creerà public/storage -> storage/app/public
# La riga successiva è ridondante se usi storage:link ma presente nel tuo script.
# ln -sfn "$PUBLIC_STORAGE_DIR" "$NEW_RELEASE_DIR/storage/app/public" || exit_on_error "Impossibile creare symlink per storage/app/public."
# 7. Imposta permessi e proprietari
log_message "Impostazione permessi e proprietari..."
# Nota: La tua logica PHP per i permessi è un po' ridondante.
# `chmod -R 775` è sufficiente per proprietario/gruppo con scrittura.
# Assicurati che l'utente che esegue lo script abbia i permessi sudo o sia il proprietario delle directory.
# Permessi per publicstorage (condivisa tra release)
chmod -R ug+w "$PUBLIC_STORAGE_DIR" || log_message "Avviso: Impossibile impostare permessi di scrittura per $PUBLIC_STORAGE_DIR"
chmod -R o+w "$PUBLIC_STORAGE_DIR" || log_message "Avviso: Impossibile impostare permessi di scrittura per altri su $PUBLIC_STORAGE_DIR" # `guo+w` non è standard, `o+w` è per "others"
# Permessi per la nuova release (storage e bootstrap/cache)
chown -R "$WEBSERVER_USER":"$WEBSERVER_GROUP" "$NEW_RELEASE_DIR/storage" || log_message "Avviso: Impossibile cambiare proprietario di $NEW_RELEASE_DIR/storage"
chown -R "$WEBSERVER_USER":"$WEBSERVER_GROUP" "$NEW_RELEASE_DIR/bootstrap/cache" || log_message "Avviso: Impossibile cambiare proprietario di $NEW_RELEASE_DIR/bootstrap/cache"
chmod -R 775 "$NEW_RELEASE_DIR/storage" || log_message "Avviso: Impossibile impostare permessi 775 per $NEW_RELEASE_DIR/storage"
chmod -R 775 "$NEW_RELEASE_DIR/bootstrap/cache" || log_message "Avviso: Impossibile impostare permessi 775 per $NEW_RELEASE_DIR/bootstrap/cache"
# 8. COMPOSER - Installare le dipendenze
log_message "Installazione delle dipendenze Composer in $NEW_RELEASE_DIR..."
# Usa --working-dir per specificare la directory
composer install --no-dev --optimize-autoloader --working-dir="$NEW_RELEASE_DIR" || {
log_message "Errore durante l'installazione delle dipendenze Composer."
# Cattura l'output di composer per il debug
composer_output=$(composer install --no-dev --optimize-autoloader --working-dir="$NEW_RELEASE_DIR" 2>&1)
log_message "Output di Composer:\n$composer_output"
exit_on_error "Composer install fallito."
}
# 9. Generare cache di configurazione, route e view
log_message "Generazione cache di configurazione, route e view..."
php "$NEW_RELEASE_DIR/artisan" config:cache || log_message "Avviso: config:cache fallito."
php "$NEW_RELEASE_DIR/artisan" route:cache || log_message "Avviso: route:cache fallito."
php "$NEW_RELEASE_DIR/artisan" view:cache || log_message "Avviso: view:cache fallito."
php "$NEW_RELEASE_DIR/artisan" event:cache || log_message "Avviso: event:cache fallito (se non usato, ignorare)." # Aggiunto per completezza
# 10. Eseguire le migrazioni
log_message "Esecuzione delle migrazioni del database..."
php "$NEW_RELEASE_DIR/artisan" migrate --force || exit_on_error "Errore durante l'esecuzione delle migrazioni. Controlla la configurazione del database."
# 11. Eseguire eventuali comandi post-deploy personalizzati
log_message "Esecuzione di comandi post-deploy personalizzati (app:postdeploy)..."
php "$NEW_RELEASE_DIR/artisan" app:postdeploy || log_message "Avviso: Comando app:postdeploy fallito o non trovato. Saltato."
# 12. Pulizia cache Laravel
log_message "Pulizia cache Laravel (optimize:clear)..."
php "$NEW_RELEASE_DIR/artisan" optimize:clear || log_message "Avviso: optimize:clear fallito."
# 13. Aggiornare il link simbolico per 'current' (Passaggio atomico)
log_message "Aggiornamento del symlink 'current' alla nuova release ($NEW_RELEASE_DIR)..."
ln -sfn "$NEW_RELEASE_DIR" "$CURRENT_SYMLINK" || exit_on_error "Impossibile aggiornare il symlink 'current'."
# 14. Creare un link simbolico per il trigger di deploy in current/public
# Questo crea un symlink dal deploy.php originale a current/public/deploy/index.php
# Nota: Il tuo script PHP originale crea deploy.php, qui assumiamo che deploy.php esista nella APP_ROOT
DEPLOY_SCRIPT_PATH="$APP_ROOT/deploy.php" # Assumi che deploy.php sia nella root dell'app
DEPLOY_TRIGGER_DIR="$NEW_RELEASE_DIR/public/deploy"
DEPLOY_TRIGGER_LINK="$DEPLOY_TRIGGER_DIR/index.php"
log_message "Creazione del link simbolico per il trigger di deploy: $DEPLOY_TRIGGER_LINK"
mkdir -p "$DEPLOY_TRIGGER_DIR" || log_message "Avviso: Impossibile creare directory per trigger deploy."
if [ -f "$DEPLOY_SCRIPT_PATH" ]; then
ln -sfn "$DEPLOY_SCRIPT_PATH" "$DEPLOY_TRIGGER_LINK" || log_message "Avviso: Impossibile creare link simbolico per trigger deploy."
else
log_message "Avviso: Script deploy.php non trovato in $DEPLOY_SCRIPT_PATH. Trigger link non creato."
fi
# 15. Store deploy metadata in current/public/deploy/data.json
log_message "Creazione del file di metadati di deploy: $NEW_RELEASE_DIR/public/deploy/data.json"
DEPLOY_JSON_FILE="$NEW_RELEASE_DIR/public/deploy/data.json"
if command -v jq &> /dev/null; then
jq -n \
--arg timestamp "$(date '+%Y-%m-%d %H:%M:%S')" \
--arg release "$TIMESTAMP" \
'{timestamp: $timestamp, release: $release}' > "$DEPLOY_JSON_FILE" \
|| log_message "Avviso: Impossibile creare il file data.json con jq."
else
echo "{\"timestamp\": \"$(date '+%Y-%m-%d %H:%M:%S')\", \"release\": \"$TIMESTAMP\"}" > "$DEPLOY_JSON_FILE"
log_message "Avviso: 'jq' non è installato. Il file data.json è stato creato in formato semplice."
fi
# 16. Pulire vecchie release (mantieni solo le ultime 5)
log_message "Pulizia delle vecchie release (mantenendo le ultime 5)..."
# Ottieni le directory di release ordinate per data di modifica (più recenti prima)
# e salta le prime 5
OLD_RELEASES=$(ls -td "$RELEASES_DIR"/*/ | head -n +6 | tail -n +6) # Mantiene le ultime 5, elimina dalla sesta in poi
if [ -n "$OLD_RELEASES" ]; then
for release_path in $OLD_RELEASES; do
log_message "Eliminazione della vecchia release: $release_path"
rm -rf "$release_path" || log_message "Avviso: Impossibile eliminare la vecchia release: $release_path"
done
else
log_message "Nessuna vecchia release da pulire."
fi
# 17. Rimuovere il file di blocco del deploy
log_message "Rimozione del file di blocco ($DEPLOY_LOCK_FILE)..."
rm -f "$DEPLOY_LOCK_FILE" || log_message "Avviso: Impossibile rimuovere il file di blocco ($DEPLOY_LOCK_FILE)."
log_message "Deployment completato con successo!"
<?php
/*
2025 giobi.com
to install this script, set a .env file with a GIT_REPO url
it's better to set also a GIT_BRANCH, DEPLOY_KEY and APP_URL
run this
wget https://gist.github.com/giobi/9a3c43757e6a34620f4c371fe135ce60/raw/update.php
then run it with
php update.php {--force}
have fun!
this script is a work in progress, please report any issue to github.com/giobi
*/
declare(strict_types=1);
const VERSION = '25.5.8';
// Funzione per mostrare messaggi di log
function logMessage(string $message): void
{
$message = "[" . date('Y-m-d H:i:s') . "] $message" . PHP_EOL;
echo $message;
// in present update lock file
$deployLock = __DIR__ . '/deploy.lock';
if (file_exists($deployLock)) {
$data = json_decode(file_get_contents($deployLock), true);
$data['status'] = $message;
file_put_contents($deployLock, json_encode($data, JSON_PRETTY_PRINT));
}
if (php_sapi_name() !== 'cli') {
echo str_repeat(' ', 4096) . PHP_EOL;
ob_flush();
flush();
}
}
// Funzione per caricare il file .env in stile Laravel
function loadEnv(string $filePath): array
{
if (!file_exists($filePath)) {
logMessage(".env file not found at $filePath");
exit(1);
}
$env = [];
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (str_starts_with(trim($line), '#') || !str_contains($line, '=')) {
continue;
}
[$key, $value] = explode('=', $line, 2);
$env[trim($key)] = trim($value);
}
return $env;
}
// Determinare se lo script viene eseguito dalla linea di comando o tramite HTTP
if (php_sapi_name() === 'cli') {
$isCli = true;
parse_str(implode('&', array_slice($argv, 1)), $_GET);
} else {
$isCli = false;
}
// Caricare il file .env
$envFile = __DIR__ . '/.env';
$env = loadEnv($envFile);
if (!isset($env['GIT_REPO'])) {
logMessage("GIT_REPO, GIT_BRANCH, DEPLOY_KEY, or APP_URL not set in .env. Please configure it.");
exit(1);
}
if (!isset($env['APP_URL'])) {
logMessage("APP_URL not set in .env, something could be wrong.");
// exit(1);
}
if (!isset($env['GIT_BRANCH'])) {
logMessage("GIT_BRANCH not set in .env, defaulting to 'main'.");
$env['GIT_BRANCH'] = 'main';
}
$gitRepo = $env['GIT_REPO'];
$gitBranch = $env['GIT_BRANCH'];
$deployToken = $env['DEPLOY_TOKEN'] ?? null;
$appUrl = rtrim($env['APP_URL'], '/') ?? "no url set";
// Se non è CLI, verificare la chiave GET
if (!$isCli) {
if (!$deployToken || !isset($_GET['token']) || $_GET['token'] !== $deployToken) {
http_response_code(403);
echo "Forbidden: Invalid token: " . $_GET['token'];
exit;
}
}
$noInteraction = in_array('--force', $argv);
// chiedere conferma per il deploy
if ($isCli && !$noInteraction) {
echo "Updater version: " . VERSION . PHP_EOL;
echo "By giobi.com" . PHP_EOL;
echo "Git repository: $gitRepo" . PHP_EOL;
echo "Git branch: $gitBranch" . PHP_EOL;
echo "App URL: $appUrl" . PHP_EOL;
echo "---" . PHP_EOL;
echo "" . PHP_EOL;
echo "Deploying $gitRepo:$gitBranch to $appUrl" . PHP_EOL;
echo "Are you sure you want to continue? [y/N] ";
$confirm = strtolower(trim(fgets(STDIN)));
if ($confirm !== 'y') {
logMessage("Deployment cancelled.");
exit;
}
}
// Assicurarsi che la directory releases esista
$releasesDir = __DIR__ . '/releases';
if (!is_dir($releasesDir)) {
mkdir($releasesDir, 0755, true);
logMessage("Created releases directory: $releasesDir");
}
// assicurarsi che public-storage esista
$publicStorage = __DIR__ . '/publicstorage';
if (!is_dir($publicStorage)) {
mkdir($publicStorage, 0755, true);
logMessage("Created public storage directory: $publicStorage");
}
// generare deploy.lock
$deployLock = __DIR__ . '/deploy.lock';
if (!file_exists($deployLock)) {
touch($deployLock);
// put json data into deploy.lock
$data = [
'timestamp' => date('Y-m-d H:i:s'),
'deployer' => get_current_user(),
'ip' => $_SERVER['REMOTE_ADDR'],
'git_repo' => $gitRepo,
'git_branch' => $gitBranch,
'app_url' => $appUrl,
'status' => 'deploying',
];
file_put_contents($deployLock, json_encode($data, JSON_PRETTY_PRINT));
logMessage("Created deploy lock file: $deployLock");
} else {
// ask to remove lock file
if ($isCli) {
echo "Deploy lock file already exists. Do you want to remove it? [y/N] ";
$confirm = strtolower(trim(fgets(STDIN)));
if ($confirm === 'y') {
unlink($deployLock);
logMessage("Removed deploy lock file: $deployLock");
} else {
logMessage("Deployment cancelled.");
}
}
exit;
}
// Generare timestamp per la release
$timestamp = date('YmdHis');
$releaseDir = "$releasesDir/$timestamp";
// Clonare il repository nella nuova directory
logMessage("Cloning repository...");
exec("git clone -b $gitBranch --single-branch $gitRepo $releaseDir", $output, $returnCode);
if ($returnCode !== 0) {
logMessage("Failed to clone repository. Check your Git configuration.");
exit(1);
}
// Assicurarsi che le directory richieste in storage/framework esistano
$frameworkDir = "$releaseDir/storage/framework";
$sessionsDir = "$frameworkDir/sessions";
$viewsDir = "$frameworkDir/views";
$cacheDir = "$frameworkDir/cache";
$logsDir = "$releaseDir/storage/logs";
$bootstrapCacheDir = "$releaseDir/bootstrap/cache";
foreach ([$frameworkDir, $sessionsDir, $viewsDir, $cacheDir, $logsDir, $cacheDir] as $dir) {
if (!is_dir($dir) && !is_link($dir)) {
mkdir($dir, 0755, true);
logMessage("Created directory: $dir");
}
}
// Creare link simbolici per .env e storage/app/public
logMessage("Creating symbolic links for env and storage...");
symlink($envFile, $releaseDir . '/.env');
symlink($publicStorage, "$releaseDir/public/storage");
symlink($publicStorage, "$releaseDir/storage/app/public");
/*
chmod -R gu+w storage
chmod -R guo+w storage
aggiornare i permessi delle cartelle storage
*/
exec("chmod -R gu+w $publicStorage");
exec("chmod -R guo+w $publicStorage");
exec("chmod -R gu+w $frameworkDir");
exec("chmod -R guo+w $frameworkDir");
exec("chmod -R guo+w $logsDir");
exec("chmod -R 775 $bootstrapCacheDir");
$webserverUser = 'www-data'; // <--- IMPOSTA QUESTO
$webserverGroup = 'www-data'; // <--- IMPOSTA QUESTO
exec("chown -R $webserverUser:$webserverGroup $releaseDir/storage");
exec("chown -R $webserverUser:$webserverGroup $releaseDir/bootstrap/cache");
// Imposta permessi di scrittura per proprietario e gruppo (775)
exec("chmod -R 775 $releaseDir/storage"); // Applica a storage, include logs e framework
exec("chmod -R 775 $releaseDir/bootstrap/cache");
// COMPOSER - Installare le dipendenze
logMessage("Installing dependencies...");
exec("composer update --no-dev --optimize-autoloader -d $releaseDir", $output, $returnCode);
if ($returnCode !== 0) {
logMessage("Failed to install dependencies. Ensure Composer is installed and configured.");
// *** AGGIUNGI QUESTO PER VEDERE L'OUTPUT DI COMPOSER ***
logMessage("Composer output:");
logMessage(implode(PHP_EOL, $output));
// ***************************************************
// remove lock file
unlink($deployLock);
exit(1);
}
// Generare cache di configurazione, route e view
logMessage("Caching configuration, routes, and views...");
exec("php $releaseDir/artisan config:cache", $output, $returnCode);
exec("php $releaseDir/artisan route:cache", $output, $returnCode);
exec("php $releaseDir/artisan view:cache", $output, $returnCode);
// Eseguire le migrazioni
logMessage("Running migrations...");
exec("php $releaseDir/artisan migrate --force", $output, $returnCode);
if ($returnCode !== 0) {
logMessage("Failed to run migrations. Check your database configuration.");
exit(1);
}
// Eseguire eventuali comandi post-deploy personalizzati
logMessage("Running post-deploy commands if available...");
exec("php $releaseDir/artisan app:postdeploy", $output, $returnCode);
if ($returnCode !== 0) {
logMessage("Post-deploy command failed or not found. Skipping.");
}
// php artisan optimize:clear
exec("php $releaseDir/artisan optimize:clear");
// Aggiornare il link simbolico per 'current'
logMessage("Updating current symlink...");
$currentLink = __DIR__ . '/current';
if (is_link($currentLink)) {
unlink($currentLink);
}
symlink($releaseDir, $currentLink);
// Creare un link simbolico per il trigger di deploy in current/public
mkdir("$releaseDir/public/deploy", 0755, true);
$deployTrigger = __DIR__ . '/current/public/deploy/index.php';
$deployScript = __DIR__ . '/deploy.php';
if (!is_link($deployTrigger)) {
symlink($deployScript, $deployTrigger);
logMessage("Created deploy trigger link: $deployTrigger");
}
// Store deploy metadata in current/public/deploy.json
$deployData = [
'timestamp' => date('Y-m-d H:i:s'),
// 'deployer' => get_current_user(),
// 'ip' => $_SERVER['REMOTE_ADDR'],
// 'git_repo' => $gitRepo,
// 'git_branch' => $gitBranch,
// 'app_url' => $appUrl,
// 'release_dir' => $releaseDir,
'release' => $timestamp,
];
$deployJson = __DIR__ . '/current/public/deploy/data.json';
// create file
touch($deployJson);
file_put_contents($deployJson, json_encode($deployData, JSON_PRETTY_PRINT));
// Mostrare la URL per il trigger di deploy
if ($isCli) {
$deployUrl = "$appUrl/deploy.php?token=$deployToken";
logMessage("Deployment trigger URL: $deployUrl");
}
// Pulire vecchie release (mantieni solo le ultime 5)
logMessage("Cleaning up old releases...");
$releases = array_diff(scandir($releasesDir), ['.', '..']);
usort($releases, function ($a, $b) use ($releasesDir) {
return filemtime("$releasesDir/$b") <=> filemtime("$releasesDir/$a");
});
$oldReleases = array_slice($releases, 5);
foreach ($oldReleases as $oldRelease) {
$oldReleasePath = "$releasesDir/$oldRelease";
exec("rm -rf $oldReleasePath");
}
// Rimuovere il file di blocco del deploy
unlink($deployLock);
logMessage("Deployment successful!");
if ($isCli) {
exit;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment