testing php storm code cleanup and styling

This commit is contained in:
Andras Bacsai 2023-08-08 11:51:36 +02:00
parent a8ee779b31
commit f2228cec7b
368 changed files with 23834 additions and 2623 deletions

View File

@ -15,6 +15,7 @@ class PrepareCoolifyTask
{
protected Activity $activity;
protected CoolifyTaskArgs $remoteProcessArgs;
public function __construct(CoolifyTaskArgs $remoteProcessArgs)
{
$this->remoteProcessArgs = $remoteProcessArgs;

View File

@ -49,6 +49,28 @@ public function __construct(Activity $activity, bool $hide_from_output = false,
$this->ignore_errors = $ignore_errors;
}
public static function decodeOutput(?Activity $activity = null): string
{
if (is_null($activity)) {
return '';
}
try {
$decoded = json_decode(
data_get($activity, 'description'),
associative: true,
flags: JSON_THROW_ON_ERROR
);
} catch (\JsonException $exception) {
return '';
}
return collect($decoded)
->sortBy(fn($i) => $i['order'])
->map(fn($i) => $i['output'])
->implode("");
}
public function __invoke(): ProcessResult
{
$this->time_start = hrtime(true);
@ -83,15 +105,6 @@ public function __invoke(): ProcessResult
return $processResult;
}
protected function getLatestCounter(): int
{
$description = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR);
if ($description === null || count($description) === 0) {
return 1;
}
return end($description)['order'] + 1;
}
protected function getCommand(): string
{
$user = $this->activity->getExtraProperty('user');
@ -120,6 +133,13 @@ protected function handleOutput(string $type, string $output)
}
}
protected function elapsedTime(): int
{
$timeMs = (hrtime(true) - $this->time_start) / 1_000_000;
return intval($timeMs);
}
public function encodeOutput($type, $output)
{
$outputStack = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR);
@ -135,26 +155,13 @@ public function encodeOutput($type, $output)
return json_encode($outputStack, flags: JSON_THROW_ON_ERROR);
}
public static function decodeOutput(?Activity $activity = null): string
protected function getLatestCounter(): int
{
if (is_null($activity)) {
return '';
$description = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR);
if ($description === null || count($description) === 0) {
return 1;
}
try {
$decoded = json_decode(
data_get($activity, 'description'),
associative: true,
flags: JSON_THROW_ON_ERROR
);
} catch (\JsonException $exception) {
return '';
}
return collect($decoded)
->sortBy(fn ($i) => $i['order'])
->map(fn ($i) => $i['output'])
->implode("");
return end($description)['order'] + 1;
}
/**
@ -171,11 +178,4 @@ protected function isAfterLastThrottle()
return ($this->current_time - $this->throttle_interval_ms) > $this->last_write_at;
}
protected function elapsedTime(): int
{
$timeMs = (hrtime(true) - $this->time_start) / 1_000_000;
return intval($timeMs);
}
}

View File

@ -3,15 +3,14 @@
namespace App\Actions\Database;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\Team;
use App\Models\StandalonePostgresql;
use Symfony\Component\Yaml\Yaml;
use Illuminate\Support\Str;
use Symfony\Component\Yaml\Yaml;
class StartPostgresql
{
public $database;
public function __invoke(Server $server, StandalonePostgresql $database)
{
$this->database = $database;
@ -83,28 +82,7 @@ public function __invoke(Server $server, StandalonePostgresql $database)
], $server);
return $activity;
}
private function generate_environment_variables()
{
$environment_variables = collect();
ray('Generate Environment Variables')->green();
ray($this->database->runtime_environment_variables)->green();
foreach ($this->database->runtime_environment_variables as $env) {
$environment_variables->push("$env->key=$env->value");
}
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_USER'))->isEmpty()) {
$environment_variables->push("POSTGRES_USER={$this->database->postgres_user}");
}
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_PASSWORD'))->isEmpty()) {
$environment_variables->push("POSTGRES_PASSWORD={$this->database->postgres_password}");
}
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('POSTGRES_DB'))->isEmpty()) {
$environment_variables->push("POSTGRES_DB={$this->database->postgres_db}");
}
return $environment_variables->all();
}
private function generate_local_persistent_volumes()
{
$local_persistent_volumes = [];
@ -114,6 +92,7 @@ private function generate_local_persistent_volumes()
}
return $local_persistent_volumes;
}
private function generate_local_persistent_volumes_only_volume_names()
{
$local_persistent_volumes_names = [];
@ -129,4 +108,27 @@ private function generate_local_persistent_volumes_only_volume_names()
}
return $local_persistent_volumes_names;
}
private function generate_environment_variables()
{
$environment_variables = collect();
ray('Generate Environment Variables')->green();
ray($this->database->runtime_environment_variables)->green();
foreach ($this->database->runtime_environment_variables as $env) {
$environment_variables->push("$env->key=$env->value");
}
if ($environment_variables->filter(fn($env) => Str::of($env)->contains('POSTGRES_USER'))->isEmpty()) {
$environment_variables->push("POSTGRES_USER={$this->database->postgres_user}");
}
if ($environment_variables->filter(fn($env) => Str::of($env)->contains('POSTGRES_PASSWORD'))->isEmpty()) {
$environment_variables->push("POSTGRES_PASSWORD={$this->database->postgres_password}");
}
if ($environment_variables->filter(fn($env) => Str::of($env)->contains('POSTGRES_DB'))->isEmpty()) {
$environment_variables->push("POSTGRES_DB={$this->database->postgres_db}");
}
return $environment_variables->all();
}
}

View File

@ -3,11 +3,8 @@
namespace App\Actions\Fortify;
use App\Models\InstanceSettings;
use App\Models\Team;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Laravel\Fortify\Contracts\CreatesNewUsers;
@ -19,7 +16,7 @@ class CreateNewUser implements CreatesNewUsers
/**
* Validate and create a newly registered user.
*
* @param array<string, string> $input
* @param array<string, string> $input
*/
public function create(array $input): User
{

View File

@ -14,7 +14,7 @@ class ResetUserPassword implements ResetsUserPasswords
/**
* Validate and reset the user's forgotten password.
*
* @param array<string, string> $input
* @param array<string, string> $input
*/
public function reset(User $user, array $input): void
{

View File

@ -14,7 +14,7 @@ class UpdateUserPassword implements UpdatesUserPasswords
/**
* Validate and update the user's password.
*
* @param array<string, string> $input
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{

View File

@ -13,7 +13,7 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
/**
* Validate and update the given user's profile information.
*
* @param array<string, string> $input
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{
@ -43,7 +43,7 @@ public function update(User $user, array $input): void
/**
* Update the given verified user's profile information.
*
* @param array<string, string> $input
* @param array<string, string> $input
*/
protected function updateVerifiedUser(User $user, array $input): void
{

View File

@ -2,8 +2,6 @@
namespace App\Actions\Proxy;
use App\Actions\Proxy\SaveConfigurationSync;
use App\Enums\ProxyTypes;
use App\Models\Server;
use Illuminate\Support\Str;
@ -25,4 +23,4 @@ public function __invoke(Server $server, bool $reset = false)
return $proxy_configuration;
}
}
}

View File

@ -2,12 +2,11 @@
namespace App\Actions\Proxy;
use App\Actions\Proxy\CheckConfigurationSync;
use App\Enums\ProxyStatus;
use App\Enums\ProxyTypes;
use App\Models\Server;
use Spatie\Activitylog\Models\Activity;
use Illuminate\Support\Str;
use Spatie\Activitylog\Models\Activity;
class StartProxy
{
@ -54,4 +53,4 @@ public function __invoke(Server $server): Activity
return $activity;
}
}
}

View File

