mirror of
git://f0xx.org/ac/ac-ms-build
synced 2026-08-12 18:13:16 +03:00
Builder: docker home env + Gitea CI webhook status.
Export HOME/DOCKER_CONFIG for nobody PHP-FPM, improve docker health checks, and report build status to Gitea when enabled. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -16,15 +16,31 @@ final class BuildRunner {
|
||||
return $which !== '' ? $which : 'docker';
|
||||
}
|
||||
|
||||
/** Writable HOME for docker CLI when PHP-FPM runs as nobody (default HOME=/). */
|
||||
public static function dockerHomeDir(): string {
|
||||
$home = trim((string) cfg('build.docker_home', '/var/www/ac/broadcast'));
|
||||
return $home !== '' ? rtrim($home, '/') : '/var/www/ac/broadcast';
|
||||
}
|
||||
|
||||
public static function dockerEnvPrefix(): string {
|
||||
$home = self::dockerHomeDir();
|
||||
$config = $home . '/.docker';
|
||||
if (!is_dir($config)) {
|
||||
@mkdir($config, 0775, true);
|
||||
}
|
||||
return 'HOME=' . escapeshellarg($home) . ' DOCKER_CONFIG=' . escapeshellarg($config) . ' ';
|
||||
}
|
||||
|
||||
public static function dockerAvailable(): bool {
|
||||
$bin = escapeshellarg(self::dockerBinary());
|
||||
return trim((string) shell_exec("{$bin} info >/dev/null 2>&1 && echo ok")) === 'ok';
|
||||
$env = self::dockerEnvPrefix();
|
||||
return trim((string) shell_exec("{$env}{$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];
|
||||
$parts = ['bin=' . $bin, 'home=' . self::dockerHomeDir()];
|
||||
if (!is_executable($bin)) {
|
||||
$parts[] = 'bin_not_executable';
|
||||
}
|
||||
@@ -143,7 +159,11 @@ YAML;
|
||||
));
|
||||
$mobileSub = trim((string) cfg('build.mobile_subdir', 'ac-mobile-android'));
|
||||
$scriptsDir = trim((string) cfg('build.scripts_dir', dirname((string) cfg('build.runner_script', ''))));
|
||||
$dockerHome = self::dockerHomeDir();
|
||||
$env = [
|
||||
'HOME=' . escapeshellarg($dockerHome),
|
||||
'DOCKER_CONFIG=' . escapeshellarg($dockerHome . '/.docker'),
|
||||
'BUILDER_HOME=' . escapeshellarg($dockerHome),
|
||||
'BUILD_ID=' . $id,
|
||||
'BUILD_LOG_FILE=' . escapeshellarg($logPath),
|
||||
'BUILD_LOG_STDOUT_ONLY=1',
|
||||
@@ -189,7 +209,65 @@ YAML;
|
||||
'started_at' => gmdate('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
return BuildRepository::getById($id) ?? ['id' => $id, 'build_code' => $buildCode];
|
||||
$build = BuildRepository::getById($id) ?? ['id' => $id, 'build_code' => $buildCode];
|
||||
if (GiteaCiStatus::isEnabled() && !empty($params['git_sha'])) {
|
||||
GiteaCiStatus::reportForBuild($build, 'pending', 'Build running');
|
||||
}
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/** Cancel queued/running builds for the same branch (superseded by a newer push). */
|
||||
public static function cancelSupersededForBranch(string $branch): void {
|
||||
$branch = trim($branch);
|
||||
if ($branch === '') {
|
||||
return;
|
||||
}
|
||||
foreach (BuildRepository::listActiveForBranch($branch) as $id) {
|
||||
$build = BuildRepository::getById($id);
|
||||
if (!$build) {
|
||||
continue;
|
||||
}
|
||||
self::stopBuild($id);
|
||||
if (GiteaCiStatus::isEnabled()) {
|
||||
GiteaCiStatus::reportForBuild($build, 'error', 'Superseded by newer commit');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $payload Gitea push webhook JSON */
|
||||
public static function enqueueFromWebhook(array $payload): array {
|
||||
$ref = (string) ($payload['ref'] ?? '');
|
||||
$after = (string) ($payload['after'] ?? '');
|
||||
if ($after === '' || str_starts_with($after, '0000000')) {
|
||||
throw new InvalidArgumentException('empty_or_delete_push');
|
||||
}
|
||||
$branch = str_starts_with($ref, 'refs/heads/') ? substr($ref, 11) : $ref;
|
||||
if ($branch === '') {
|
||||
throw new InvalidArgumentException('missing_branch');
|
||||
}
|
||||
$repo = is_array($payload['repository'] ?? null) ? $payload['repository'] : [];
|
||||
$fullName = (string) ($repo['full_name'] ?? cfg('build.gitea_default_repo', 'ac/ac-mobile-android'));
|
||||
[$owner, $repoName] = array_pad(explode('/', $fullName, 2), 2, 'ac-mobile-android');
|
||||
self::cancelSupersededForBranch($branch);
|
||||
$params = [
|
||||
'git_ref' => $branch,
|
||||
'git_sha' => $after,
|
||||
'branch' => $branch,
|
||||
'trigger_source' => 'ci',
|
||||
'gitea_owner' => $owner !== '' ? $owner : 'ac',
|
||||
'gitea_repo' => $repoName,
|
||||
'run_tests' => true,
|
||||
'run_native' => true,
|
||||
'run_apk' => true,
|
||||
'auto_ota' => false,
|
||||
'notify_on_fail' => true,
|
||||
];
|
||||
$build = self::enqueue($params, null);
|
||||
if (GiteaCiStatus::isEnabled()) {
|
||||
GiteaCiStatus::reportForBuild($build, 'pending', 'Build queued');
|
||||
}
|
||||
return $build;
|
||||
}
|
||||
|
||||
public static function failBuild(int $id, string $message, ?string $logPath = null): void {
|
||||
@@ -205,6 +283,9 @@ YAML;
|
||||
]);
|
||||
$build = BuildRepository::getById($id);
|
||||
if ($build) {
|
||||
if (GiteaCiStatus::isEnabled()) {
|
||||
GiteaCiStatus::reportForBuild($build, 'failure', substr($safe, 0, 120));
|
||||
}
|
||||
BuildNotifier::onFailure($id, $build, $safe);
|
||||
}
|
||||
}
|
||||
@@ -544,8 +625,15 @@ YAML;
|
||||
);
|
||||
}
|
||||
BuildRepository::update($buildId, $update);
|
||||
$build = BuildRepository::getById($buildId);
|
||||
if ($build && GiteaCiStatus::isEnabled()) {
|
||||
if ($status === 'passed') {
|
||||
GiteaCiStatus::reportForBuild($build, 'success', 'Build passed');
|
||||
} else {
|
||||
GiteaCiStatus::reportForBuild($build, 'failure', 'Build failed');
|
||||
}
|
||||
}
|
||||
if ($status === 'failed') {
|
||||
$build = BuildRepository::getById($buildId);
|
||||
if ($build) {
|
||||
BuildNotifier::onFailure($buildId, $build, (string) ($update['error_message'] ?? 'Build failed'));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user