208 lines
8.2 KiB
PHP
208 lines
8.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Actions\Applications\CreateLaravelEnvironment;
|
|
use App\Enums\BuildStrategy;
|
|
use App\Enums\EnvironmentAttachmentRole;
|
|
use App\Enums\SchedulerMode;
|
|
use App\Enums\ServiceType;
|
|
use App\Http\Requests\StoreEnvironmentRequest;
|
|
use App\Http\Requests\UpdateEnvironmentRequest;
|
|
use App\Models\Environment;
|
|
use App\Models\Organisation;
|
|
use App\Support\CaddyRouteRenderer;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Collection;
|
|
use Inertia\Response;
|
|
|
|
class EnvironmentController extends Controller
|
|
{
|
|
public function create(Request $request): Response
|
|
{
|
|
$organisation = Organisation::findOrFail($request->route('organisation'));
|
|
$application = $organisation->applications()->findOrFail($request->route('application'));
|
|
|
|
return inertia('environments/Create', [
|
|
'application' => $application,
|
|
]);
|
|
}
|
|
|
|
public function store(StoreEnvironmentRequest $request): RedirectResponse
|
|
{
|
|
$organisation = Organisation::findOrFail($request->route('organisation'));
|
|
$application = $organisation->applications()->findOrFail($request->route('application'));
|
|
|
|
$environment = app(CreateLaravelEnvironment::class)->execute(
|
|
application: $application,
|
|
name: $request->string('name')->toString(),
|
|
branch: $request->string('branch')->toString(),
|
|
phpVersion: $request->string('php_version')->toString(),
|
|
);
|
|
|
|
return redirect()
|
|
->route('environments.show', [
|
|
'organisation' => $organisation->id,
|
|
'application' => $application->id,
|
|
'environment' => $environment->id,
|
|
])
|
|
->with('success', 'Environment created.');
|
|
}
|
|
|
|
public function show(Request $request): Response
|
|
{
|
|
$organisation = Organisation::findOrFail($request->route('organisation'));
|
|
$application = $organisation->applications()->findOrFail($request->route('application'));
|
|
$environment = $application->environments()
|
|
->with([
|
|
'services.replicas',
|
|
'services.endpoints',
|
|
'services.slices',
|
|
'services.operations.steps',
|
|
'attachments.service',
|
|
'attachments.serviceSlice',
|
|
'variables',
|
|
'buildArtifacts.builtByService',
|
|
'operations.steps',
|
|
'operations.children.target',
|
|
])
|
|
->findOrFail($request->route('environment'));
|
|
|
|
$serverCount = $this->serverIdsFor($environment)->count();
|
|
|
|
return inertia('environments/Show', [
|
|
'application' => $application,
|
|
'environment' => $environment,
|
|
'deploymentRequirements' => [
|
|
'registryRequired' => $organisation->registries()->doesntExist() && $serverCount > 1,
|
|
'registryCount' => $organisation->registries()->count(),
|
|
'serverCount' => $serverCount,
|
|
],
|
|
'gatewayRoutePreviews' => $this->gatewayRoutePreviews($environment),
|
|
]);
|
|
}
|
|
|
|
public function edit(Request $request): Response
|
|
{
|
|
$organisation = Organisation::findOrFail($request->route('organisation'));
|
|
$application = $organisation->applications()->findOrFail($request->route('application'));
|
|
$environment = $application->environments()
|
|
->with('services')
|
|
->findOrFail($request->route('environment'));
|
|
|
|
return inertia('environments/Edit', [
|
|
'application' => $application,
|
|
'environment' => $environment,
|
|
'schedulerModes' => array_values(SchedulerMode::toArray()),
|
|
'buildStrategies' => array_values(BuildStrategy::toArray()),
|
|
]);
|
|
}
|
|
|
|
public function update(UpdateEnvironmentRequest $request): RedirectResponse
|
|
{
|
|
$organisation = Organisation::findOrFail($request->route('organisation'));
|
|
$application = $organisation->applications()->findOrFail($request->route('application'));
|
|
$environment = $application->environments()
|
|
->with('services')
|
|
->findOrFail($request->route('environment'));
|
|
|
|
$schedulerTargetServiceId = $request->integer('scheduler_target_service_id') ?: null;
|
|
|
|
if ($schedulerTargetServiceId !== null) {
|
|
abort_unless($environment->services()->whereKey($schedulerTargetServiceId)->exists(), 422);
|
|
}
|
|
|
|
$environment->update([
|
|
'name' => $request->string('name')->toString(),
|
|
'branch' => $request->string('branch')->toString(),
|
|
'status' => $request->string('status')->toString(),
|
|
'scheduler_enabled' => $request->boolean('scheduler_enabled'),
|
|
'scheduler_target_service_id' => $schedulerTargetServiceId,
|
|
'scheduler_mode' => $request->enum('scheduler_mode', SchedulerMode::class),
|
|
'build_config' => [
|
|
...($environment->build_config ?? []),
|
|
'build_strategy' => $request->enum('build_strategy', BuildStrategy::class)?->value,
|
|
'php_version' => $request->string('php_version')->toString(),
|
|
'document_root' => $request->string('document_root')->toString(),
|
|
'health_path' => $request->string('health_path')->toString(),
|
|
'js_package_manager' => $request->string('js_package_manager')->toString(),
|
|
'js_build_command' => $request->filled('js_build_command')
|
|
? $request->string('js_build_command')->toString()
|
|
: null,
|
|
],
|
|
]);
|
|
|
|
return redirect()
|
|
->route('environments.show', [
|
|
'organisation' => $organisation->id,
|
|
'application' => $application->id,
|
|
'environment' => $environment->id,
|
|
])
|
|
->with('success', 'Environment updated.');
|
|
}
|
|
|
|
public function destroy(Request $request): RedirectResponse
|
|
{
|
|
$organisation = Organisation::findOrFail($request->route('organisation'));
|
|
$application = $organisation->applications()->findOrFail($request->route('application'));
|
|
$environment = $application->environments()->findOrFail($request->route('environment'));
|
|
|
|
$environment->delete();
|
|
|
|
return redirect()
|
|
->route('applications.show', [
|
|
'organisation' => $organisation->id,
|
|
'application' => $application->id,
|
|
])
|
|
->with('success', 'Environment deleted.');
|
|
}
|
|
|
|
/**
|
|
* @return \Illuminate\Support\Collection<int, int>
|
|
*/
|
|
private function serverIdsFor(Environment $environment): Collection
|
|
{
|
|
return $environment->services
|
|
->flatMap(fn ($service) => [
|
|
$service->server_id,
|
|
...$service->replicas->pluck('server_id')->all(),
|
|
])
|
|
->filter()
|
|
->unique()
|
|
->values();
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, array{attachment_id: int, caddyfile: string}>
|
|
*/
|
|
private function gatewayRoutePreviews(Environment $environment): Collection
|
|
{
|
|
$upstreams = $this->previewGatewayUpstreams($environment);
|
|
$renderer = app(CaddyRouteRenderer::class);
|
|
|
|
return $environment->attachments
|
|
->filter(fn ($attachment): bool => $attachment->role === EnvironmentAttachmentRole::GATEWAY)
|
|
->map(fn ($attachment): array => [
|
|
'attachment_id' => $attachment->id,
|
|
'caddyfile' => $renderer->render($attachment, $upstreams),
|
|
])
|
|
->values();
|
|
}
|
|
|
|
/**
|
|
* @return array<int, string>
|
|
*/
|
|
private function previewGatewayUpstreams(Environment $environment): array
|
|
{
|
|
return $environment->services
|
|
->filter(fn ($service): bool => $service->type === ServiceType::LARAVEL && in_array('web', $service->process_roles ?? [], true))
|
|
->flatMap(fn ($service) => $service->replicas->map(
|
|
fn ($replica): string => ($replica->internal_host ?: $replica->container_name).':'.($replica->internal_port ?: 80)
|
|
))
|
|
->values()
|
|
->whenEmpty(fn ($upstreams) => $upstreams->push('web:80'))
|
|
->all();
|
|
}
|
|
}
|