diff --git a/examples/build_console/backend/config/config.example.php b/examples/build_console/backend/config/config.example.php index 30f42c0..62c55aa 100644 --- a/examples/build_console/backend/config/config.example.php +++ b/examples/build_console/backend/config/config.example.php @@ -24,6 +24,7 @@ return [ ], 'build' => [ 'docker_image' => 'androidcast-ci:latest', + 'docker_bin' => '/usr/bin/docker', 'ci_version' => '00.01.00.1000', 'repo_root' => '/workspace', 'artifacts_root' => '/workspace/out/builds', diff --git a/examples/build_console/backend/public/index.php b/examples/build_console/backend/public/index.php index 817dde9..03698bb 100644 --- a/examples/build_console/backend/public/index.php +++ b/examples/build_console/backend/public/index.php @@ -74,6 +74,7 @@ if ($view === 'build' && isset($_GET['id'])) { BuildRunner::finalizeFromArtifacts((int) $build['id']); $build = BuildRepository::getById((int) $_GET['id']); } + $health = BuildRepository::healthSummary(); $view = 'build'; $pageTitle = 'Build ' . ($build['build_code'] ?? ''); require __DIR__ . '/../views/layout.php'; diff --git a/examples/build_console/backend/src/BuildRepository.php b/examples/build_console/backend/src/BuildRepository.php index 914c04b..c4c6868 100644 --- a/examples/build_console/backend/src/BuildRepository.php +++ b/examples/build_console/backend/src/BuildRepository.php @@ -116,7 +116,7 @@ SQL); $running = (int) $pdo->query("SELECT COUNT(*) FROM builds WHERE status = 'running'")->fetchColumn(); $failed = (int) $pdo->query("SELECT COUNT(*) FROM builds WHERE status = 'failed' AND created_at > (NOW() - INTERVAL 7 DAY)")->fetchColumn(); $passed = (int) $pdo->query("SELECT COUNT(*) FROM builds WHERE status = 'passed' AND created_at > (NOW() - INTERVAL 7 DAY)")->fetchColumn(); - $dockerOk = trim((string) shell_exec('docker info >/dev/null 2>&1 && echo ok')) === 'ok'; + $dockerOk = BuildRunner::dockerAvailable(); return [ 'docker' => $dockerOk ? 'ok' : 'down', 'running' => $running, diff --git a/examples/build_console/backend/src/BuildRunner.php b/examples/build_console/backend/src/BuildRunner.php index c6ad85e..7a6ca93 100644 --- a/examples/build_console/backend/src/BuildRunner.php +++ b/examples/build_console/backend/src/BuildRunner.php @@ -2,8 +2,37 @@ declare(strict_types=1); final class BuildRunner { + public static function dockerBinary(): string { + $configured = trim((string) cfg('build.docker_bin', '')); + if ($configured !== '' && is_executable($configured)) { + return $configured; + } + foreach (['/usr/bin/docker', '/usr/local/bin/docker'] as $path) { + if (is_executable($path)) { + return $path; + } + } + $which = trim((string) shell_exec('command -v docker 2>/dev/null')); + return $which !== '' ? $which : 'docker'; + } + public static function dockerAvailable(): bool { - return trim((string) shell_exec('docker info >/dev/null 2>&1 && echo ok')) === 'ok'; + $bin = escapeshellarg(self::dockerBinary()); + return trim((string) shell_exec("{$bin} info >/dev/null 2>&1 && echo ok")) === 'ok'; + } + + public static function dockerCheckDetail(): string { + $bin = self::dockerBinary(); + $sock = '/var/run/docker.sock'; + $parts = ['bin=' . $bin]; + if (!is_executable($bin)) { + $parts[] = 'bin_not_executable'; + } + if (!is_readable($sock)) { + $parts[] = 'sock_not_readable'; + } + $parts[] = self::dockerAvailable() ? 'info_ok' : 'info_failed'; + return implode(', ', $parts); } public static function generateBuildCode(): string { @@ -91,7 +120,13 @@ YAML; BuildRepository::update($id, ['log_path' => $logPath]); if (!self::dockerAvailable()) { - self::failBuild($id, 'Docker daemon not available', $logPath); + $detail = self::dockerCheckDetail(); + self::failBuild( + $id, + 'Docker daemon not available (' . $detail . '). ' + . 'Ensure docker service is running and PHP-FPM user (nginx) is in group docker, then restart php-fpm.', + $logPath + ); return BuildRepository::getById($id) ?? ['id' => $id, 'build_code' => $buildCode, 'status' => 'failed']; } @@ -106,6 +141,7 @@ YAML; $env = [ 'BUILD_ID=' . $id, 'BUILD_LOG_FILE=' . escapeshellarg($logPath), + 'BUILD_LOG_STDOUT_ONLY=1', 'BUILD_WORK_DIR=' . escapeshellarg($repo), 'BUILD_OUT_DIR=' . escapeshellarg($dir), 'ANDROIDCAST_CI_VERSION=' . escapeshellarg((string) cfg('build.ci_version', '00.01.00.1000')), diff --git a/examples/build_console/backend/views/build_detail.php b/examples/build_console/backend/views/build_detail.php index fdc7f34..775b5cb 100644 --- a/examples/build_console/backend/views/build_detail.php +++ b/examples/build_console/backend/views/build_detail.php @@ -14,6 +14,13 @@ if ($pipelineYaml === '') { · = h($build['error_message']) ?>
+ +Ecosystem health reports Docker: ok now. The log below is from this failed run — use Re-run (do not only refresh).
+