changes
This commit is contained in:
@@ -6,44 +6,70 @@ use Illuminate\Support\Facades\Log;
|
|||||||
|
|
||||||
class DeploySiteAction
|
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 $logFile = '/var/www/_deploy/deploy.log';
|
||||||
|
private string $pidFile = '/var/www/_deploy/deploy.pid';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Создаёт файл-триггер для запуска деплоя
|
* Запускает deploy.sh напрямую
|
||||||
*
|
*
|
||||||
* @return array ['success' => bool, 'message' => string]
|
* @return array ['success' => bool, 'message' => string]
|
||||||
*/
|
*/
|
||||||
public function run(): array
|
public function run(): array
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// Проверяем, не запущен ли уже деплой
|
if (!file_exists($this->deployScript)) {
|
||||||
if (file_exists($this->lockFile)) {
|
return [
|
||||||
$lockContent = file_get_contents($this->lockFile);
|
'success' => false,
|
||||||
$lockData = json_decode($lockContent, true);
|
'message' => 'Скрипт деплоя не найден на сервере',
|
||||||
|
];
|
||||||
if ($lockData && isset($lockData['status']) && $lockData['status'] === 'running') {
|
|
||||||
return [
|
|
||||||
'success' => false,
|
|
||||||
'message' => 'Деплой уже запущен! Подождите завершения текущего процесса.',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Создаём файл-триггер
|
// Проверяем, не запущен ли уже деплой
|
||||||
$lockData = [
|
if ($this->isDeployRunning()) {
|
||||||
'status' => 'pending',
|
return [
|
||||||
'started_at' => now()->toDateTimeString(),
|
'success' => false,
|
||||||
'started_by' => auth()->id(),
|
'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 [
|
return [
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'message' => 'Деплой запущен! Процесс обновления сайта начнётся в течение 1 минуты.',
|
'message' => 'Деплой запущен! Процесс обновления сайта начнётся в течение нескольких секунд.',
|
||||||
];
|
];
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::error('Deploy trigger failed', ['exception' => $e->getMessage()]);
|
Log::error('Deploy trigger failed', ['exception' => $e->getMessage()]);
|
||||||
@@ -60,28 +86,52 @@ class DeploySiteAction
|
|||||||
*/
|
*/
|
||||||
public function getStatus(): array
|
public function getStatus(): array
|
||||||
{
|
{
|
||||||
if (!file_exists($this->lockFile)) {
|
if (!file_exists($this->logFile)) {
|
||||||
return ['status' => 'idle', 'message' => 'Деплой не запущен'];
|
return ['status' => 'idle', 'message' => 'Деплой не запущен'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = file_get_contents($this->lockFile);
|
$log = file_get_contents($this->logFile);
|
||||||
$data = json_decode($content, true);
|
|
||||||
|
|
||||||
if (!$data) {
|
// Проверяем, запущен ли процесс
|
||||||
return ['status' => 'error', 'message' => 'Ошибка чтения статуса'];
|
if ($this->isDeployRunning()) {
|
||||||
|
return [
|
||||||
|
'status' => 'running',
|
||||||
|
'message' => 'Деплой выполняется...',
|
||||||
|
'log' => $log,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Читаем лог если есть
|
// Процесс завершил — проверяем результат
|
||||||
$log = '';
|
$lastLines = array_slice(explode("\n", trim($log)), -5);
|
||||||
if (file_exists($this->logFile)) {
|
$lastOutput = implode("\n", $lastLines);
|
||||||
$log = file_get_contents($this->logFile);
|
|
||||||
|
$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 [
|
return [
|
||||||
'status' => $data['status'] ?? 'unknown',
|
'status' => 'unknown',
|
||||||
'started_at' => $data['started_at'] ?? null,
|
'message' => 'Статус неизвестен',
|
||||||
'completed_at' => $data['completed_at'] ?? null,
|
|
||||||
'message' => $data['message'] ?? '',
|
|
||||||
'log' => $log,
|
'log' => $log,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -91,8 +141,31 @@ class DeploySiteAction
|
|||||||
*/
|
*/
|
||||||
public function clearStatus(): void
|
public function clearStatus(): void
|
||||||
{
|
{
|
||||||
if (file_exists($this->lockFile)) {
|
if (file_exists($this->logFile)) {
|
||||||
unlink($this->lockFile);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user