diff --git a/config/config.example.php b/config/config.example.php index 2fa1028..a7d6c9e 100644 --- a/config/config.example.php +++ b/config/config.example.php @@ -41,7 +41,7 @@ return [ 'scripts_dir' => '/workspace/ac-scripts', 'notify' => [ 'admin_email' => 'bestcastr@gmail.com', - 'broadcast_config' => '/var/www/ac/workspace/ac-ms-broadcast/config/config.php', + 'broadcast_config' => '/var/www/ac/broadcast/config/config.php', 'telegram_token' => '', 'telegram_chat_id' => '', ], diff --git a/public/api/build_trigger.php b/public/api/build_trigger.php index 2c13268..ced2e5a 100644 --- a/public/api/build_trigger.php +++ b/public/api/build_trigger.php @@ -32,5 +32,15 @@ if (!isset($params['trigger_source'])) { } $user = Auth::user(); -$build = BuildRunner::enqueue($params, isset($user['id']) ? (int) $user['id'] : null); -json_out(['ok' => true, 'build' => $build]); +try { + $build = BuildRunner::enqueue($params, isset($user['id']) ? (int) $user['id'] : null); +} catch (Throwable $e) { + error_log('[build_trigger] ' . $e->getMessage()); + json_out(['ok' => false, 'error' => BuildErrorSanitizer::sanitize($e->getMessage())], 500); +} +$failed = (($build['status'] ?? '') === 'failed'); +json_out([ + 'ok' => !$failed, + 'build' => $build, + 'error' => $failed ? (string) ($build['error_message'] ?? 'Build failed to start') : null, +]); diff --git a/src/BuildNotifier.php b/src/BuildNotifier.php index 942ff42..c1ddebc 100644 --- a/src/BuildNotifier.php +++ b/src/BuildNotifier.php @@ -47,6 +47,9 @@ final class BuildNotifier { self::sendPlainEmail($to, $subject, nl2br(h($bodyText)), self::smtpConfig()); } } + + // Lab default: always alert admin_email (and Telegram when configured). + self::notifyAdmin($subject, $bodyText, $code, $safeError, $detailUrl); } private static function notifyAdmin(string $subject, string $bodyText, string $code, string $safeError, string $detailUrl): void { @@ -106,14 +109,19 @@ final class BuildNotifier { if (is_array($cached)) { return $cached; } - $path = (string) cfg( - 'build.notify.broadcast_config', - '/var/www/ac/workspace/ac-ms-broadcast/config/config.php' - ); - if ($path !== '' && is_file($path)) { - $cfg = require $path; - $cached = is_array($cfg) ? $cfg : []; - return $cached; + $paths = array_values(array_unique(array_filter([ + (string) cfg('build.notify.broadcast_config', ''), + '/var/www/ac/broadcast/config/config.php', + '/var/www/ac/workspace/ac-ms-broadcast/config/config.php', + ]))); + foreach ($paths as $path) { + if ($path !== '' && is_file($path)) { + $cfg = require $path; + if (is_array($cfg)) { + $cached = $cfg; + return $cached; + } + } } $cached = []; return $cached; @@ -187,7 +195,13 @@ final class BuildNotifier { /** @param array $smtp */ private static function sendPlainEmail(string $to, string $subject, string $htmlBody, array $smtp): void { - if ($to === '' || empty($smtp['user']) || empty($smtp['pass'])) { + if ($to === '') { + return; + } + $transport = strtolower((string) cfg('mail.transport', 'smtp')); + $hasSmtpCreds = !empty($smtp['user']) && !empty($smtp['pass']); + if ($transport === 'sendmail' || !$hasSmtpCreds) { + self::sendMailTransport($to, $subject, $htmlBody); return; } $host = (string) ($smtp['host'] ?? 'smtp.gmail.com'); @@ -233,4 +247,17 @@ final class BuildNotifier { $send('QUIT'); fclose($sock); } + + private static function sendMailTransport(string $to, string $subject, string $htmlBody): void { + $from = (string) cfg('mail.from', 'Android Cast '); + $replyTo = (string) cfg('mail.reply_to', ''); + $plain = strip_tags(str_replace(['
', '
', '
'], "\n", $htmlBody)); + $headers = "From: {$from}\r\n"; + if ($replyTo !== '') { + $headers .= "Reply-To: {$replyTo}\r\n"; + } + $headers .= "MIME-Version: 1.0\r\n"; + $headers .= "Content-Type: text/html; charset=UTF-8\r\n"; + @mail($to, $subject, $htmlBody, $headers); + } } diff --git a/src/BuildRunner.php b/src/BuildRunner.php index bb6be02..1bb81a3 100644 --- a/src/BuildRunner.php +++ b/src/BuildRunner.php @@ -133,7 +133,13 @@ YAML; ]); $dir = self::artifactDir($id); if (!is_dir($dir) && !mkdir($dir, 0775, true) && !is_dir($dir)) { - throw new RuntimeException('Cannot create artifact dir: ' . $dir); + self::failBuild( + $id, + 'Cannot create artifact dir: ' . $dir + . ' (check prepare-be-builder-dirs.sh: builds/ must be writable by PHP-FPM user nobody)', + null + ); + return BuildRepository::getById($id) ?? ['id' => $id, 'build_code' => $buildCode, 'status' => 'failed']; } $logPath = $dir . '/build.log'; BuildRepository::update($id, ['log_path' => $logPath]);