controlServer; if (! $server instanceof Server) { throw new RuntimeException('A control/build server is required to prune the managed registry.'); } $activeBuilds = $registry->organisation->applications() ->whereHas('environments.buildArtifacts', fn ($query) => $query ->where('status', BuildArtifactStatus::BUILDING) ->where('registry_ref', 'like', rtrim((string) $registry->url, '/').'/%')) ->exists(); if ($activeBuilds) { throw new RuntimeException('Managed registry pruning cannot run while builds are active.'); } $this->retention->markPrunable($registry); $artifacts = $this->prunableArtifacts($registry); $maintenance = $this->scripts->maintenance($registry, $artifacts); $operation = $server->operations()->create([ 'kind' => OperationKind::REGISTRY_MAINTENANCE, 'status' => OperationStatus::PENDING, 'metadata' => [ 'registry_id' => $registry->id, 'artifact_ids' => $artifacts->pluck('id')->values()->all(), ], ]); $operation->steps()->create([ 'name' => 'Delete prunable manifests and run registry GC', 'order' => 1, 'status' => OperationStatus::PENDING, 'script' => $maintenance['script'], 'secrets' => $maintenance['secrets'], ]); return $operation->refresh(); } /** * @return \Illuminate\Support\Collection */ private function prunableArtifacts(Registry $registry): \Illuminate\Support\Collection { return $registry->organisation->applications() ->with(['environments.buildArtifacts' => fn ($query) => $query ->where('status', BuildArtifactStatus::PRUNABLE) ->where('registry_ref', 'like', rtrim((string) $registry->url, '/').'/%')]) ->get() ->flatMap(fn ($application) => $application->environments) ->flatMap(fn ($environment) => $environment->buildArtifacts) ->values(); } }