From c0babe8277087657815a9473857f5ce7d3da48a5 Mon Sep 17 00:00:00 2001 From: F4ilji Date: Thu, 9 Apr 2026 17:41:22 +0500 Subject: [PATCH] changes --- .../Actions/Posts/DeploySiteAction.php | 145 +++++++++++++----- 1 file changed, 109 insertions(+), 36 deletions(-) diff --git a/app/Containers/Dashboard/Actions/Posts/DeploySiteAction.php b/app/Containers/Dashboard/Actions/Posts/DeploySiteAction.php index 30ecfed..85e0a05 100644 --- a/app/Containers/Dashboard/Actions/Posts/DeploySiteAction.php +++ b/app/Containers/Dashboard/Actions/Posts/DeploySiteAction.php @@ -6,44 +6,70 @@ use Illuminate\Support\Facades\Log; class DeploySiteAction { - private string $lockFile = '/var/www/_deploy/deploy.lock'; + private string $deployScript = '/var/www/_deploy/deploy.sh'; private string $logFile = '/var/www/_deploy/deploy.log'; + private string $pidFile = '/var/www/_deploy/deploy.pid'; /** - * Создаёт файл-триггер для запуска деплоя + * Запускает deploy.sh напрямую * * @return array ['success' => bool, 'message' => string] */ public function run(): array { try { - // Проверяем, не запущен ли уже деплой - if (file_exists($this->lockFile)) { - $lockContent = file_get_contents($this->lockFile); - $lockData = json_decode($lockContent, true); - - if ($lockData && isset($lockData['status']) && $lockData['status'] === 'running') { - return [ - 'success' => false, - 'message' => 'Деплой уже запущен! Подождите завершения текущего процесса.', - ]; - } + if (!file_exists($this->deployScript)) { + return [ + 'success' => false, + 'message' => 'Скрипт деплоя не найден на сервере', + ]; } - // Создаём файл-триггер - $lockData = [ - 'status' => 'pending', - 'started_at' => now()->toDateTimeString(), - 'started_by' => auth()->id(), + // Проверяем, не запущен ли уже деплой + if ($this->isDeployRunning()) { + return [ + 'success' => false, + 'message' => 'Деплой уже запущен! Подождите завершения текущего процесса.', + ]; + } + + // Запускаем deploy.sh в фоне через proc_open + $command = sprintf( + 'nohup bash %s > %s 2>&1 & echo $!', + escapeshellarg($this->deployScript), + escapeshellarg($this->logFile) + ); + + $descriptors = [ + 1 => ['pipe', 'w'], // stdout + 2 => ['pipe', 'w'], // stderr ]; - file_put_contents($this->lockFile, json_encode($lockData, JSON_PRETTY_PRINT)); + $process = proc_open($command, $descriptors, $pipes); - Log::info('Deploy triggered', ['user_id' => auth()->id()]); + if (!is_resource($process)) { + Log::error('Deploy script failed to start — proc_open unavailable'); + return [ + 'success' => false, + 'message' => 'Ошибка при запуске скрипта деплоя (proc_open недоступен)', + ]; + } + + // Читаем PID процесса + $pid = trim(stream_get_contents($pipes[1])); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + + if (!empty($pid) && is_numeric($pid)) { + file_put_contents($this->pidFile, $pid); + } + + Log::info('Deploy triggered', ['user_id' => auth()->id(), 'pid' => $pid]); return [ 'success' => true, - 'message' => 'Деплой запущен! Процесс обновления сайта начнётся в течение 1 минуты.', + 'message' => 'Деплой запущен! Процесс обновления сайта начнётся в течение нескольких секунд.', ]; } catch (\Exception $e) { Log::error('Deploy trigger failed', ['exception' => $e->getMessage()]); @@ -60,28 +86,52 @@ class DeploySiteAction */ public function getStatus(): array { - if (!file_exists($this->lockFile)) { + if (!file_exists($this->logFile)) { return ['status' => 'idle', 'message' => 'Деплой не запущен']; } - $content = file_get_contents($this->lockFile); - $data = json_decode($content, true); + $log = file_get_contents($this->logFile); - if (!$data) { - return ['status' => 'error', 'message' => 'Ошибка чтения статуса']; + // Проверяем, запущен ли процесс + if ($this->isDeployRunning()) { + return [ + 'status' => 'running', + 'message' => 'Деплой выполняется...', + 'log' => $log, + ]; } - // Читаем лог если есть - $log = ''; - if (file_exists($this->logFile)) { - $log = file_get_contents($this->logFile); + // Процесс завершил — проверяем результат + $lastLines = array_slice(explode("\n", trim($log)), -5); + $lastOutput = implode("\n", $lastLines); + + $isSuccess = stripos($lastOutput, 'успешн') !== false + || stripos($lastOutput, 'success') !== false + || stripos($lastOutput, '✅') !== false; + + $isFailed = stripos($lastOutput, 'ошибк') !== false + || stripos($lastOutput, 'error') !== false + || stripos($lastOutput, '❌') !== false; + + if ($isSuccess) { + return [ + 'status' => 'completed', + 'message' => 'Деплой завершён успешно!', + 'log' => $log, + ]; + } + + if ($isFailed) { + return [ + 'status' => 'failed', + 'message' => 'Деплой завершён с ошибкой', + 'log' => $log, + ]; } return [ - 'status' => $data['status'] ?? 'unknown', - 'started_at' => $data['started_at'] ?? null, - 'completed_at' => $data['completed_at'] ?? null, - 'message' => $data['message'] ?? '', + 'status' => 'unknown', + 'message' => 'Статус неизвестен', 'log' => $log, ]; } @@ -91,8 +141,31 @@ class DeploySiteAction */ public function clearStatus(): void { - if (file_exists($this->lockFile)) { - unlink($this->lockFile); + if (file_exists($this->logFile)) { + unlink($this->logFile); + } + if (file_exists($this->pidFile)) { + unlink($this->pidFile); } } + + /** + * Проверяет, запущен ли процесс деплоя + */ + private function isDeployRunning(): bool + { + if (!file_exists($this->pidFile)) { + return false; + } + + $pid = trim(file_get_contents($this->pidFile)); + if (empty($pid)) { + return false; + } + + // Проверяем существование процесса + exec(sprintf('kill -0 %s 2>/dev/null', escapeshellarg($pid)), $output, $exitCode); + + return $exitCode === 0; + } }