@ -23,7 +23,7 @@ public function __invoke(bool $force)
$this->server = Server::where('name', $localhost_name)->firstOrFail();
$this->latest_version = get_latest_version_of_coolify();
$this->current_version = config('version');
ray('latest version:' . $this->latest_version . " current version: " . $this->current_version . ' force: ' . $force);
ray('latest version:' . $this->latest_version . " current version: " . $this->current_version . ' force: ' . $force);
if ($settings->next_channel) {
ray('next channel enabled');
$this->latest_version = 'next';
@ -49,6 +49,7 @@ public function __invoke(bool $force)
return;
}
}
private function update()
{
if (isDev()) {

View File

@ -10,10 +10,12 @@ class Init extends Command
{
protected $signature = 'app:init';
protected $description = 'Cleanup instance related stuffs';
public function handle()
{
$this->cleanup_in_progress_application_deployments();
}
private function cleanup_in_progress_application_deployments()
{
// Cleanup any failed deployments

View File

@ -64,7 +64,8 @@ private function showHelp()
</ul>
</div>
</div>
HTML);
HTML
);
ask(<<<'HTML'
<div class="mr-1">

View File

@ -4,8 +4,8 @@
use Illuminate\Console\Command;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;
class SyncBunny extends Command
{
@ -64,7 +64,7 @@ public function handle()
]);
});
try {
Http::pool(fn (Pool $pool) => [
Http::pool(fn(Pool $pool) => [
$pool->storage(file: "$parent_dir/$compose_file")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file"),
$pool->storage(file: "$parent_dir/$compose_file_prod")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file_prod"),
$pool->storage(file: "$parent_dir/$production_env")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$production_env"),
@ -73,7 +73,7 @@ public function handle()
$pool->storage(file: "$parent_dir/$versions")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$versions"),
]);
ray("{$bunny_cdn}/{$bunny_cdn_path}");
Http::pool(fn (Pool $pool) => [
Http::pool(fn(Pool $pool) => [
$pool->purge("$bunny_cdn/$bunny_cdn_path/$compose_file"),
$pool->purge("$bunny_cdn/$bunny_cdn_path/$compose_file_prod"),
$pool->purge("$bunny_cdn/$bunny_cdn_path/$production_env"),

View File

@ -2,12 +2,12 @@
namespace App\Console;
use App\Jobs\InstanceApplicationsStatusJob;
use App\Jobs\CheckResaleLicenseJob;
use App\Jobs\CheckResaleLicenseKeys;
use App\Jobs\DockerCleanupJob;
use App\Jobs\InstanceApplicationsStatusJob;
use App\Jobs\InstanceAutoUpdateJob;
use App\Jobs\ProxyCheckJob;
use App\Jobs\DockerCleanupJob;
use App\Jobs\CheckResaleLicenseKeys;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -31,6 +31,7 @@ protected function schedule(Schedule $schedule): void
$schedule->job(new InstanceAutoUpdateJob)->everyTenMinutes();
}
}
protected function commands(): void
{
$this->load(__DIR__ . '/Commands');

View File

@ -22,6 +22,7 @@ public function __construct(
public ?Model $model = null,
public string $status = ProcessStatus::QUEUED->value,
public bool $ignore_errors = false,
) {
)
{
}
}

View File

@ -9,8 +9,9 @@
class ServerMetadata extends Data
{
public function __construct(
public ?ProxyTypes $type,
public ?ProxyTypes $type,
public ?ProxyStatus $status
) {
)
{
}
}

View File

@ -8,6 +8,7 @@ enum ProxyTypes: string
case NGINX = 'NGINX';
case CADDY = 'CADDY';
}
enum ProxyStatus: string
{
case EXITED = 'exited';

View File

@ -4,13 +4,12 @@
use App\Models\InstanceSettings;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
use Sentry\Laravel\Integration;
use Throwable;
class Handler extends ExceptionHandler
{
private InstanceSettings $settings;
/**
* A list of exception types with their corresponding custom log levels.
*
@ -19,7 +18,6 @@ class Handler extends ExceptionHandler
protected $levels = [
//
];
/**
* A list of the exception types that are not reported.
*
@ -28,7 +26,6 @@ class Handler extends ExceptionHandler
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed to the session on validation exceptions.
*
@ -39,6 +36,7 @@ class Handler extends ExceptionHandler
'password',
'password_confirmation',
];
private InstanceSettings $settings;
/**
* Register the exception handling callbacks for the application.

View File

@ -5,12 +5,11 @@
use App\Models\ApplicationDeploymentQueue;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\Request;
use Spatie\Activitylog\Models\Activity;
class ApplicationController extends Controller
{
use AuthorizesRequests, ValidatesRequests;
public function configuration()
{
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
@ -28,6 +27,7 @@ public function configuration()
ray($application->persistentStorages()->get());
return view('project.application.configuration', ['application' => $application]);
}
public function deployments()
{
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();

View File

@ -2,17 +2,15 @@
namespace App\Http\Controllers;
use App\Http\Livewire\Team\Invitations;
use App\Models\InstanceSettings;
use App\Models\Project;
use App\Models\S3Storage;
use App\Models\Server;
use App\Models\TeamInvitation;
use App\Models\User;
use App\Models\S3Storage;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\DB;
class Controller extends BaseController
{
@ -27,6 +25,7 @@ public function subscription()
'settings' => InstanceSettings::get()
]);
}
public function license()
{
if (!isCloud()) {
@ -36,6 +35,7 @@ public function license()
'settings' => InstanceSettings::get()
]);
}
public function dashboard()
{
$projects = Project::ownedByCurrentTeam()->get();
@ -55,6 +55,7 @@ public function dashboard()
's3s' => $s3s,
]);
}
public function settings()
{
if (auth()->user()->isInstanceAdmin()) {
@ -66,6 +67,7 @@ public function settings()
return redirect()->route('dashboard');
}
}
public function emails()
{
if (auth()->user()->isInstanceAdmin()) {
@ -77,6 +79,7 @@ public function emails()
return redirect()->route('dashboard');
}
}
public function team()
{
$invitations = [];
@ -87,18 +90,23 @@ public function team()
'invitations' => $invitations,
]);
}
public function storages() {
public function storages()
{
$s3 = S3Storage::ownedByCurrentTeam()->get();
return view('team.storages.all', [
's3' => $s3,
]);
}
public function storages_show() {
public function storages_show()
{
$storage = S3Storage::ownedByCurrentTeam()->whereUuid(request()->storage_uuid)->firstOrFail();
return view('team.storages.show', [
'storage' => $storage,
]);
}
public function members()
{
$invitations = [];
@ -109,6 +117,7 @@ public function members()
'invitations' => $invitations,
]);
}
public function acceptInvitation()
{
try {
@ -135,6 +144,7 @@ public function acceptInvitation()
throw $th;
}
}
public function revokeInvitation()
{
try {
@ -152,4 +162,4 @@ public function revokeInvitation()
throw $th;
}
}
}
}

View File

@ -2,15 +2,13 @@
namespace App\Http\Controllers;
use App\Models\ApplicationDeploymentQueue;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\Request;
use Spatie\Activitylog\Models\Activity;
class DatabaseController extends Controller
{
use AuthorizesRequests, ValidatesRequests;
public function configuration()
{
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();

View File

@ -2,7 +2,6 @@
namespace App\Http\Controllers;
use App\Http\Livewire\Server\PrivateKey;
use App\Models\Environment;
use App\Models\Project;
use App\Models\Server;
@ -16,24 +15,28 @@ public function servers()
'servers' => Server::isUsable()->get()
]);
}
public function destinations()
{
return response()->json([
'destinations' => Server::destinationsByServer(request()->query('server_id'))->sortBy('name')
]);
}
public function projects()
{
return response()->json([
'projects' => Project::ownedByCurrentTeam()->get()
]);
}
public function environments()
{
return response()->json([
'environments' => Project::ownedByCurrentTeam()->whereUuid(request()->query('project_uuid'))->first()->environments
]);
}
public function newProject()
{
$project = Project::firstOrCreate(
@ -44,6 +47,7 @@ public function newProject()
'project_uuid' => $project->uuid
]);
}
public function newEnvironment()
{
$environment = Environment::firstOrCreate(
@ -54,6 +58,7 @@ public function newEnvironment()
'environment_name' => $environment->name,
]);
}
public function newTeam()
{
$team = Team::create(

View File

@ -25,6 +25,7 @@ public function edit()
}
return view('project.edit', ['project' => $project]);
}
public function show()
{
$projectUuid = request()->route('project_uuid');
@ -55,6 +56,7 @@ public function new()
'type' => $type
]);
}
public function resources()
{
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();

View File

@ -15,12 +15,6 @@ class ActivityMonitor extends Component
protected $activity;
protected $listeners = ['newMonitorActivity'];
public function hydrateActivity()
{
$this->activity = Activity::query()
->find($this->activityId);
}
public function newMonitorActivity($activityId)
{
$this->activityId = $activityId;
@ -30,6 +24,12 @@ public function newMonitorActivity($activityId)
$this->isPollingActive = true;
}
public function hydrateActivity()
{
$this->activity = Activity::query()
->find($this->activityId);
}
public function polling()
{
$this->hydrateActivity();
@ -45,6 +45,7 @@ public function polling()
$this->emit('activityFinished');
}
}
protected function setStatus($status)
{
$this->activity->properties = $this->activity->properties->merge([
@ -52,4 +53,4 @@ protected function setStatus($status)
]);
$this->activity->save();
}
}
}

View File

@ -19,11 +19,13 @@ class CheckLicense extends Component
'instance_id' => 'Instance Id (Do not change this)',
'settings.is_resale_license_active' => 'Is License Active',
];
public function mount()
{
$this->instance_id = config('app.id');
$this->settings = InstanceSettings::get();
}
public function submit()
{
$this->validate();

View File

@ -18,11 +18,13 @@ class Form extends Component
'destination.network' => 'network',
'destination.server.ip' => 'IP Address',
];
public function submit()
{
$this->validate();
$this->destination->save();
}
public function delete()
{
try {

View File

@ -5,9 +5,9 @@
use App\Models\Server;
use App\Models\StandaloneDocker as ModelsStandaloneDocker;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Str;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
use Illuminate\Support\Str;
class StandaloneDocker extends Component
{
@ -28,6 +28,7 @@ class StandaloneDocker extends Component
'network' => 'network',
'server_id' => 'server'
];
public function mount()
{
if (request()->query('server_id')) {
@ -44,15 +45,13 @@ public function mount()
}
$this->name = Str::kebab("{$this->servers->first()->name}-{$this->network}");
}
public function generate_name() {
public function generate_name()
{
$this->server = Server::find($this->server_id);
$this->name = Str::kebab("{$this->server->name}-{$this->network}");
}
private function createNetworkAndAttachToProxy()
{
instant_remote_process(['docker network create --attachable ' . $this->network], $this->server, throwError: false);
instant_remote_process(["docker network connect $this->network coolify-proxy"], $this->server, throwError: false);
}
public function submit()
{
$this->validate();
@ -77,4 +76,10 @@ public function submit()
return general_error_handler(err: $e);
}
}
}
private function createNetworkAndAttachToProxy()
{
instant_remote_process(['docker network create --attachable ' . $this->network], $this->server, throwError: false);
instant_remote_process(["docker network connect $this->network coolify-proxy"], $this->server, throwError: false);
}
}

View File

@ -10,6 +10,7 @@ class Show extends Component
{
public Server $server;
public Collection|array $networks = [];
public function scan()
{
$alreadyAddedNetworks = $this->server->standaloneDockers;

View File

@ -4,33 +4,39 @@
use App\Models\S3Storage;
use Illuminate\Support\Facades\Storage;
use Livewire\WithFileUploads;
use Livewire\Component;
use Livewire\WithFileUploads;
class S3Test extends Component
{
use WithFileUploads;
public $s3;
public $file;
public function mount() {
public function mount()
{
$this->s3 = S3Storage::first();
}
public function save() {
public function save()
{
try {
$this->validate([
'file' => 'required|max:150', // 1MB Max
]);
set_s3_target($this->s3);
$this->file->storeAs('files', $this->file->getClientOriginalName(),'custom-s3');
$this->file->storeAs('files', $this->file->getClientOriginalName(), 'custom-s3');
$this->emit('success', 'File uploaded successfully.');
} catch (\Throwable $th) {
return general_error_handler($th, $this, false);
}
}
public function get_files()
{
set_s3_target($this->s3);
dd(Storage::disk('custom-s3')->files('files'));
}
}
}

View File

@ -19,6 +19,7 @@ class DiscordSettings extends Component
protected $validationAttributes = [
'model.discord_webhook_url' => 'Discord Webhook',
];
public function instantSave()
{
try {
@ -29,6 +30,14 @@ public function instantSave()
$this->validate();
}
}
public function submit()
{
$this->resetErrorBag();
$this->validate();
$this->saveModel();
}
public function saveModel()
{
ray($this->model);
@ -38,15 +47,10 @@ public function saveModel()
}
$this->emit('success', 'Settings saved.');
}
public function submit()
{
$this->resetErrorBag();
$this->validate();
$this->saveModel();
}
public function sendTestNotification()
{
$this->model->notify(new Test);
$this->emit('success', 'Test notification sent.');
}
}
}

View File

@ -37,6 +37,13 @@ class EmailSettings extends Component
'model.smtp_username' => 'Username',
'model.smtp_password' => 'Password',
];
public function mount()
{
$this->decrypt();
$this->emails = auth()->user()->email;
}
private function decrypt()
{
if (data_get($this->model, 'smtp_password')) {
@ -46,11 +53,7 @@ private function decrypt()
}
}
}
public function mount()
{
$this->decrypt();
$this->emails = auth()->user()->email;
}
public function copyFromInstanceSettings()
{
$settings = InstanceSettings::get();
@ -78,6 +81,23 @@ public function copyFromInstanceSettings()
$this->emit('error', 'Instance SMTP settings are not enabled.');
}
}
public function sendTestNotification()
{
$this->model->notify(new Test($this->emails));
$this->emit('success', 'Test Email sent successfully.');
}
public function instantSave()
{
try {
$this->submit();
} catch (\Exception $e) {
$this->model->smtp_enabled = false;
$this->validate();
}
}
public function submit()
{
$this->resetErrorBag();
@ -92,6 +112,7 @@ public function submit()
$this->model->smtp_recipients = str_replace(' ', '', $this->model->smtp_recipients);
$this->saveModel();
}
public function saveModel()
{
$this->model->save();
@ -101,18 +122,4 @@ public function saveModel()
}
$this->emit('success', 'Settings saved.');
}
public function sendTestNotification()
{
$this->model->notify(new Test($this->emails));
$this->emit('success', 'Test Email sent successfully.');
}
public function instantSave()
{
try {
$this->submit();
} catch (\Exception $e) {
$this->model->smtp_enabled = false;
$this->validate();
}
}
}
}

View File

@ -20,6 +20,7 @@ class Change extends Component
'private_key.description' => 'description',
'private_key.private_key' => 'private key'
];
public function delete()
{
try {
@ -33,6 +34,7 @@ public function delete()
return general_error_handler(err: $e, that: $this);
}
}
public function changePrivateKey()
{
try {

View File

@ -19,6 +19,7 @@ class Create extends Component
'name' => 'name',
'value' => 'private Key',
];
public function createPrivateKey()
{
$this->validate();

View File

@ -17,12 +17,14 @@ class Form extends Component
protected $validationAttributes = [
'name' => 'name',
];
public function mount()
{
$this->userId = auth()->user()->id;
$this->name = auth()->user()->name;
$this->email = auth()->user()->email;
}
public function submit()
{

View File

@ -17,6 +17,7 @@ class AddEmpty extends Component
'name' => 'Project Name',
'description' => 'Project Description',
];
public function submit()
{
try {

View File

@ -17,6 +17,7 @@ class AddEnvironment extends Component
protected $validationAttributes = [
'name' => 'Environment Name',
];
public function submit()
{
try {

View File

@ -10,10 +10,12 @@ class DeploymentLogs extends Component
public ApplicationDeploymentQueue $application_deployment_queue;
public $isKeepAliveOn = true;
protected $listeners = ['refreshQueue'];
public function refreshQueue()
{
$this->application_deployment_queue->refresh();
}
public function polling()
{
$this->emit('deploymentFinished');

View File

@ -8,17 +8,16 @@
use App\Models\Server;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Process;
use Livewire\Component;
use Illuminate\Support\Str;
use Livewire\Component;
class DeploymentNavbar extends Component
{
protected $listeners = ['deploymentFinished'];
public ApplicationDeploymentQueue $application_deployment_queue;
public Application $application;
public Server $server;
public bool $is_debug_enabled = false;
protected $listeners = ['deploymentFinished'];
public function mount()
{
@ -26,10 +25,12 @@ public function mount()
$this->server = $this->application->destination->server;
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
}
public function deploymentFinished()
{
$this->application_deployment_queue->refresh();
}
public function show_debug()
{
$this->application->settings->is_debug_enabled = !$this->application->settings->is_debug_enabled;
@ -37,6 +38,7 @@ public function show_debug()
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
$this->emit('refreshQueue');
}
public function cancel()
{
try {
@ -66,4 +68,4 @@ public function cancel()
return general_error_handler(err: $e, that: $this);
}
}
}
}

View File

@ -20,6 +20,7 @@ public function mount()
$this->current_url = url()->current();
$this->show_more();
}
private function show_more()
{
if (count($this->deployments) !== 0) {
@ -30,10 +31,12 @@ private function show_more()
return;
}
}
public function reload_deployments()
{
$this->load_deployments();
}
public function load_deployments(int|null $take = null)
{
if ($take) {

View File

@ -4,8 +4,8 @@
use App\Models\Application;
use App\Models\InstanceSettings;
use Livewire\Component;
use Illuminate\Support\Str;
use Livewire\Component;
use Spatie\Url\Url;
class General extends Component
@ -65,6 +65,7 @@ class General extends Component
'application.ports_exposes' => 'Ports exposes',
'application.ports_mappings' => 'Ports mappings',
];
public function instantSave()
{
// @TODO: find another way - if possible
@ -86,6 +87,7 @@ public function instantSave()
$this->emit('success', 'Application settings updated!');
$this->checkWildCardDomain();
}
protected function checkWildCardDomain()
{
$coolify_instance_settings = InstanceSettings::get();
@ -93,6 +95,7 @@ protected function checkWildCardDomain()
$this->global_wildcard_domain = data_get($coolify_instance_settings, 'wildcard_domain');
$this->wildcard_domain = $this->server_wildcard_domain ?? $this->global_wildcard_domain ?? null;
}
public function mount()
{
$this->is_static = $this->application->settings->is_static;
@ -104,6 +107,7 @@ public function mount()
$this->is_force_https_enabled = $this->application->settings->is_force_https_enabled;
$this->checkWildCardDomain();
}
public function generateGlobalRandomDomain()
{
// Set wildcard domain based on Global wildcard domain
@ -115,6 +119,7 @@ public function generateGlobalRandomDomain()
$this->application->save();
$this->emit('success', 'Application settings updated!');
}
public function generateServerRandomDomain()
{
// Set wildcard domain based on Server wildcard domain
@ -126,6 +131,7 @@ public function generateServerRandomDomain()
$this->application->save();
$this->emit('success', 'Application settings updated!');
}
public function submit()
{
try {

View File

@ -28,6 +28,12 @@ public function check_status()
));
$this->application->refresh();
}
public function force_deploy_without_cache()
{
$this->deploy(force_rebuild: true);
}
public function deploy(bool $force_rebuild = false)
{
$this->setDeploymentUuid();
@ -43,10 +49,13 @@ public function deploy(bool $force_rebuild = false)
'environment_name' => $this->parameters['environment_name'],
]);
}
public function force_deploy_without_cache()
protected function setDeploymentUuid()
{
$this->deploy(force_rebuild: true);
$this->deploymentUuid = new Cuid2(7);
$this->parameters['deployment_uuid'] = $this->deploymentUuid;
}
public function stop()
{
remote_process(
@ -57,9 +66,4 @@ public function stop()
$this->application->save();
$this->application->environment->project->team->notify(new StatusChanged($this->application));
}
protected function setDeploymentUuid()
{
$this->deploymentUuid = new Cuid2(7);
$this->parameters['deployment_uuid'] = $this->deploymentUuid;
}
}

View File

@ -17,6 +17,7 @@ class Form extends Component
protected $validationAttributes = [
'application.preview_url_template' => 'preview url template',
];
public function resetToDefault()
{
$this->application->preview_url_template = '{{pr_id}}.{{domain}}';
@ -24,6 +25,7 @@ public function resetToDefault()
$this->application->save();
$this->generate_real_url();
}
public function generate_real_url()
{
if (data_get($this->application, 'fqdn')) {
@ -32,10 +34,12 @@ public function generate_real_url()
$this->preview_url_template = Str::of($this->application->preview_url_template)->replace('{{domain}}', $host);
}
}
public function mount()
{
$this->generate_real_url();
}
public function submit()
{
$this->validate();

View File

@ -22,6 +22,7 @@ public function mount()
$this->pull_requests = collect();
$this->parameters = getRouteParameters();
}
public function loadStatus($pull_request_id)
{
dispatch(new ContainerStatusJob(
@ -30,11 +31,7 @@ public function loadStatus($pull_request_id)
pull_request_id: $pull_request_id
));
}
protected function setDeploymentUuid()
{
$this->deployment_uuid = new Cuid2(7);
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
}
public function load_prs()
{
try {
@ -46,6 +43,7 @@ public function load_prs()
return general_error_handler(err: $e, that: $this);
}
}
public function deploy(int $pull_request_id, string|null $pull_request_html_url = null)
{
try {
@ -74,6 +72,13 @@ public function deploy(int $pull_request_id, string|null $pull_request_html_url
return general_error_handler(err: $e, that: $this);
}
}
protected function setDeploymentUuid()
{
$this->deployment_uuid = new Cuid2(7);
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
}
public function stop(int $pull_request_id)
{
try {
@ -87,6 +92,7 @@ public function stop(int $pull_request_id)
return general_error_handler(err: $e, that: $this);
}
}
public function previewRefresh()
{
$this->application->previews->each(function ($preview) {

View File

@ -3,8 +3,8 @@
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use Livewire\Component;
use Illuminate\Support\Str;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class Rollback extends Component
@ -18,6 +18,7 @@ public function mount()
{
$this->parameters = getRouteParameters();
}
public function rollbackImage($commit)
{
$deployment_uuid = new Cuid2(7);
@ -36,6 +37,7 @@ public function rollbackImage($commit)
'environment_name' => $this->parameters['environment_name'],
]);
}
public function loadImages()
{
try {

View File

@ -21,16 +21,19 @@ class Source extends Component
'application.git_branch' => 'branch',
'application.git_commit_sha' => 'commit sha',
];
public function mount()
{
$this->get_private_keys();
}
private function get_private_keys()
{
$this->private_keys = PrivateKey::whereTeamId(session('currentTeam')->id)->get()->reject(function ($key) {
return $key->id == $this->application->private_key_id;
});
}
public function mount()
{
$this->get_private_keys();
}
public function setPrivateKey(int $private_key_id)
{
$this->application->private_key_id = $private_key_id;
@ -38,6 +41,7 @@ public function setPrivateKey(int $private_key_id)
$this->application->refresh();
$this->get_private_keys();
}
public function submit()
{
$this->validate();

View File

@ -2,10 +2,10 @@
namespace App\Http\Livewire\Project\Database;
use Livewire\Component;
use App\Actions\Database\StartPostgresql;
use App\Jobs\ContainerStatusJob;
use App\Notifications\Application\StatusChanged;
use Livewire\Component;
class Heading extends Component
{
@ -13,13 +13,16 @@ class Heading extends Component
public array $parameters;
protected $listeners = ['activityFinished'];
public function activityFinished() {
public function activityFinished()
{
$this->database->update([
'started_at' => now(),
]);
$this->emit('refresh');
$this->check_status();
}
public function check_status()
{
dispatch_sync(new ContainerStatusJob(
@ -28,11 +31,14 @@ public function check_status()
));
$this->database->refresh();
}
public function mount()
{
$this->parameters = getRouteParameters();
}
public function stop() {
public function stop()
{
remote_process(
["docker rm -f {$this->database->uuid}"],
$this->database->destination->server
@ -41,7 +47,9 @@ public function stop() {
$this->database->save();
$this->database->environment->project->team->notify(new StatusChanged($this->database));
}
public function start() {
public function start()
{
if ($this->database->type() === 'standalone-postgresql') {
$activity = resolve(StartPostgresql::class)($this->database->destination->server, $this->database);
$this->emit('newMonitorActivity', $activity->id);

View File

@ -31,10 +31,14 @@ class General extends Component
'database.init_scripts' => 'Init Scripts',
'database.image' => 'Image',
];
public function refresh() {
public function refresh(): void
{
$this->database->refresh();
}
public function submit() {
public function submit()
{
try {
$this->validate();
$this->database->save();

View File

@ -14,6 +14,7 @@ public function mount()
{
$this->parameters = getRouteParameters();
}
public function delete()
{
$this->validate([

View File

@ -14,6 +14,7 @@ public function mount()
{
$this->parameters = getRouteParameters();
}
public function delete()
{
$this->validate([

View File

@ -5,12 +5,9 @@
use App\Models\Application;
use App\Models\GithubApp;
use App\Models\Project;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Livewire\Component;
class GithubPrivateRepository extends Component
@ -30,18 +27,14 @@ class GithubPrivateRepository extends Component
public string $selected_branch_name = 'main';
public string $token;
protected int $page = 1;
public $repositories;
public int $total_repositories_count = 0;
public $branches;
public int $total_branches_count = 0;
public int $port = 3000;
public bool $is_static = false;
public string|null $publish_directory = null;
protected int $page = 1;
public function mount()
{
@ -50,32 +43,7 @@ public function mount()
$this->repositories = $this->branches = collect();
$this->github_apps = GithubApp::private();
}
protected function loadRepositoryByPage()
{
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/installation/repositories?per_page=100&page={$this->page}");
$json = $response->json();
if ($response->status() !== 200) {
return $this->emit('error', $json['message']);
}
if ($json['total_count'] === 0) {
return;
}
$this->total_repositories_count = $json['total_count'];
$this->repositories = $this->repositories->concat(collect($json['repositories']));
}
protected function loadBranchByPage()
{
ray('Loading page ' . $this->page);
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/repos/{$this->selected_repository_owner}/{$this->selected_repository_repo}/branches?per_page=100&page={$this->page}");
$json = $response->json();
if ($response->status() !== 200) {
return $this->emit('error', $json['message']);
}
$this->total_branches_count = count($json);
$this->branches = $this->branches->concat(collect($json));
}
public function loadRepositories($github_app_id)
{
$this->repositories = collect();
@ -93,6 +61,22 @@ public function loadRepositories($github_app_id)
$this->selected_repository_id = $this->repositories[0]['id'];
$this->current_step = 'repository';
}
protected function loadRepositoryByPage()
{
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/installation/repositories?per_page=100&page={$this->page}");
$json = $response->json();
if ($response->status() !== 200) {
return $this->emit('error', $json['message']);
}
if ($json['total_count'] === 0) {
return;
}
$this->total_repositories_count = $json['total_count'];
$this->repositories = $this->repositories->concat(collect($json['repositories']));
}
public function loadBranches()
{
$this->selected_repository_owner = $this->repositories->where('id', $this->selected_repository_id)->first()['owner']['login'];
@ -107,6 +91,20 @@ public function loadBranches()
}
}
}
protected function loadBranchByPage()
{
ray('Loading page ' . $this->page);
$response = Http::withToken($this->token)->get("{$this->github_app->api_url}/repos/{$this->selected_repository_owner}/{$this->selected_repository_repo}/branches?per_page=100&page={$this->page}");
$json = $response->json();
if ($response->status() !== 200) {
return $this->emit('error', $json['message']);
}
$this->total_branches_count = count($json);
$this->branches = $this->branches->concat(collect($json));
}
public function submit()
{
try {
@ -136,7 +134,7 @@ public function submit()
'destination_id' => $destination->id,
'destination_type' => $destination_class,
'source_id' => $this->github_app->id,
'source_type' => $this->github_app->getMorphClass()
'source_type' => $this->github_app->getMorphClass()
]);
$application->settings->is_static = $this->is_static;
$application->settings->save();
@ -150,6 +148,7 @@ public function submit()
return general_error_handler(err: $e, that: $this);
}
}
public function instantSave()
{
if ($this->is_static) {

View File

@ -27,14 +27,7 @@ class GithubPrivateRepositoryDeployKey extends Component
public null|string $publish_directory = null;
public string $repository_url;
private object $repository_url_parsed;
public string $branch;
private GithubApp|GitlabApp $git_source;
private string $git_host;
private string $git_repository;
private string $git_branch;
protected $rules = [
'repository_url' => 'required|url',
'branch' => 'required|string',
@ -49,6 +42,12 @@ class GithubPrivateRepositoryDeployKey extends Component
'is_static' => 'Is static',
'publish_directory' => 'Publish directory',
];
private object $repository_url_parsed;
private GithubApp|GitlabApp $git_source;
private string $git_host;
private string $git_repository;
private string $git_branch;
public function mount()
{
if (isDev()) {
@ -58,6 +57,7 @@ public function mount()
$this->query = request()->query();
$this->private_keys = PrivateKey::where('team_id', session('currentTeam')->id)->where('id', '!=', 0)->get();
}
public function instantSave()
{
if ($this->is_static) {
@ -68,30 +68,13 @@ public function instantSave()
$this->publish_directory = null;
}
}
public function setPrivateKey($private_key_id)
{
$this->private_key_id = $private_key_id;
$this->current_step = 'repository';
}
private function get_git_source()
{
$this->repository_url_parsed = Url::fromString($this->repository_url);
$this->git_host = $this->repository_url_parsed->getHost();
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
if ($this->branch) {
$this->git_branch = $this->branch;
} else {
$this->git_branch = $this->repository_url_parsed->getSegment(4) ?? 'main';
}
if ($this->git_host == 'github.com') {
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
} elseif ($this->git_host == 'gitlab.com') {
$this->git_source = GitlabApp::where('name', 'Public GitLab')->first();
} elseif ($this->git_host == 'bitbucket.org') {
// Not supported yet
}
}
public function submit()
{
$this->validate();
@ -123,7 +106,7 @@ public function submit()
'destination_type' => $destination_class,
'private_key_id' => $this->private_key_id,
'source_id' => $this->git_source->id,
'source_type' => $this->git_source->getMorphClass()
'source_type' => $this->git_source->getMorphClass()
];
$application = Application::create($application_init);
$application->settings->is_static = $this->is_static;
@ -138,4 +121,24 @@ public function submit()
return general_error_handler(err: $e, that: $this);
}
}
private function get_git_source()
{
$this->repository_url_parsed = Url::fromString($this->repository_url);
$this->git_host = $this->repository_url_parsed->getHost();
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
if ($this->branch) {
$this->git_branch = $this->branch;
} else {
$this->git_branch = $this->repository_url_parsed->getSegment(4) ?? 'main';
}
if ($this->git_host == 'github.com') {
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
} elseif ($this->git_host == 'gitlab.com') {
$this->git_source = GitlabApp::where('name', 'Public GitLab')->first();
} elseif ($this->git_host == 'bitbucket.org') {
// Not supported yet
}
}
}

View File

@ -15,13 +15,10 @@
class PublicGitRepository extends Component
{
public string $repository_url;
private object $repository_url_parsed;
public int $port = 3000;
public string $type;
public $parameters;
public $query;
public bool $branch_found = false;
public string $selected_branch = 'main';
public bool $is_static = false;
@ -29,11 +26,6 @@ class PublicGitRepository extends Component
public string $git_branch = 'main';
public int $rate_limit_remaining = 0;
public $rate_limit_reset = 0;
private GithubApp|GitlabApp $git_source;
private string $git_host;
private string $git_repository;
protected $rules = [
'repository_url' => 'required|url',
'port' => 'required|numeric',
@ -46,6 +38,11 @@ class PublicGitRepository extends Component
'is_static' => 'static',
'publish_directory' => 'publish directory',
];
private object $repository_url_parsed;
private GithubApp|GitlabApp $git_source;
private string $git_host;
private string $git_repository;
public function mount()
{
if (isDev()) {
@ -67,12 +64,7 @@ public function instantSave()
}
$this->emit('success', 'Application settings updated!');
}
private function get_branch()
{
['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = git_api(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches/{$this->git_branch}");
$this->rate_limit_reset = Carbon::parse((int)$this->rate_limit_reset)->format('Y-M-d H:i:s');
$this->branch_found = true;
}
public function load_branch()
{
$this->branch_found = false;
@ -96,6 +88,7 @@ public function load_branch()
}
}
}
private function get_git_source()
{
$this->repository_url_parsed = Url::fromString($this->repository_url);
@ -111,6 +104,14 @@ private function get_git_source()
// Not supported yet
}
}
private function get_branch()
{
['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = git_api(source: $this->git_source, endpoint: "/repos/{$this->git_repository}/branches/{$this->git_branch}");
$this->rate_limit_reset = Carbon::parse((int)$this->rate_limit_reset)->format('Y-M-d H:i:s');
$this->branch_found = true;
}
public function submit()
{
try {

View File

@ -19,17 +19,20 @@ public function mount()
{
$this->parameters = getRouteParameters();
}
public function set_type(string $type)
{
$this->type = $type;
$this->current_step = 'servers';
}
public function set_server(Server $server)
{
$this->server_id = $server->id;
$this->destinations = $server->destinations();
$this->current_step = 'destinations';
}
public function set_destination(string $destination_uuid)
{
$this->destination_uuid = $destination_uuid;
@ -40,6 +43,7 @@ public function set_destination(string $destination_uuid)
'destination' => $this->destination_uuid,
]);
}
public function load_servers()
{
$this->servers = Server::ownedByCurrentTeam()->get();

View File

@ -16,6 +16,7 @@ public function mount()
$this->modalId = new Cuid2(7);
$this->parameters = getRouteParameters();
}
public function delete()
{
$destination = $this->resource->destination->getMorphClass()::where('id', $this->resource->destination->id)->first();

View File

@ -23,10 +23,12 @@ class Add extends Component
'value' => 'value',
'is_build_time' => 'build',
];
public function mount()
{
$this->parameters = getRouteParameters();
}
public function submit()
{
ray('submitting');
@ -39,6 +41,7 @@ public function submit()
]);
$this->clear();
}
public function clear()
{
$this->key = '';

View File

@ -11,14 +11,17 @@ class All extends Component
public $resource;
public string|null $modalId = null;
protected $listeners = ['refreshEnvs', 'submit'];
public function mount()
{
$this->modalId = new Cuid2(7);
}
public function refreshEnvs()
{
$this->resource->refresh();
}
public function submit($data)
{
try {
@ -27,16 +30,16 @@ public function submit($data)
$this->emit('error', 'Environment variable already exists.');
return;
}
$environment = new EnvironmentVariable();
$environment = new EnvironmentVariable();
$environment->key = $data['key'];
$environment->value = $data['value'];
$environment->is_build_time = $data['is_build_time'];
$environment->is_preview = $data['is_preview'];
if($this->resource->type() === 'application') {
if ($this->resource->type() === 'application') {
$environment->application_id = $this->resource->id;
}
if($this->resource->type() === 'standalone-postgresql') {
if ($this->resource->type() === 'standalone-postgresql') {
$environment->standalone_postgresql_id = $this->resource->id;
}
$environment->save();

View File

@ -21,17 +21,20 @@ class Show extends Component
'value' => 'value',
'is_build_time' => 'build',
];
public function mount()
{
$this->modalId = new Cuid2(7);
$this->parameters = getRouteParameters();
}
public function submit()
{
$this->validate();
$this->env->save();
$this->emit('success', 'Environment variable updated successfully.');
}
public function delete()
{
$this->env->delete();

View File

@ -25,6 +25,7 @@ class ResourceLimits extends Component
'resource.limits_cpuset' => 'cpuset',
'resource.limits_cpu_shares' => 'cpu shares',
];
public function submit()
{
try {

View File

@ -22,10 +22,12 @@ class Add extends Component
'mount_path' => 'mount',
'host_path' => 'host',
];
public function mount()
{
$this->parameters = getRouteParameters();
}
public function submit()
{
$this->validate();
@ -35,6 +37,7 @@ public function submit()
'host_path' => $this->host_path,
]);
}
public function clear()
{
$this->name = '';

View File

@ -9,10 +9,12 @@ class All extends Component
{
public $resource;
protected $listeners = ['refreshStorages', 'submit'];
public function refreshStorages()
{
$this->resource->refresh();
}
public function submit($data)
{
try {

View File

@ -19,16 +19,19 @@ class Show extends Component
'mount_path' => 'mount',
'host_path' => 'host',
];
public function mount()
{
$this->modalId = new Cuid2(7);
}
public function submit()
{
$this->validate();
$this->storage->save();
$this->emit('success', 'Storage updated successfully');
}
public function delete()
{
$this->storage->delete();

View File

@ -2,7 +2,6 @@
namespace App\Http\Livewire;
use App\Enums\ActivityTypes;
use App\Models\Server;
use Livewire\Component;
@ -20,6 +19,7 @@ class RunCommand extends Component
'server' => 'server',
'command' => 'command',
];
public function mount($servers)
{
$this->servers = $servers;

View File

@ -5,7 +5,6 @@
use App\Actions\Server\InstallDocker;
use App\Models\Server;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class Form extends Component
{
@ -34,16 +33,19 @@ class Form extends Component
'server.settings.is_reachable' => 'is reachable',
'server.settings.is_part_of_swarm' => 'is part of swarm'
];
public function mount()
{
$this->wildcard_domain = $this->server->settings->wildcard_domain;
$this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage;
}
public function installDocker()
{
$activity = resolve(InstallDocker::class)($this->server, session('currentTeam'));
$this->emit('newMonitorActivity', $activity->id);
}
public function validateServer()
{
try {
@ -59,6 +61,7 @@ public function validateServer()
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
}
}
public function delete()
{
if (!$this->server->isEmpty()) {
@ -68,6 +71,7 @@ public function delete()
$this->server->delete();
redirect()->route('server.all');
}
public function submit()
{
$this->validate();
@ -88,4 +92,4 @@ public function submit()
$this->server->save();
$this->emit('success', 'Server updated successfully.');
}
}
}

View File

@ -2,7 +2,6 @@
namespace App\Http\Livewire\Server\New;
use App\Models\PrivateKey;
use App\Models\Server;
use Livewire\Component;
@ -35,19 +34,23 @@ class ByIp extends Component
'user' => 'user',
'port' => 'port',
];
public function mount()
{
$this->name = generate_random_name();
$this->private_key_id = $this->private_keys->first()->id;
}
public function setPrivateKey(string $private_key_id)
{
$this->private_key_id = $private_key_id;
}
public function instantSave()
{
$this->emit('success', 'Application settings updated!');
}
public function submit()
{
$this->validate();

View File

@ -3,7 +3,6 @@
namespace App\Http\Livewire\Server;
use App\Models\Server;
use Illuminate\Support\Facades\Storage;
use Livewire\Component;
use Masmerise\Toaster\Toaster;
@ -13,6 +12,16 @@ class PrivateKey extends Component
public $privateKeys;
public $parameters;
public function setPrivateKey($private_key_id)
{
$this->server->update([
'private_key_id' => $private_key_id
]);
refreshPrivateKey($this->server->privateKey);
$this->server->refresh();
$this->checkConnection();
}
public function checkConnection()
{
try {
@ -27,15 +36,7 @@ public function checkConnection()
return general_error_handler(customErrorMessage: "Server is not reachable. Reason: {$e->getMessage()}", that: $this);
}
}
public function setPrivateKey($private_key_id)
{
$this->server->update([
'private_key_id' => $private_key_id
]);
refreshPrivateKey($this->server->privateKey);
$this->server->refresh();
$this->checkConnection();
}
public function mount()
{
$this->parameters = getRouteParameters();

View File

@ -5,7 +5,6 @@
use App\Actions\Proxy\CheckConfigurationSync;
use App\Actions\Proxy\SaveConfigurationSync;
use App\Enums\ProxyTypes;
use Illuminate\Support\Str;
use App\Models\Server;
use Livewire\Component;
@ -17,21 +16,25 @@ class Proxy extends Component
public $proxy_settings = null;
public string|null $redirect_url = null;
protected $listeners = ['proxyStatusUpdated', 'saveConfiguration'=>'submit'];
protected $listeners = ['proxyStatusUpdated', 'saveConfiguration' => 'submit'];
public function mount()
{
$this->redirect_url = $this->server->proxy->redirect_url;
}
public function proxyStatusUpdated()
{
$this->server->refresh();
}
public function change_proxy()
{
$this->server->proxy = null;
$this->server->save();
$this->emit('proxyStatusUpdated');
}
public function select_proxy(string $proxy_type)
{
$this->server->proxy->type = $proxy_type;
@ -39,6 +42,7 @@ public function select_proxy(string $proxy_type)
$this->server->save();
$this->emit('proxyStatusUpdated');
}
public function submit()
{
try {
@ -53,6 +57,7 @@ public function submit()
return general_error_handler(err: $e);
}
}
public function reset_proxy_configuration()
{
try {
@ -61,6 +66,7 @@ public function reset_proxy_configuration()
return general_error_handler(err: $e);
}
}
public function load_proxy_configuration()
{
try {
@ -69,4 +75,4 @@ public function load_proxy_configuration()
return general_error_handler(err: $e);
}
}
}
}

View File

@ -5,12 +5,12 @@
use App\Actions\Proxy\StartProxy;
use App\Models\Server;
use Livewire\Component;
use Str;
class Deploy extends Component
{
public Server $server;
public $proxy_settings = null;
public function start_proxy()
{
if (
@ -22,6 +22,7 @@ public function start_proxy()
$activity = resolve(StartProxy::class)($this->server);
$this->emit('newMonitorActivity', $activity->id);
}
public function stop()
{
instant_remote_process([
@ -31,4 +32,4 @@ public function stop()
$this->server->save();
$this->emit('proxyStatusUpdated');
}
}
}

View File

@ -9,6 +9,7 @@
class Status extends Component
{
public Server $server;
public function get_status()
{
dispatch_sync(new ProxyContainerStatusJob(
@ -17,4 +18,4 @@ public function get_status()
$this->server->refresh();
$this->emit('proxyStatusUpdated');
}
}
}

View File

@ -31,6 +31,7 @@ class Configuration extends Component
'settings.public_port_min' => 'Public port min',
'settings.public_port_max' => 'Public port max',
];
public function mount()
{
$this->do_not_track = $this->settings->do_not_track;
@ -38,6 +39,7 @@ public function mount()
$this->is_registration_enabled = $this->settings->is_registration_enabled;
$this->next_channel = $this->settings->next_channel;
}
public function instantSave()
{
$this->settings->do_not_track = $this->do_not_track;
@ -47,6 +49,21 @@ public function instantSave()
$this->settings->save();
$this->emit('success', 'Settings updated!');
}
public function submit()
{
$this->resetErrorBag();
if ($this->settings->public_port_min > $this->settings->public_port_max) {
$this->addError('settings.public_port_min', 'The minimum port must be lower than the maximum port.');
return;
}
$this->validate();
$this->settings->save();
$this->server = Server::findOrFail(0);
$this->setup_instance_fqdn();
$this->emit('success', 'Instance settings updated successfully!');
}
private function setup_instance_fqdn()
{
$file = "$this->dynamic_config_path/coolify.yaml";
@ -60,35 +77,35 @@ private function setup_instance_fqdn()
$schema = $url->getScheme();
$traefik_dynamic_conf = [
'http' =>
[
'routers' =>
[
'coolify-http' =>
[
'entryPoints' => [
0 => 'http',
],
'service' => 'coolify',
'rule' => "Host(`{$host}`)",
],
],
'services' =>
[
'coolify' =>
[
'loadBalancer' =>
'routers' =>
[
'servers' =>
[
0 =>
'coolify-http' =>
[
'url' => 'http://coolify:80',
'entryPoints' => [
0 => 'http',
],
'service' => 'coolify',
'rule' => "Host(`{$host}`)",
],
],
'services' =>
[
'coolify' =>
[
'loadBalancer' =>
[
'servers' =>
[
0 =>
[
'url' => 'http://coolify:80',
],
],
],
],
],
],
],
],
],
];
if ($schema === 'https') {
@ -110,6 +127,7 @@ private function setup_instance_fqdn()
dispatch(new ProxyStartJob($this->server));
}
}
private function save_configuration_to_disk(array $traefik_dynamic_conf, string $file)
{
$yaml = Yaml::dump($traefik_dynamic_conf, 12, 2);
@ -128,17 +146,4 @@ private function save_configuration_to_disk(array $traefik_dynamic_conf, string
ray($yaml);
}
}
public function submit()
{
$this->resetErrorBag();
if ($this->settings->public_port_min > $this->settings->public_port_max) {
$this->addError('settings.public_port_min', 'The minimum port must be lower than the maximum port.');
return;
}
$this->validate();
$this->settings->save();
$this->server = Server::findOrFail(0);
$this->setup_instance_fqdn();
$this->emit('success', 'Instance settings updated successfully!');
}
}

View File

@ -4,7 +4,6 @@
use App\Models\InstanceSettings;
use App\Notifications\TransactionalEmails\Test;
use Illuminate\Support\Facades\Notification;
use Livewire\Component;
class Email extends Component
@ -32,11 +31,23 @@ class Email extends Component
'settings.smtp_username' => 'Username',
'settings.smtp_password' => 'Password',
];
public function mount()
{
$this->decrypt();
$this->emails = auth()->user()->email;
}
private function decrypt()
{
if (data_get($this->settings, 'smtp_password')) {
try {
$this->settings->smtp_password = decrypt($this->settings->smtp_password);
} catch (\Exception $e) {
}
}
}
public function instantSave()
{
try {
@ -47,20 +58,7 @@ public function instantSave()
$this->validate();
}
}
public function sendTestNotification()
{
$this->settings->notify(new Test($this->emails));
$this->emit('success', 'Test email sent.');
}
private function decrypt()
{
if (data_get($this->settings, 'smtp_password')) {
try {
$this->settings->smtp_password = decrypt($this->settings->smtp_password);
} catch (\Exception $e) {
}
}
}
public function submit()
{
$this->resetErrorBag();
@ -75,4 +73,10 @@ public function submit()
$this->emit('success', 'Transaction email settings updated successfully.');
$this->decrypt();
}
}
public function sendTestNotification()
{
$this->settings->notify(new Test($this->emails));
$this->emit('success', 'Test email sent.');
}
}

View File

@ -34,12 +34,14 @@ class Change extends Component
'github_app.webhook_secret' => 'nullable',
'github_app.is_system_wide' => 'required|bool',
];
public function mount()
{
$this->webhook_endpoint = $this->ipv4;
$this->parameters = getRouteParameters();
$this->is_system_wide = $this->github_app->is_system_wide;
}
public function submit()
{
try {
@ -49,6 +51,7 @@ public function submit()
return general_error_handler(err: $e, that: $this);
}
}
public function instantSave()
{
}

View File

@ -19,6 +19,7 @@ public function mount()
{
$this->name = generate_random_name();
}
public function createGitHubApp()
{
try {

View File

@ -8,10 +8,12 @@
class SwitchTeam extends Component
{
public string $selectedTeamId = 'default';
public function updatedSelectedTeamId()
{
$this->switch_to($this->selectedTeamId);
}
public function switch_to($team_id)
{
if (!auth()->user()->teams->contains($team_id)) {

View File

@ -18,6 +18,7 @@ class Create extends Component
'name' => 'name',
'description' => 'description',
];
public function submit()
{
$this->validate();

View File

@ -4,7 +4,6 @@
use App\Models\Team;
use Livewire\Component;
use Masmerise\Toaster\Toaster;
class Form extends Component
{
@ -17,10 +16,12 @@ class Form extends Component
'team.name' => 'name',
'team.description' => 'description',
];
public function mount()
{
$this->team = session('currentTeam');
}
public function submit()
{
$this->validate();

View File

@ -9,13 +9,15 @@ class Invitations extends Component
{
public $invitations;
protected $listeners = ['refreshInvitations'];
public function refreshInvitations()
{
$this->invitations = TeamInvitation::whereTeamId(auth()->user()->currentTeam()->id)->get();
}
public function deleteInvitation(int $invitation_id)
{
TeamInvitation::find($invitation_id)->delete();
$this->refreshInvitations();
}
public function refreshInvitations()
{
$this->invitations = TeamInvitation::whereTeamId(auth()->user()->currentTeam()->id)->get();
}
}

View File

@ -12,14 +12,17 @@ class InviteLink extends Component
{
public string $email;
public string $role = 'member';
public function mount()
{
$this->email = isDev() ? 'test3@example.com' : '';
}
public function viaEmail()
{
$this->generate_invite_link(isEmail: true);
}
private function generate_invite_link(bool $isEmail = false)
{
try {
@ -72,8 +75,9 @@ private function generate_invite_link(bool $isEmail = false)
return general_error_handler(err: $e, that: $this, customErrorMessage: $error_message);
}
}
public function viaLink()
{
$this->generate_invite_link();
}
}
}

View File

@ -8,16 +8,19 @@
class Member extends Component
{
public User $member;
public function makeAdmin()
{
$this->member->teams()->updateExistingPivot(session('currentTeam')->id, ['role' => 'admin']);
$this->emit('reloadWindow');
}
public function makeReadonly()
{
$this->member->teams()->updateExistingPivot(session('currentTeam')->id, ['role' => 'member']);
$this->emit('reloadWindow');
}
public function remove()
{
$this->member->teams()->detach(session('currentTeam'));

View File

@ -2,8 +2,8 @@
namespace App\Http\Livewire\Team\Storage;
use Livewire\Component;
use App\Models\S3Storage;
use Livewire\Component;
class Create extends Component
{
@ -33,7 +33,9 @@ class Create extends Component
'bucket' => 'Bucket',
'endpoint' => 'Endpoint',
];
public function mount() {
public function mount()
{
if (isDev()) {
$this->name = 'Local MinIO';
$this->description = 'Local MinIO';
@ -43,15 +45,9 @@ public function mount() {
$this->endpoint = 'http://coolify-minio:9000';
}
}
private function test_s3_connection() {
try {
$this->storage->testConnection();
return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
} catch(\Throwable $th) {
return general_error_handler($th, $this);
}
}
public function submit() {
public function submit()
{
try {
$this->validate();
$this->storage = new S3Storage();
@ -71,9 +67,19 @@ public function submit() {
$this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
$this->storage->save();
return redirect()->route('team.storages.show', $this->storage->uuid);
} catch(\Throwable $th) {
} catch (\Throwable $th) {
return general_error_handler($th, $this);
}
}
}
private function test_s3_connection()
{
try {
$this->storage->testConnection();
return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
} catch (\Throwable $th) {
return general_error_handler($th, $this);
}
}
}

View File

@ -2,8 +2,8 @@
namespace App\Http\Livewire\Team\Storage;
use Livewire\Component;
use App\Models\S3Storage;
use Livewire\Component;
class Form extends Component
{
@ -26,22 +26,27 @@ class Form extends Component
'storage.bucket' => 'Bucket',
'storage.endpoint' => 'Endpoint',
];
public function test_s3_connection() {
public function test_s3_connection()
{
try {
$this->storage->testConnection();
return $this->emit('success', 'Connection is working. Tested with "ListObjectsV2" action.');
} catch(\Throwable $th) {
} catch (\Throwable $th) {
return general_error_handler($th, $this);
}
}
public function delete() {
public function delete()
{
try {
$this->storage->delete();
return redirect()->route('team.storages.all');
} catch(\Throwable $th) {
} catch (\Throwable $th) {
return general_error_handler($th, $this);
}
}
public function submit()
{
$this->validate();
@ -54,4 +59,4 @@ public function submit()
return general_error_handler($th, $this);
}
}
}
}

View File

@ -4,8 +4,8 @@
use App\Actions\Server\UpdateCoolify;
use App\Models\InstanceSettings;
use Masmerise\Toaster\Toaster;
use Livewire\Component;
use Masmerise\Toaster\Toaster;
class Upgrade extends Component
{
@ -27,6 +27,7 @@ public function checkUpdate()
$this->latestVersion = 'next';
}
}
public function upgrade()
{
try {
@ -40,4 +41,4 @@ public function upgrade()
return general_error_handler(err: $e, that: $this);
}
}
}
}

View File

@ -13,7 +13,7 @@ class RedirectIfAuthenticated
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, string ...$guards): Response
{

View File

@ -20,7 +20,7 @@ class TrustProxies extends Middleware
* @var int
*/
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |

View File

@ -12,8 +12,8 @@
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
use App\Notifications\Application\DeploymentSuccess;
use App\Notifications\Application\DeploymentFailed;
use App\Notifications\Application\DeploymentSuccess;
use App\Traits\ExecuteRemoteCommand;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -22,8 +22,8 @@
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
use Spatie\Url\Url;
use Illuminate\Support\Str;
use Spatie\Url\Url;
use Symfony\Component\Yaml\Yaml;
use Throwable;
use Visus\Cuid2\Cuid2;
@ -61,6 +61,7 @@ class ApplicationDeploymentJob implements ShouldQueue
private $log_model;
private Collection $saved_outputs;
public function __construct(int $application_deployment_queue_id)
{
ray()->clearScreen();
@ -137,62 +138,7 @@ public function handle(): void
// ray()->measure();
}
}
public function failed(Throwable $exception): void
{
$this->execute_remote_command(
["echo 'Oops something is not okay, are you okay? 😢'"],
["echo '{$exception->getMessage()}'"]
);
$this->next(ApplicationDeploymentStatus::FAILED->value);
}
private function execute_in_builder(string $command)
{
return "docker exec {$this->deployment_uuid} bash -c '{$command}'";
// return "docker exec {$this->deployment_uuid} bash -c '{$command} |& tee -a /proc/1/fd/1; [ \$PIPESTATUS -eq 0 ] || exit \$PIPESTATUS'";
}
private function deploy()
{
$this->execute_remote_command(
[
"echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}.'"
],
);
$this->prepare_builder_image();
$this->clone_repository();
$tag = Str::of("{$this->commit}-{$this->application->id}-{$this->pull_request_id}");
if (strlen($tag) > 128) {
$tag = $tag->substr(0, 128);
};
$this->build_image_name = "{$this->application->git_repository}:{$tag}-build";
$this->production_image_name = "{$this->application->uuid}:{$tag}";
ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
if (!$this->force_rebuild) {
$this->execute_remote_command([
"docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
]);
if (Str::of($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
$this->execute_remote_command([
"echo 'Docker Image found locally with the same Git Commit SHA {$this->application->uuid}:{$this->commit}. Build step skipped...'"
]);
$this->generate_compose_file();
$this->stop_running_container();
$this->start_by_compose_file();
return;
}
}
$this->cleanup_git();
$this->generate_buildpack();
$this->generate_compose_file();
$this->generate_build_env_variables();
$this->add_build_env_variables_to_dockerfile();
$this->build_image();
$this->stop_running_container();
$this->start_by_compose_file();
}
private function deploy_pull_request()
{
$this->build_image_name = "{$this->application->uuid}:pr-{$this->pull_request_id}-build";
@ -214,117 +160,154 @@ private function deploy_pull_request()
$this->start_by_compose_file();
}
private function next(string $status)
{
// If the deployment is cancelled by the user, don't update the status
if ($this->application_deployment_queue->status !== ApplicationDeploymentStatus::CANCELLED_BY_USER->value) {
$this->application_deployment_queue->update([
'status' => $status,
]);
}
queue_next_deployment($this->application);
if ($status === ApplicationDeploymentStatus::FINISHED->value) {
$this->application->environment->project->team->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
}
if ($status === ApplicationDeploymentStatus::FAILED->value) {
$this->application->environment->project->team->notify(new DeploymentFailed($this->application, $this->deployment_uuid, $this->preview));
}
}
private function start_by_compose_file()
private function prepare_builder_image()
{
$this->execute_remote_command(
["echo -n 'Starting new application... '"],
[$this->execute_in_builder("docker compose --project-directory {$this->workdir} up -d >/dev/null"), "hidden" => true],
["echo 'Done. 🎉'"],
[
"echo -n 'Pulling latest version of the builder image (ghcr.io/coollabsio/coolify-builder).'",
],
[
"docker run --pull=always -d --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/coollabsio/coolify-builder",
"hidden" => true,
],
[
"command" => $this->execute_in_builder("mkdir -p {$this->workdir}")
],
);
}
private function stop_running_container()
private function execute_in_builder(string $command)
{
return "docker exec {$this->deployment_uuid} bash -c '{$command}'";
// return "docker exec {$this->deployment_uuid} bash -c '{$command} |& tee -a /proc/1/fd/1; [ \$PIPESTATUS -eq 0 ] || exit \$PIPESTATUS'";
}
private function clone_repository()
{
$this->execute_remote_command(
["echo -n 'Removing old running application.'"],
[$this->execute_in_builder("docker rm -f $this->container_name >/dev/null 2>&1"), "hidden" => true],
[
"echo -n 'Importing {$this->application->git_repository}:{$this->application->git_branch} to {$this->workdir}. '"
],
[
$this->importing_git_repository()
],
[
$this->execute_in_builder("cd {$this->workdir} && git rev-parse HEAD"),
"hidden" => true,
"save" => "git_commit_sha"
],
);
$this->commit = $this->saved_outputs->get('git_commit_sha');
}
private function importing_git_repository()
{
$commands = collect([]);
$git_clone_command = "git clone -q -b {$this->application->git_branch}";
if ($this->pull_request_id !== 0) {
$pr_branch_name = "pr-{$this->pull_request_id}-coolify";
}
if ($this->application->deploymentType() === 'source') {
$source_html_url = data_get($this->application, 'source.html_url');
$url = parse_url(filter_var($source_html_url, FILTER_SANITIZE_URL));
$source_html_url_host = $url['host'];
$source_html_url_scheme = $url['scheme'];
if ($this->source->getMorphClass() == 'App\Models\GithubApp') {
if ($this->source->is_public) {
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->workdir}";
$git_clone_command = $this->set_git_import_settings($git_clone_command);
$commands->push($this->execute_in_builder($git_clone_command));
} else {
$github_access_token = generate_github_installation_token($this->source);
$commands->push($this->execute_in_builder("git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->workdir}"));
}
if ($this->pull_request_id !== 0) {
$commands->push($this->execute_in_builder("cd {$this->workdir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name"));
}
return $commands->implode(' && ');
}
}
if ($this->application->deploymentType() === 'deploy_key') {
$private_key = base64_encode($this->application->private_key->private_key);
$git_clone_command = "GIT_SSH_COMMAND=\"ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_full_url} {$this->workdir}";
$git_clone_command = $this->set_git_import_settings($git_clone_command);
$commands = collect([
$this->execute_in_builder("mkdir -p /root/.ssh"),
$this->execute_in_builder("echo '{$private_key}' | base64 -d > /root/.ssh/id_rsa"),
$this->execute_in_builder("chmod 600 /root/.ssh/id_rsa"),
$this->execute_in_builder($git_clone_command)
]);
return $commands->implode(' && ');
}
}
private function set_git_import_settings($git_clone_command)
{
if ($this->application->git_commit_sha !== 'HEAD') {
$git_clone_command = "{$git_clone_command} && cd {$this->workdir} && git -c advice.detachedHead=false checkout {$this->application->git_commit_sha} >/dev/null 2>&1";
}
if ($this->application->settings->is_git_submodules_enabled) {
$git_clone_command = "{$git_clone_command} && cd {$this->workdir} && git submodule update --init --recursive";
}
if ($this->application->settings->is_git_lfs_enabled) {
$git_clone_command = "{$git_clone_command} && cd {$this->workdir} && git lfs pull";
}
return $git_clone_command;
}
private function cleanup_git()
{
$this->execute_remote_command(
[$this->execute_in_builder("rm -fr {$this->workdir}/.git")],
);
}
private function build_image()
private function generate_buildpack()
{
$this->execute_remote_command([
"echo -n 'Building docker image.'",
]);
if ($this->application->settings->is_static) {
$this->execute_remote_command([
$this->execute_in_builder("docker build -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true
]);
$dockerfile = base64_encode("FROM {$this->application->static_image}
WORKDIR /usr/share/nginx/html/
LABEL coolify.deploymentId={$this->deployment_uuid}
COPY --from=$this->build_image_name /app/{$this->application->publish_directory} .
COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
$nginx_config = base64_encode("server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
try_files \$uri \$uri.html \$uri/index.html \$uri/ /index.html =404;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}");
$this->execute_remote_command(
[
$this->execute_in_builder("echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile-prod")
],
[
$this->execute_in_builder("echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf")
],
[
$this->execute_in_builder("docker build -f {$this->workdir}/Dockerfile-prod {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
]
);
} else {
$this->execute_remote_command([
$this->execute_in_builder("docker build -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
]);
}
$this->execute_remote_command(
[
"echo -n 'Generating nixpacks configuration.'",
],
[$this->nixpacks_build_cmd()],
[$this->execute_in_builder("cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")],
[$this->execute_in_builder("rm -f {$this->workdir}/.nixpacks/Dockerfile")]
);
}
private function add_build_env_variables_to_dockerfile()
{
$this->execute_remote_command([
$this->execute_in_builder("cat {$this->workdir}/Dockerfile"), "hidden" => true, "save" => 'dockerfile'
]);
$dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile'))->trim()->explode("\n"));
foreach ($this->application->build_environment_variables as $env) {
$dockerfile->splice(1, 0, "ARG {$env->key}={$env->value}");
}
$dockerfile_base64 = base64_encode($dockerfile->implode("\n"));
$this->execute_remote_command([
$this->execute_in_builder("echo '{$dockerfile_base64}' | base64 -d > {$this->workdir}/Dockerfile"),
"hidden" => true
]);
}
private function generate_build_env_variables()
private function nixpacks_build_cmd()
{
$this->build_args = collect(["--build-arg SOURCE_COMMIT={$this->commit}"]);
$this->generate_env_variables();
$nixpacks_command = "nixpacks build -o {$this->workdir} {$this->env_args} --no-error-without-start";
if ($this->application->build_command) {
$nixpacks_command .= " --build-cmd \"{$this->application->build_command}\"";
}
if ($this->application->start_command) {
$nixpacks_command .= " --start-cmd \"{$this->application->start_command}\"";
}
if ($this->application->install_command) {
$nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
}
$nixpacks_command .= " {$this->workdir}";
return $this->execute_in_builder($nixpacks_command);
}
private function generate_env_variables()
{
$this->env_args = collect([]);
if ($this->pull_request_id === 0) {
foreach ($this->application->build_environment_variables as $env) {
$this->build_args->push("--build-arg {$env->key}={$env->value}");
foreach ($this->application->nixpacks_environment_variables as $env) {
$this->env_args->push("--env {$env->key}={$env->value}");
}
} else {
foreach ($this->application->build_environment_variables_preview as $env) {
$this->build_args->push("--build-arg {$env->key}={$env->value}");
foreach ($this->application->nixpacks_environment_variables_preview as $env) {
$this->env_args->push("--env {$env->key}={$env->value}");
}
}
$this->build_args = $this->build_args->implode(' ');
$this->env_args = $this->env_args->implode(' ');
}
private function generate_compose_file()
@ -388,6 +371,7 @@ private function generate_compose_file()
$docker_compose_base64 = base64_encode($this->docker_compose);
$this->execute_remote_command([$this->execute_in_builder("echo '{$docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yml"), "hidden" => true]);
}
private function generate_local_persistent_volumes()
{
$local_persistent_volumes = [];
@ -400,6 +384,7 @@ private function generate_local_persistent_volumes()
}
return $local_persistent_volumes;
}
private function generate_local_persistent_volumes_only_volume_names()
{
$local_persistent_volumes_names = [];
@ -420,6 +405,7 @@ private function generate_local_persistent_volumes_only_volume_names()
}
return $local_persistent_volumes_names;
}
private function generate_environment_variables($ports)
{
$environment_variables = collect();
@ -436,27 +422,12 @@ private function generate_environment_variables($ports)
}
}
// Add PORT if not exists, use the first port as default
if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('PORT'))->isEmpty()) {
if ($environment_variables->filter(fn($env) => Str::of($env)->contains('PORT'))->isEmpty()) {
$environment_variables->push("PORT={$ports[0]}");
}
return $environment_variables->all();
}
private function generate_healthcheck_commands()
{
if (!$this->application->health_check_port) {
$this->application->health_check_port = $this->application->ports_exposes_array[0];
}
if ($this->application->health_check_path) {
$generated_healthchecks_commands = [
"curl -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$this->application->health_check_port}{$this->application->health_check_path} > /dev/null"
];
} else {
$generated_healthchecks_commands = [
"curl -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$this->application->health_check_port}/"
];
}
return implode(' ', $generated_healthchecks_commands);
}
private function set_labels_for_applications()
{
$labels = [];
@ -520,140 +491,192 @@ private function set_labels_for_applications()
}
return $labels;
}
private function generate_buildpack()
private function generate_healthcheck_commands()
{
if (!$this->application->health_check_port) {
$this->application->health_check_port = $this->application->ports_exposes_array[0];
}
if ($this->application->health_check_path) {
$generated_healthchecks_commands = [
"curl -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$this->application->health_check_port}{$this->application->health_check_path} > /dev/null"
];
} else {
$generated_healthchecks_commands = [
"curl -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$this->application->health_check_port}/"
];
}
return implode(' ', $generated_healthchecks_commands);
}
private function build_image()
{
$this->execute_remote_command([
"echo -n 'Building docker image.'",
]);
if ($this->application->settings->is_static) {
$this->execute_remote_command([
$this->execute_in_builder("docker build -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true
]);
$dockerfile = base64_encode("FROM {$this->application->static_image}
WORKDIR /usr/share/nginx/html/
LABEL coolify.deploymentId={$this->deployment_uuid}
COPY --from=$this->build_image_name /app/{$this->application->publish_directory} .
COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
$nginx_config = base64_encode("server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
try_files \$uri \$uri.html \$uri/index.html \$uri/ /index.html =404;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}");
$this->execute_remote_command(
[
$this->execute_in_builder("echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile-prod")
],
[
$this->execute_in_builder("echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf")
],
[
$this->execute_in_builder("docker build -f {$this->workdir}/Dockerfile-prod {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
]
);
} else {
$this->execute_remote_command([
$this->execute_in_builder("docker build -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
]);
}
}
private function stop_running_container()
{
$this->execute_remote_command(
[
"echo -n 'Generating nixpacks configuration.'",
],
[$this->nixpacks_build_cmd()],
[$this->execute_in_builder("cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")],
[$this->execute_in_builder("rm -f {$this->workdir}/.nixpacks/Dockerfile")]
["echo -n 'Removing old running application.'"],
[$this->execute_in_builder("docker rm -f $this->container_name >/dev/null 2>&1"), "hidden" => true],
);
}
private function nixpacks_build_cmd()
private function start_by_compose_file()
{
$this->generate_env_variables();
$nixpacks_command = "nixpacks build -o {$this->workdir} {$this->env_args} --no-error-without-start";
if ($this->application->build_command) {
$nixpacks_command .= " --build-cmd \"{$this->application->build_command}\"";
}
if ($this->application->start_command) {
$nixpacks_command .= " --start-cmd \"{$this->application->start_command}\"";
}
if ($this->application->install_command) {
$nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
}
$nixpacks_command .= " {$this->workdir}";
return $this->execute_in_builder($nixpacks_command);
$this->execute_remote_command(
["echo -n 'Starting new application... '"],
[$this->execute_in_builder("docker compose --project-directory {$this->workdir} up -d >/dev/null"), "hidden" => true],
["echo 'Done. 🎉'"],
);
}
private function generate_env_variables()
private function deploy()
{
$this->env_args = collect([]);
$this->execute_remote_command(
[
"echo 'Starting deployment of {$this->application->git_repository}:{$this->application->git_branch}.'"
],
);
$this->prepare_builder_image();
$this->clone_repository();
$tag = Str::of("{$this->commit}-{$this->application->id}-{$this->pull_request_id}");
if (strlen($tag) > 128) {
$tag = $tag->substr(0, 128);
};
$this->build_image_name = "{$this->application->git_repository}:{$tag}-build";
$this->production_image_name = "{$this->application->uuid}:{$tag}";
ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
if (!$this->force_rebuild) {
$this->execute_remote_command([
"docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
]);
if (Str::of($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
$this->execute_remote_command([
"echo 'Docker Image found locally with the same Git Commit SHA {$this->application->uuid}:{$this->commit}. Build step skipped...'"
]);
$this->generate_compose_file();
$this->stop_running_container();
$this->start_by_compose_file();
return;
}
}
$this->cleanup_git();
$this->generate_buildpack();
$this->generate_compose_file();
$this->generate_build_env_variables();
$this->add_build_env_variables_to_dockerfile();
$this->build_image();
$this->stop_running_container();
$this->start_by_compose_file();
}
private function generate_build_env_variables()
{
$this->build_args = collect(["--build-arg SOURCE_COMMIT={$this->commit}"]);
if ($this->pull_request_id === 0) {
foreach ($this->application->nixpacks_environment_variables as $env) {
$this->env_args->push("--env {$env->key}={$env->value}");
foreach ($this->application->build_environment_variables as $env) {
$this->build_args->push("--build-arg {$env->key}={$env->value}");
}
} else {
foreach ($this->application->nixpacks_environment_variables_preview as $env) {
$this->env_args->push("--env {$env->key}={$env->value}");
foreach ($this->application->build_environment_variables_preview as $env) {
$this->build_args->push("--build-arg {$env->key}={$env->value}");
}
}
$this->env_args = $this->env_args->implode(' ');
$this->build_args = $this->build_args->implode(' ');
}
private function cleanup_git()
{
$this->execute_remote_command(
[$this->execute_in_builder("rm -fr {$this->workdir}/.git")],
);
}
private function prepare_builder_image()
{
$this->execute_remote_command(
[
"echo -n 'Pulling latest version of the builder image (ghcr.io/coollabsio/coolify-builder).'",
],
[
"docker run --pull=always -d --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/coollabsio/coolify-builder",
"hidden" => true,
],
[
"command" => $this->execute_in_builder("mkdir -p {$this->workdir}")
],
);
}
private function set_git_import_settings($git_clone_command)
{
if ($this->application->git_commit_sha !== 'HEAD') {
$git_clone_command = "{$git_clone_command} && cd {$this->workdir} && git -c advice.detachedHead=false checkout {$this->application->git_commit_sha} >/dev/null 2>&1";
}
if ($this->application->settings->is_git_submodules_enabled) {
$git_clone_command = "{$git_clone_command} && cd {$this->workdir} && git submodule update --init --recursive";
}
if ($this->application->settings->is_git_lfs_enabled) {
$git_clone_command = "{$git_clone_command} && cd {$this->workdir} && git lfs pull";
}
return $git_clone_command;
}
private function importing_git_repository()
{
$commands = collect([]);
$git_clone_command = "git clone -q -b {$this->application->git_branch}";
if ($this->pull_request_id !== 0) {
$pr_branch_name = "pr-{$this->pull_request_id}-coolify";
}
if ($this->application->deploymentType() === 'source') {
$source_html_url = data_get($this->application, 'source.html_url');
$url = parse_url(filter_var($source_html_url, FILTER_SANITIZE_URL));
$source_html_url_host = $url['host'];
$source_html_url_scheme = $url['scheme'];
private function add_build_env_variables_to_dockerfile()
{
$this->execute_remote_command([
$this->execute_in_builder("cat {$this->workdir}/Dockerfile"), "hidden" => true, "save" => 'dockerfile'
]);
$dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile'))->trim()->explode("\n"));
if ($this->source->getMorphClass() == 'App\Models\GithubApp') {
if ($this->source->is_public) {
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->workdir}";
$git_clone_command = $this->set_git_import_settings($git_clone_command);
$commands->push($this->execute_in_builder($git_clone_command));
} else {
$github_access_token = generate_github_installation_token($this->source);
$commands->push($this->execute_in_builder("git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->application->git_repository}.git {$this->workdir}"));
}
if ($this->pull_request_id !== 0) {
$commands->push($this->execute_in_builder("cd {$this->workdir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name"));
}
return $commands->implode(' && ');
}
foreach ($this->application->build_environment_variables as $env) {
$dockerfile->splice(1, 0, "ARG {$env->key}={$env->value}");
}
if ($this->application->deploymentType() === 'deploy_key') {
$private_key = base64_encode($this->application->private_key->private_key);
$git_clone_command = "GIT_SSH_COMMAND=\"ssh -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_full_url} {$this->workdir}";
$git_clone_command = $this->set_git_import_settings($git_clone_command);
$commands = collect([
$this->execute_in_builder("mkdir -p /root/.ssh"),
$this->execute_in_builder("echo '{$private_key}' | base64 -d > /root/.ssh/id_rsa"),
$this->execute_in_builder("chmod 600 /root/.ssh/id_rsa"),
$this->execute_in_builder($git_clone_command)
$dockerfile_base64 = base64_encode($dockerfile->implode("\n"));
$this->execute_remote_command([
$this->execute_in_builder("echo '{$dockerfile_base64}' | base64 -d > {$this->workdir}/Dockerfile"),
"hidden" => true
]);
}
private function next(string $status)
{
// If the deployment is cancelled by the user, don't update the status
if ($this->application_deployment_queue->status !== ApplicationDeploymentStatus::CANCELLED_BY_USER->value) {
$this->application_deployment_queue->update([
'status' => $status,
]);
return $commands->implode(' && ');
}
queue_next_deployment($this->application);
if ($status === ApplicationDeploymentStatus::FINISHED->value) {
$this->application->environment->project->team->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
}
if ($status === ApplicationDeploymentStatus::FAILED->value) {
$this->application->environment->project->team->notify(new DeploymentFailed($this->application, $this->deployment_uuid, $this->preview));
}
}
private function clone_repository()
public function failed(Throwable $exception): void
{
$this->execute_remote_command(
[
"echo -n 'Importing {$this->application->git_repository}:{$this->application->git_branch} to {$this->workdir}. '"
],
[
$this->importing_git_repository()
],
[
$this->execute_in_builder("cd {$this->workdir} && git rev-parse HEAD"),
"hidden" => true,
"save" => "git_commit_sha"
],
["echo 'Oops something is not okay, are you okay? 😢'"],
["echo '{$exception->getMessage()}'"]
);
$this->commit = $this->saved_outputs->get('git_commit_sha');
$this->next(ApplicationDeploymentStatus::FAILED->value);
}
}
}

View File

@ -22,11 +22,13 @@ class ApplicationPullRequestUpdateJob implements ShouldQueue
public function __construct(
public string $application_id,
public int $pull_request_id,
public int $pull_request_id,
public string $deployment_uuid,
public string $status
) {
)
{
}
public function handle()
{
try {
@ -61,6 +63,7 @@ public function handle()
throw $e;
}
}
private function update_comment()
{
['data' => $data] = git_api(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/comments/{$this->preview->pull_request_issue_comment_id}", method: 'patch', data: [
@ -71,6 +74,7 @@ private function update_comment()
$this->create_comment();
}
}
private function create_comment()
{
['data' => $data] = git_api(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/{$this->pull_request_id}/comments", method: 'post', data: [

View File

@ -3,15 +3,11 @@
namespace App\Jobs;
use App\Actions\License\CheckResaleLicense;
use App\Models\InstanceSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
use Visus\Cuid2\Cuid2;
class CheckResaleLicenseJob implements ShouldQueue
{

View File

@ -2,7 +2,6 @@
namespace App\Jobs;
use App\Models\Application;
use App\Models\ApplicationPreview;
use App\Notifications\Application\StatusChanged;
use Illuminate\Bus\Queueable;
@ -11,7 +10,6 @@
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class ContainerStatusJob implements ShouldQueue, ShouldBeUnique
{
@ -27,10 +25,12 @@ public function __construct($resource, string $container_name, string|null $pull
$this->container_name = $container_name;
$this->pull_request_id = $pull_request_id;
}
public function uniqueId(): string
{
return $this->container_name;
}
public function handle(): void
{
try {

View File

@ -19,8 +19,9 @@ class CoolifyTask implements ShouldQueue
*/
public function __construct(
public Activity $activity,
public bool $ignore_errors = false,
) {
public bool $ignore_errors = false,
)
{
}
/**

View File

@ -8,13 +8,14 @@
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class DockerCleanupJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $timeout = 500;
/**
* Create a new job instance.
*/

View File

@ -15,10 +15,12 @@ class InstanceApplicationsStatusJob implements ShouldQueue, ShouldBeUnique
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $applications;
public function __construct()
{
$this->applications = Application::all();
}
public function handle(): void
{
try {

View File

@ -3,9 +3,6 @@
namespace App\Jobs;
use App\Actions\Server\UpdateCoolify;
use App\Models\InstanceSettings;
use App\Models\Server;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -22,6 +19,7 @@ class InstanceAutoUpdateJob implements ShouldQueue, ShouldBeUnique
public function __construct(private bool $force = false)
{
}
public function handle(): void
{
resolve(UpdateCoolify::class)($this->force);

View File

@ -3,7 +3,6 @@
namespace App\Jobs;
use App\Actions\Proxy\StartProxy;
use App\Enums\ProxyTypes;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -18,6 +17,7 @@ class ProxyCheckJob implements ShouldQueue
public function __construct()
{
}
public function handle()
{
try {

View File

@ -9,8 +9,8 @@
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Str;
class ProxyContainerStatusJob implements ShouldQueue, ShouldBeUnique
@ -20,18 +20,22 @@ class ProxyContainerStatusJob implements ShouldQueue, ShouldBeUnique
public Server $server;
public $tries = 1;
public $timeout = 120;
public function middleware(): array
{
return [new WithoutOverlapping($this->server->id)];
}
public function __construct(Server $server)
{
$this->server = $server;
}
public function middleware(): array
{
return [new WithoutOverlapping($this->server->id)];
}
public function uniqueId(): int
{
return $this->server->id;
}
public function handle(): void
{
try {

View File

@ -17,6 +17,7 @@ class ProxyStartJob implements ShouldQueue
public function __construct(protected Server $server)
{
}
public function handle()
{
try {

View File

@ -3,7 +3,6 @@
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
@ -29,7 +28,8 @@ class SendMessageToDiscordJob implements ShouldQueue
public function __construct(
public string $text,
public string $webhookUrl
) {
)
{
}
/**

View File

@ -2,28 +2,12 @@
namespace App\Models;
use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Spatie\Activitylog\Models\Activity;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Masmerise\Toaster\Toastable;
use Masmerise\Toaster\Toaster;
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
use Spatie\Activitylog\Models\Activity;
class Application extends BaseModel
{
protected static function booted()
{
static::created(function ($application) {
ApplicationSetting::create([
'application_id' => $application->id,
]);
});
static::deleting(function ($application) {
$application->settings()->delete();
$application->persistentStorages()->delete();
});
}
protected $fillable = [
'name',
'repository_project_id',
@ -43,15 +27,42 @@ protected static function booted()
'publish_directory',
'private_key_id'
];
public function type() {
protected static function booted()
{
static::created(function ($application) {
ApplicationSetting::create([
'application_id' => $application->id,
]);
});
static::deleting(function ($application) {
$application->settings()->delete();
$application->persistentStorages()->delete();
});
}
public function settings()
{
return $this->hasOne(ApplicationSetting::class);
}
public function persistentStorages()
{
return $this->morphMany(LocalPersistentVolume::class, 'resource');
}
public function type()
{
return 'application';
}
public function publishDirectory(): Attribute
{
return Attribute::make(
set: fn ($value) => $value ? '/' . ltrim($value, '/') : null,
set: fn($value) => $value ? '/' . ltrim($value, '/') : null,
);
}
public function gitBranchLocation(): Attribute
{
return Attribute::make(
@ -63,6 +74,7 @@ public function gitBranchLocation(): Attribute
);
}
public function gitCommits(): Attribute
{
return Attribute::make(
@ -73,99 +85,108 @@ public function gitCommits(): Attribute
}
);
}
public function baseDirectory(): Attribute
{
return Attribute::make(
set: fn ($value) => '/' . ltrim($value, '/'),
set: fn($value) => '/' . ltrim($value, '/'),
);
}
public function portsMappings(): Attribute
{
return Attribute::make(
set: fn ($value) => $value === "" ? null : $value,
set: fn($value) => $value === "" ? null : $value,
);
}
// Normal Deployments
public function portsMappingsArray(): Attribute
{
return Attribute::make(
get: fn () =>
is_null($this->ports_mappings)
get: fn() => is_null($this->ports_mappings)
? []
: explode(',', $this->ports_mappings),
);
}
public function portsExposesArray(): Attribute
{
return Attribute::make(
get: fn () =>
is_null($this->ports_exposes)
get: fn() => is_null($this->ports_exposes)
? []
: explode(',', $this->ports_exposes)
);
}
// Normal Deployments
public function environment_variables(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', false);
}
public function runtime_environment_variables(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', false)->where('key', 'not like', 'NIXPACKS_%');
}
// Preview Deployments
public function build_environment_variables(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', false)->where('is_build_time', true)->where('key', 'not like', 'NIXPACKS_%');
}
public function nixpacks_environment_variables(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', false)->where('key', 'like', 'NIXPACKS_%');
}
// Preview Deployments
public function environment_variables_preview(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', true);
}
public function runtime_environment_variables_preview(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', true)->where('key', 'not like', 'NIXPACKS_%');
}
public function build_environment_variables_preview(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', true)->where('is_build_time', true)->where('key', 'not like', 'NIXPACKS_%');
}
public function nixpacks_environment_variables_preview(): HasMany
{
return $this->hasMany(EnvironmentVariable::class)->where('is_preview', true)->where('key', 'like', 'NIXPACKS_%');
}
public function private_key()
{
return $this->belongsTo(PrivateKey::class);
}
public function environment()
{
return $this->belongsTo(Environment::class);
}
public function previews()
{
return $this->hasMany(ApplicationPreview::class);
}
public function settings()
{
return $this->hasOne(ApplicationSetting::class);
}
public function destination()
{
return $this->morphTo();
}
public function source()
{
return $this->morphTo();
}
public function persistentStorages()
{
return $this->morphMany(LocalPersistentVolume::class, 'resource');
}
public function deployments(int $skip = 0, int $take = 10)
{
@ -177,10 +198,12 @@ public function deployments(int $skip = 0, int $take = 10)
'deployments' => $deployments
];
}
public function get_deployment(string $deployment_uuid)
{
return Activity::where('subject_id', $this->id)->where('properties->type_uuid', '=', $deployment_uuid)->first();
}
public function isDeployable(): bool
{
if ($this->settings->is_auto_deploy_enabled) {
@ -188,6 +211,7 @@ public function isDeployable(): bool
}
return false;
}
public function isPRDeployable(): bool
{
if ($this->settings->is_preview_deployments_enabled) {
@ -195,6 +219,7 @@ public function isPRDeployable(): bool
}
return false;
}
public function deploymentType()
{
if (data_get($this, 'private_key_id')) {

View File

@ -13,12 +13,14 @@ class ApplicationPreview extends BaseModel
'status',
'application_id',
];
public function application()
{
return $this->belongsTo(Application::class);
}
static function findPreviewByApplicationAndPullId(int $application_id, int $pull_request_id)
{
return self::where('application_id', $application_id)->where('pull_request_id', $pull_request_id)->firstOrFail();
}
public function application()
{
return $this->belongsTo(Application::class);
}
}

View File

@ -26,6 +26,7 @@ class ApplicationSetting extends Model
'is_git_submodules_enabled',
'is_git_lfs_enabled',
];
public function isStatic(): Attribute
{
return Attribute::make(
@ -42,6 +43,7 @@ public function isStatic(): Attribute
}
);
}
public function application()
{
return $this->belongsTo(Application::class);

View File

@ -14,7 +14,7 @@ protected static function boot()
static::creating(function (Model $model) {
// Generate a UUID if one isn't set
if (!$model->uuid) {
$model->uuid = (string) new Cuid2(7);
$model->uuid = (string)new Cuid2(7);
}
});
}

View File

@ -8,6 +8,7 @@ public function environment()
{
return $this->belongsTo(Environment::class);
}
public function destination()
{
return $this->morphTo();

Some files were not shown because too many files have changed in this diff Show More