Last active
June 30, 2025 15:12
-
-
Save giobi/9a3c43757e6a34620f4c371fe135ce60 to your computer and use it in GitHub Desktop.
Laravel app updater from remote git
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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!" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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