mirror of
git://f0xx.org/android_cast
synced 2026-07-29 03:38:52 +03:00
sync BE
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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')),
|
||||
|
||||
@@ -14,6 +14,13 @@ if ($pipelineYaml === '') {
|
||||
· <span class="error-text"><?= h($build['error_message']) ?></span>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<?php
|
||||
$healthDocker = ($health['docker'] ?? '') === 'ok';
|
||||
$dockerFail = str_contains((string) ($build['error_message'] ?? ''), 'Docker daemon not available');
|
||||
if ($status === 'failed' && $dockerFail && $healthDocker):
|
||||
?>
|
||||
<p class="muted graphs-footnote">Ecosystem health reports <strong>Docker: ok</strong> now. The log below is from this failed run — use <strong>Re-run</strong> (do not only refresh).</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="build-actions card card--lift" style="margin-bottom:12px">
|
||||
<h2>Actions</h2>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
# ./scripts/docker-build-runner.sh --build-id 42 --workdir /path/to/repo
|
||||
#
|
||||
# Env: see ci-build-and-publish-ota.sh
|
||||
# When invoked from PHP (BUILD_LOG_STDOUT_ONLY=1), log via stdout only — parent redirects to build.log.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
@@ -14,27 +15,49 @@ BUILD_ID="${BUILD_ID:-local}"
|
||||
LOG_FILE="${BUILD_LOG_FILE:-${ROOT}/out/builds/${BUILD_ID}/build.log}"
|
||||
WORK_DIR="${BUILD_WORK_DIR:-${ROOT}}"
|
||||
OUT_DIR="${BUILD_OUT_DIR:-${WORK_DIR}/out/builds/${BUILD_ID}}"
|
||||
LOG_STDOUT_ONLY="${BUILD_LOG_STDOUT_ONLY:-0}"
|
||||
|
||||
mkdir -p "$(dirname "$LOG_FILE")" "$OUT_DIR"
|
||||
|
||||
echo "[runner] image=${IMAGE} ci_version=${CI_VERSION} build_id=${BUILD_ID}" | tee -a "$LOG_FILE"
|
||||
echo "[runner] workdir=${WORK_DIR} out=${OUT_DIR}" | tee -a "$LOG_FILE"
|
||||
log() {
|
||||
if [[ "$LOG_STDOUT_ONLY" == "1" ]]; then
|
||||
echo "$@"
|
||||
else
|
||||
echo "$@" | tee -a "$LOG_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
run_logged() {
|
||||
if [[ "$LOG_STDOUT_ONLY" == "1" ]]; then
|
||||
"$@"
|
||||
else
|
||||
"$@" 2>&1 | tee -a "$LOG_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Git 2.35+ refuses repos owned by another uid (PHP-FPM nginx vs deploy user).
|
||||
git_safe() {
|
||||
git -c safe.directory="${WORK_DIR}" "$@"
|
||||
}
|
||||
|
||||
log "[runner] image=${IMAGE} ci_version=${CI_VERSION} build_id=${BUILD_ID}"
|
||||
log "[runner] workdir=${WORK_DIR} out=${OUT_DIR}"
|
||||
|
||||
if [[ -n "${GIT_REF:-}" ]] && [[ -d "${WORK_DIR}/.git" ]]; then
|
||||
echo "[runner] syncing git ref=${GIT_REF}" | tee -a "$LOG_FILE"
|
||||
git -C "${WORK_DIR}" fetch origin --prune 2>&1 | tee -a "$LOG_FILE" || true
|
||||
git -C "${WORK_DIR}" checkout "${GIT_REF}" 2>&1 | tee -a "$LOG_FILE" || true
|
||||
git -C "${WORK_DIR}" pull --rebase origin "${GIT_REF}" 2>&1 | tee -a "$LOG_FILE" || true
|
||||
git -C "${WORK_DIR}" rev-parse HEAD 2>&1 | tee -a "$LOG_FILE" || true
|
||||
log "[runner] syncing git ref=${GIT_REF}"
|
||||
run_logged git_safe -C "${WORK_DIR}" fetch origin --prune || true
|
||||
run_logged git_safe -C "${WORK_DIR}" checkout "${GIT_REF}"
|
||||
run_logged git_safe -C "${WORK_DIR}" pull --rebase origin "${GIT_REF}" || true
|
||||
run_logged git_safe -C "${WORK_DIR}" rev-parse HEAD
|
||||
fi
|
||||
|
||||
docker build \
|
||||
run_logged docker build \
|
||||
--build-arg ANDROIDCAST_CI_VERSION="${CI_VERSION}" \
|
||||
-t "$IMAGE" \
|
||||
-f "${ROOT}/Dockerfile" \
|
||||
"${ROOT}" 2>&1 | tee -a "$LOG_FILE"
|
||||
"${ROOT}"
|
||||
|
||||
docker run --rm \
|
||||
run_logged docker run --rm \
|
||||
-v "${WORK_DIR}:/workspace" \
|
||||
-v "${ROOT}/out:/workspace/out" \
|
||||
-w /workspace \
|
||||
@@ -50,6 +73,6 @@ docker run --rm \
|
||||
-e GIT_SHA="${GIT_SHA:-}" \
|
||||
-e RELEASE_NOTES="${RELEASE_NOTES:-}" \
|
||||
"$IMAGE" \
|
||||
./scripts/ci-build-and-publish-ota.sh 2>&1 | tee -a "$LOG_FILE"
|
||||
./scripts/ci-build-and-publish-ota.sh
|
||||
|
||||
echo "[runner] finished build_id=${BUILD_ID}" | tee -a "$LOG_FILE"
|
||||
log "[runner] finished build_id=${BUILD_ID}"
|
||||
|
||||
Reference in New Issue
Block a user