coolify/app/Models/GithubRunnerConfig.php
Andras Bacsai 5c50ab6162 feat(github-runners): improve runner lifecycle and GitHub sync
Add runner execution observability and lifecycle hardening for self-hosted
GitHub Actions runners, including:
- scheduled artifact cleanup job for cached runner tarballs/templates
- workflow_job in_progress handling to mark executions as running
- safer cleanup failure handling and non-functional server fallback
- persisted workflow job HTML URLs with execution "Open" links in UI
- configurable runner group name sync (UI + provisioning + GitHub API)
- webhook events persistence and auto-fix for missing required events
- strict enum/status checks and related model cast/query improvements

Also includes migrations and expanded feature/unit coverage for webhook,
provisioning, cleanup, and runner group/event sync behaviors.
2026-03-03 22:21:13 +01:00

70 lines
1.8 KiB
PHP

<?php
namespace App\Models;
use App\Enums\GithubRunnerStatus;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
class GithubRunnerConfig extends BaseModel
{
protected $guarded = [];
protected function casts(): array
{
return [
'labels' => 'array',
'is_enabled' => 'boolean',
'max_runners' => 'integer',
'capacity_wait_timeout' => 'integer',
];
}
public function organization(): Attribute
{
return Attribute::make(
get: fn () => $this->githubApp?->organization,
);
}
public function server(): BelongsTo
{
return $this->belongsTo(Server::class);
}
public function githubApp(): BelongsTo
{
return $this->belongsTo(GithubApp::class);
}
public function executions(): HasMany
{
return $this->hasMany(GithubRunnerExecution::class);
}
public function activeRunnerCount(): int
{
return $this->executions()
->whereIn('status', [
GithubRunnerStatus::Queued->value,
GithubRunnerStatus::Provisioning->value,
GithubRunnerStatus::Running->value,
GithubRunnerStatus::Cleaning->value,
])
->count();
}
public function hasCapacity(): bool
{
return $this->activeRunnerCount() < $this->max_runners;
}
public function matchesLabels(array $requestedLabels): bool
{
$configLabels = collect($this->labels)->map(fn ($l) => strtolower($l));
return collect($requestedLabels)
->every(fn ($label) => $configLabels->contains(strtolower($label)));
}
}