mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-18 12:33:06 +00:00
Compare commits
129 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b47c327b55 | ||
|
|
25434a7acd | ||
|
|
0de042dbac | ||
|
|
eb9e2203b0 | ||
|
|
dcaa7a6ad7 | ||
|
|
5b584a6c6d | ||
|
|
c40ea6f1da | ||
|
|
61a7b9ac94 | ||
|
|
9e81416fef | ||
|
|
c58706e3e4 | ||
|
|
45bca8649b | ||
|
|
b095b88281 | ||
|
|
cb41584137 | ||
|
|
6659153804 | ||
|
|
44c429a224 | ||
|
|
fe9c501c1d | ||
|
|
4e94b4a0c1 | ||
|
|
2f4d7c0e43 | ||
|
|
e443fc394a | ||
|
|
5b56c50f03 | ||
|
|
3adeb2f73f | ||
|
|
9eaa13a08a | ||
|
|
df5a4a9667 | ||
|
|
26048339d6 | ||
|
|
d85af3fefc | ||
|
|
575338609b | ||
|
|
d32e43ef37 | ||
|
|
a96ef1bfab | ||
|
|
1bfedf69f2 | ||
|
|
208fe7d87b | ||
|
|
a6d58b5d72 | ||
|
|
277b4276e6 | ||
|
|
f6adc9285a | ||
|
|
f03bbe0e95 | ||
|
|
535375193c | ||
|
|
d79c063fd6 | ||
|
|
35f45492e3 | ||
|
|
ab8a7893d9 | ||
|
|
76b8d048d4 | ||
|
|
0e583334e7 | ||
|
|
0ad8ca224f | ||
|
|
050e56f69a | ||
|
|
6099ac11d9 | ||
|
|
adac728a60 | ||
|
|
e2e64e36a0 | ||
|
|
762af66cbf | ||
|
|
b08f525bd4 | ||
|
|
5ae16b195c | ||
|
|
91db1953ff | ||
|
|
1c8f92d3b7 | ||
|
|
4075572dbc | ||
|
|
2971e360d7 | ||
|
|
32bb2780f2 | ||
|
|
af69575b29 | ||
|
|
d4a7d0d25f | ||
|
|
45f9def0f6 | ||
|
|
5a90eed7ef | ||
|
|
38e1f17edf | ||
|
|
1651845e20 | ||
|
|
38e96548b5 | ||
|
|
47e4126dca | ||
|
|
e0b175ab07 | ||
|
|
93ec785f4f | ||
|
|
e849addab8 | ||
|
|
a5e6975dac | ||
|
|
4ac8e1cc67 | ||
|
|
1a5e3a7836 | ||
|
|
4498d1ed4b | ||
|
|
c8b974820b | ||
|
|
527373e297 | ||
|
|
a84be8dc33 | ||
|
|
bd856f7f67 | ||
|
|
8ff216e5fb | ||
|
|
5255311a2e | ||
|
|
774a245e84 | ||
|
|
194675c838 | ||
|
|
75862ca8de | ||
|
|
5580a4e704 | ||
|
|
51e601a303 | ||
|
|
734e9fd68d | ||
|
|
09fc950ae8 | ||
|
|
cf6caa279d | ||
|
|
68c976ab70 | ||
|
|
1560ab2a50 | ||
|
|
e3a6458506 | ||
|
|
1768b9374f | ||
|
|
51d0a30a6c | ||
|
|
9701c65297 | ||
|
|
58e3bb2571 | ||
|
|
31cbd1602d | ||
|
|
dd5723d596 | ||
|
|
620f26a6f1 | ||
|
|
540717e809 | ||
|
|
d446cd4103 | ||
|
|
7d1a76570c | ||
|
|
e18766ec21 | ||
|
|
3d0354cf7e | ||
|
|
af5b9fced1 | ||
|
|
ab5202515e | ||
|
|
f863db7ea5 | ||
|
|
3adc0bdd6e | ||
|
|
97027875bf | ||
|
|
fd9c13009f | ||
|
|
46a72fac47 | ||
|
|
5d6ee04991 | ||
|
|
d523becb29 | ||
|
|
41672f75d0 | ||
|
|
acd8541e68 | ||
|
|
ed6af777a4 | ||
|
|
05f162f4e8 | ||
|
|
5e0adc3777 | ||
|
|
7d06fc4403 | ||
|
|
0e1bcceb8e | ||
|
|
a922f2fedf | ||
|
|
1e0226c8ed | ||
|
|
5c45908087 | ||
|
|
aefdc76805 | ||
|
|
b3c8c881b7 | ||
|
|
9ab5a1f7bd | ||
|
|
23968e7886 | ||
|
|
390d24b6d7 | ||
|
|
e4296345b3 | ||
|
|
bcffbe418b | ||
|
|
bfbee4e78f | ||
|
|
2bdb44dac3 | ||
|
|
4daa1b8c16 | ||
|
|
febc399568 | ||
|
|
9b9d4f9941 | ||
|
|
f49b87870c |
@@ -1,11 +1,3 @@
|
|||||||
############################################################################################################
|
|
||||||
# Development Environment
|
|
||||||
|
|
||||||
# User and group id for the user that will run the application inside the container
|
|
||||||
# Run in your terminal: `id -u` and `id -g` and that's the results
|
|
||||||
USERID=
|
|
||||||
GROUPID=
|
|
||||||
############################################################################################################
|
|
||||||
APP_NAME=Coolify-localhost
|
APP_NAME=Coolify-localhost
|
||||||
APP_ID=development
|
APP_ID=development
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
@@ -13,6 +5,7 @@ APP_KEY=
|
|||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
APP_URL=http://localhost
|
APP_URL=http://localhost
|
||||||
APP_PORT=8000
|
APP_PORT=8000
|
||||||
|
MUX_ENABLED=false
|
||||||
|
|
||||||
DUSK_DRIVER_URL=http://selenium:4444
|
DUSK_DRIVER_URL=http://selenium:4444
|
||||||
|
|
||||||
|
|||||||
29
CONTRIBUTION.md
Normal file
29
CONTRIBUTION.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
> "First, thanks for considering to contribute to my project.
|
||||||
|
It really means a lot!" - [@andrasbacsai](https://github.com/andrasbacsai)
|
||||||
|
|
||||||
|
You can ask for guidance anytime on our
|
||||||
|
[Discord server](https://coollabs.io/discord) in the `#contribution` channel.
|
||||||
|
|
||||||
|
|
||||||
|
## 1) Setup your development environment
|
||||||
|
|
||||||
|
- You need to have Docker Engine (or equivalent) [installed](https://docs.docker.com/engine/install/) on your system.
|
||||||
|
- For better DX, install [Spin](https://serversideup.net/open-source/spin/).
|
||||||
|
|
||||||
|
## 2) Set your environment variables
|
||||||
|
|
||||||
|
- Copy [.env.development.example](./.env.development.example) to .env.
|
||||||
|
|
||||||
|
## 3) Start & setup Coolify
|
||||||
|
|
||||||
|
- Run `spin up` - You can notice that errors will be thrown. Don't worry.
|
||||||
|
- If you see weird permission errors, especially on Mac, run `sudo spin up` instead.
|
||||||
|
|
||||||
|
- Run `./scripts/run setup:dev` - This will generate a secret key for you, delete any existing database layouts, migrate database to the new layout, and seed your database.
|
||||||
|
|
||||||
|
## 4) Start development
|
||||||
|
You can login your Coolify instance at `localhost:8000` with `test@example.com` and `password`.
|
||||||
|
|
||||||
|
Your horizon (Laravel scheduler): `localhost:8000/horizon` - Only reachable if you logged in with root user.
|
||||||
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
namespace App\Actions\Server;
|
namespace App\Actions\Server;
|
||||||
|
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\StandaloneDocker;
|
use App\Models\StandaloneDocker;
|
||||||
|
|
||||||
class InstallDocker
|
class InstallDocker
|
||||||
{
|
{
|
||||||
public function __invoke(Server $server)
|
use AsAction;
|
||||||
|
public function handle(Server $server)
|
||||||
{
|
{
|
||||||
$dockerVersion = '24.0';
|
$dockerVersion = '24.0';
|
||||||
$config = base64_encode('{
|
$config = base64_encode('{
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ namespace App\Actions\Service;
|
|||||||
|
|
||||||
use Lorisleiva\Actions\Concerns\AsAction;
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
class StartService
|
class StartService
|
||||||
{
|
{
|
||||||
use AsAction;
|
use AsAction;
|
||||||
public function handle(Service $service)
|
public function handle(Service $service)
|
||||||
{
|
{
|
||||||
|
$network = $service->destination->network;
|
||||||
$service->saveComposeConfigs();
|
$service->saveComposeConfigs();
|
||||||
$commands[] = "cd " . $service->workdir();
|
$commands[] = "cd " . $service->workdir();
|
||||||
$commands[] = "echo '####### Saved configuration files to {$service->workdir()}.'";
|
$commands[] = "echo '####### Saved configuration files to {$service->workdir()}.'";
|
||||||
@@ -21,6 +23,11 @@ class StartService
|
|||||||
$commands[] = "echo '####### Starting containers.'";
|
$commands[] = "echo '####### Starting containers.'";
|
||||||
$commands[] = "docker compose up -d --remove-orphans --force-recreate";
|
$commands[] = "docker compose up -d --remove-orphans --force-recreate";
|
||||||
$commands[] = "docker network connect $service->uuid coolify-proxy 2>/dev/null || true";
|
$commands[] = "docker network connect $service->uuid coolify-proxy 2>/dev/null || true";
|
||||||
|
$compose = data_get($service,'docker_compose',[]);
|
||||||
|
$serviceNames = data_get(Yaml::parse($compose),'services',[]);
|
||||||
|
foreach($serviceNames as $serviceName => $serviceConfig){
|
||||||
|
$commands[] = "docker network connect --alias {$serviceName}-{$service->uuid} $network {$serviceName}-{$service->uuid} 2>/dev/null || true";
|
||||||
|
}
|
||||||
$activity = remote_process($commands, $service->server);
|
$activity = remote_process($commands, $service->server);
|
||||||
return $activity;
|
return $activity;
|
||||||
}
|
}
|
||||||
|
|||||||
33
app/Console/Commands/Cloud.php
Normal file
33
app/Console/Commands/Cloud.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class Cloud extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'cloud:unused-servers';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Get Unused Servers from Cloud';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
Server::all()->whereNotNull('team.subscription')->where('team.subscription.stripe_trial_already_ended',true)->each(function($server){
|
||||||
|
$this->info($server->name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
108
app/Console/Commands/ResourcesDelete.php
Normal file
108
app/Console/Commands/ResourcesDelete.php
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Models\Service;
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
use function Laravel\Prompts\confirm;
|
||||||
|
use function Laravel\Prompts\multiselect;
|
||||||
|
use function Laravel\Prompts\select;
|
||||||
|
|
||||||
|
class ResourcesDelete extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'resources:delete';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Delete a resource from the database';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$resource = select(
|
||||||
|
'What resource do you want to delete?',
|
||||||
|
['Application', 'Database', 'Service'],
|
||||||
|
);
|
||||||
|
if ($resource === 'Application') {
|
||||||
|
$this->deleteApplication();
|
||||||
|
} elseif ($resource === 'Database') {
|
||||||
|
$this->deleteDatabase();
|
||||||
|
} elseif ($resource === 'Service') {
|
||||||
|
$this->deleteService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private function deleteApplication()
|
||||||
|
{
|
||||||
|
$applications = Application::all();
|
||||||
|
if ($applications->count() === 0) {
|
||||||
|
$this->error('There are no applications to delete.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$applicationsToDelete = multiselect(
|
||||||
|
'What application do you want to delete?',
|
||||||
|
$applications->pluck('name')->toArray(),
|
||||||
|
);
|
||||||
|
$confirmed = confirm("Are you sure you want to delete all selected resources?");
|
||||||
|
if (!$confirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach ($applicationsToDelete as $application) {
|
||||||
|
$toDelete = $applications->where('name', $application)->first();
|
||||||
|
$toDelete->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private function deleteDatabase()
|
||||||
|
{
|
||||||
|
$databases = StandalonePostgresql::all();
|
||||||
|
if ($databases->count() === 0) {
|
||||||
|
$this->error('There are no databases to delete.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$databasesToDelete = multiselect(
|
||||||
|
'What database do you want to delete?',
|
||||||
|
$databases->pluck('name')->toArray(),
|
||||||
|
);
|
||||||
|
$confirmed = confirm("Are you sure you want to delete all selected resources?");
|
||||||
|
if (!$confirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach ($databasesToDelete as $database) {
|
||||||
|
$toDelete = $databases->where('name', $database)->first();
|
||||||
|
$toDelete->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private function deleteService()
|
||||||
|
{
|
||||||
|
$services = Service::all();
|
||||||
|
if ($services->count() === 0) {
|
||||||
|
$this->error('There are no services to delete.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$servicesToDelete = multiselect(
|
||||||
|
'What service do you want to delete?',
|
||||||
|
$services->pluck('name')->toArray(),
|
||||||
|
);
|
||||||
|
$confirmed = confirm("Are you sure you want to delete all selected resources?");
|
||||||
|
if (!$confirmed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach ($servicesToDelete as $service) {
|
||||||
|
$toDelete = $services->where('name', $service)->first();
|
||||||
|
$toDelete->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
app/Console/Commands/UsersResetRoot.php
Normal file
49
app/Console/Commands/UsersResetRoot.php
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
|
use function Laravel\Prompts\password;
|
||||||
|
|
||||||
|
class UsersResetRoot extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'users:reset-root';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Reset Root Password';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
$this->info('You are about to reset the root password.');
|
||||||
|
$password = password('Give me a new password for root user: ');
|
||||||
|
$passwordAgain = password('Again');
|
||||||
|
if ($password != $passwordAgain) {
|
||||||
|
$this->error('Passwords do not match.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->info('Updating root password...');
|
||||||
|
try {
|
||||||
|
User::find(0)->update(['password' => Hash::make($password)]);
|
||||||
|
$this->info('Root password updated successfully.');
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error('Failed to update root password.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,11 @@ class Kernel extends ConsoleKernel
|
|||||||
}
|
}
|
||||||
private function check_resources($schedule)
|
private function check_resources($schedule)
|
||||||
{
|
{
|
||||||
$servers = Server::all()->where('settings.is_usable', true)->where('settings.is_reachable', true);
|
if (isCloud()) {
|
||||||
|
$servers = Server::all()->whereNotNull('team.subscription')->where('team.subscription.stripe_trial_already_ended', false);
|
||||||
|
} else {
|
||||||
|
$servers = Server::all();
|
||||||
|
}
|
||||||
foreach ($servers as $server) {
|
foreach ($servers as $server) {
|
||||||
$schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer();
|
$schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use App\Models\EnvironmentVariable;
|
|||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use App\Models\StandaloneDocker;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class ProjectController extends Controller
|
class ProjectController extends Controller
|
||||||
@@ -69,17 +69,19 @@ class ProjectController extends Controller
|
|||||||
if ($type->startsWith('one-click-service-') && !is_null( (int)$server_id)) {
|
if ($type->startsWith('one-click-service-') && !is_null( (int)$server_id)) {
|
||||||
$oneClickServiceName = $type->after('one-click-service-')->value();
|
$oneClickServiceName = $type->after('one-click-service-')->value();
|
||||||
$oneClickService = data_get($services, "$oneClickServiceName.compose");
|
$oneClickService = data_get($services, "$oneClickServiceName.compose");
|
||||||
ray($oneClickServiceName);
|
|
||||||
$oneClickDotEnvs = data_get($services, "$oneClickServiceName.envs", null);
|
$oneClickDotEnvs = data_get($services, "$oneClickServiceName.envs", null);
|
||||||
if ($oneClickDotEnvs) {
|
if ($oneClickDotEnvs) {
|
||||||
$oneClickDotEnvs = Str::of(base64_decode($oneClickDotEnvs))->split('/\r\n|\r|\n/');
|
$oneClickDotEnvs = Str::of(base64_decode($oneClickDotEnvs))->split('/\r\n|\r|\n/');
|
||||||
}
|
}
|
||||||
if ($oneClickService) {
|
if ($oneClickService) {
|
||||||
|
$destination = StandaloneDocker::whereUuid($destination_uuid)->first();
|
||||||
$service = Service::create([
|
$service = Service::create([
|
||||||
'name' => "$oneClickServiceName-" . Str::random(10),
|
'name' => "$oneClickServiceName-" . Str::random(10),
|
||||||
'docker_compose_raw' => base64_decode($oneClickService),
|
'docker_compose_raw' => base64_decode($oneClickService),
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $environment->id,
|
||||||
'server_id' => (int) $server_id,
|
'server_id' => (int) $server_id,
|
||||||
|
'destination_id' => $destination->id,
|
||||||
|
'destination_type' => $destination->getMorphClass(),
|
||||||
]);
|
]);
|
||||||
$service->name = "$oneClickServiceName-" . $service->uuid;
|
$service->name = "$oneClickServiceName-" . $service->uuid;
|
||||||
$service->save();
|
$service->save();
|
||||||
@@ -90,6 +92,7 @@ class ProjectController extends Controller
|
|||||||
$generatedValue = $value;
|
$generatedValue = $value;
|
||||||
if ($value->contains('SERVICE_')) {
|
if ($value->contains('SERVICE_')) {
|
||||||
$command = $value->after('SERVICE_')->beforeLast('_');
|
$command = $value->after('SERVICE_')->beforeLast('_');
|
||||||
|
// TODO: make it shared with Service.php
|
||||||
switch ($command->value()) {
|
switch ($command->value()) {
|
||||||
case 'PASSWORD':
|
case 'PASSWORD':
|
||||||
$generatedValue = Str::password(symbols: false);
|
$generatedValue = Str::password(symbols: false);
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Models\PrivateKey;
|
|
||||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
|
||||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
|
||||||
|
|
||||||
class ServerController extends Controller
|
|
||||||
{
|
|
||||||
use AuthorizesRequests, ValidatesRequests;
|
|
||||||
|
|
||||||
public function new_server()
|
|
||||||
{
|
|
||||||
$privateKeys = PrivateKey::ownedByCurrentTeam()->get();
|
|
||||||
if (!isCloud()) {
|
|
||||||
return view('server.create', [
|
|
||||||
'limit_reached' => false,
|
|
||||||
'private_keys' => $privateKeys,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
$team = currentTeam();
|
|
||||||
$servers = $team->servers->count();
|
|
||||||
['serverLimit' => $serverLimit] = $team->limits;
|
|
||||||
$limit_reached = $servers >= $serverLimit;
|
|
||||||
|
|
||||||
return view('server.create', [
|
|
||||||
'limit_reached' => $limit_reached,
|
|
||||||
'private_keys' => $privateKeys,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -76,7 +76,6 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
Team::find(currentTeam()->id)->update([
|
Team::find(currentTeam()->id)->update([
|
||||||
'show_boarding' => false
|
'show_boarding' => false
|
||||||
]);
|
]);
|
||||||
ray(currentTeam());
|
|
||||||
refreshSession();
|
refreshSession();
|
||||||
return redirect()->route('dashboard');
|
return redirect()->route('dashboard');
|
||||||
}
|
}
|
||||||
@@ -221,7 +220,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
public function installDocker()
|
public function installDocker()
|
||||||
{
|
{
|
||||||
$this->dockerInstallationStarted = true;
|
$this->dockerInstallationStarted = true;
|
||||||
$activity = resolve(InstallDocker::class)($this->createdServer);
|
$activity = InstallDocker::run($this->createdServer);
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
}
|
}
|
||||||
public function dockerInstalledOrSkipped()
|
public function dockerInstalledOrSkipped()
|
||||||
|
|||||||
28
app/Http/Livewire/Dev/Compose.php
Normal file
28
app/Http/Livewire/Dev/Compose.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Dev;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Compose extends Component
|
||||||
|
{
|
||||||
|
public string $compose = '';
|
||||||
|
public string $base64 = '';
|
||||||
|
public $services;
|
||||||
|
public function mount() {
|
||||||
|
$this->services = getServiceTemplates();
|
||||||
|
}
|
||||||
|
public function setService(string $selected) {
|
||||||
|
$this->base64 = data_get($this->services, $selected . '.compose');
|
||||||
|
if ($this->base64) {
|
||||||
|
$this->compose = base64_decode($this->base64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function updatedCompose($value) {
|
||||||
|
$this->base64 = base64_encode($value);
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.dev.compose');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,10 +17,10 @@ class General extends Component
|
|||||||
public Application $application;
|
public Application $application;
|
||||||
public Collection $services;
|
public Collection $services;
|
||||||
public string $name;
|
public string $name;
|
||||||
public string|null $fqdn;
|
public ?string $fqdn = null;
|
||||||
public string $git_repository;
|
public string $git_repository;
|
||||||
public string $git_branch;
|
public string $git_branch;
|
||||||
public string|null $git_commit_sha;
|
public ?string $git_commit_sha = null;
|
||||||
public string $build_pack;
|
public string $build_pack;
|
||||||
|
|
||||||
public bool $is_static;
|
public bool $is_static;
|
||||||
@@ -104,6 +104,7 @@ class General extends Component
|
|||||||
}
|
}
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
|
if (data_get($this->application,'settings')) {
|
||||||
$this->is_static = $this->application->settings->is_static;
|
$this->is_static = $this->application->settings->is_static;
|
||||||
$this->is_git_submodules_enabled = $this->application->settings->is_git_submodules_enabled;
|
$this->is_git_submodules_enabled = $this->application->settings->is_git_submodules_enabled;
|
||||||
$this->is_git_lfs_enabled = $this->application->settings->is_git_lfs_enabled;
|
$this->is_git_lfs_enabled = $this->application->settings->is_git_lfs_enabled;
|
||||||
@@ -112,6 +113,7 @@ class General extends Component
|
|||||||
$this->is_auto_deploy_enabled = $this->application->settings->is_auto_deploy_enabled;
|
$this->is_auto_deploy_enabled = $this->application->settings->is_auto_deploy_enabled;
|
||||||
$this->is_force_https_enabled = $this->application->settings->is_force_https_enabled;
|
$this->is_force_https_enabled = $this->application->settings->is_force_https_enabled;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
@@ -125,7 +127,7 @@ class General extends Component
|
|||||||
}
|
}
|
||||||
if (data_get($this->application, 'dockerfile')) {
|
if (data_get($this->application, 'dockerfile')) {
|
||||||
$port = get_port_from_dockerfile($this->application->dockerfile);
|
$port = get_port_from_dockerfile($this->application->dockerfile);
|
||||||
if ($port) {
|
if ($port && !$this->application->ports_exposes) {
|
||||||
$this->application->ports_exposes = $port;
|
$this->application->ports_exposes = $port;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ class Form extends Component
|
|||||||
public function generate_real_url()
|
public function generate_real_url()
|
||||||
{
|
{
|
||||||
if (data_get($this->application, 'fqdn')) {
|
if (data_get($this->application, 'fqdn')) {
|
||||||
$url = Url::fromString($this->application->fqdn);
|
$firstFqdn = Str::of($this->application->fqdn)->before(',');
|
||||||
|
$url = Url::fromString($firstFqdn);
|
||||||
$host = $url->getHost();
|
$host = $url->getHost();
|
||||||
$this->preview_url_template = Str::of($this->application->preview_url_template)->replace('{{domain}}', $host);
|
$this->preview_url_template = Str::of($this->application->preview_url_template)->replace('{{domain}}', $host);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class Previews extends Component
|
|||||||
public function load_prs()
|
public function load_prs()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
['rate_limit_remaining' => $rate_limit_remaining, 'data' => $data] = git_api(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/pulls");
|
['rate_limit_remaining' => $rate_limit_remaining, 'data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/pulls");
|
||||||
$this->rate_limit_remaining = $rate_limit_remaining;
|
$this->rate_limit_remaining = $rate_limit_remaining;
|
||||||
$this->pull_requests = $data->sortBy('number')->values();
|
$this->pull_requests = $data->sortBy('number')->values();
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
@@ -72,8 +72,7 @@ class Previews extends Component
|
|||||||
public function stop(int $pull_request_id)
|
public function stop(int $pull_request_id)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$container_name = generateApplicationContainerName($this->application);
|
$container_name = generateApplicationContainerName($this->application, $pull_request_id);
|
||||||
ray('Stopping container: ' . $container_name);
|
|
||||||
|
|
||||||
instant_remote_process(["docker rm -f $container_name"], $this->application->destination->server, throwError: false);
|
instant_remote_process(["docker rm -f $container_name"], $this->application->destination->server, throwError: false);
|
||||||
ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->delete();
|
ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->delete();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class CreateScheduledBackup extends Component
|
|||||||
public $database;
|
public $database;
|
||||||
public $frequency;
|
public $frequency;
|
||||||
public bool $enabled = true;
|
public bool $enabled = true;
|
||||||
public bool $save_s3 = true;
|
public bool $save_s3 = false;
|
||||||
public $s3_storage_id;
|
public $s3_storage_id;
|
||||||
public $s3s;
|
public $s3s;
|
||||||
|
|
||||||
|
|||||||
@@ -50,8 +50,9 @@ class General extends Component
|
|||||||
$this->getDbUrl();
|
$this->getDbUrl();
|
||||||
}
|
}
|
||||||
public function getDbUrl() {
|
public function getDbUrl() {
|
||||||
|
|
||||||
if ($this->database->is_public) {
|
if ($this->database->is_public) {
|
||||||
$this->db_url = "postgres://{$this->database->postgres_user}:{$this->database->postgres_password}@{$this->database->destination->server->ip}:{$this->database->public_port}/{$this->database->postgres_db}";
|
$this->db_url = "postgres://{$this->database->postgres_user}:{$this->database->postgres_password}@{$this->database->destination->server->getIp}:{$this->database->public_port}/{$this->database->postgres_db}";
|
||||||
} else {
|
} else {
|
||||||
$this->db_url = "postgres://{$this->database->postgres_user}:{$this->database->postgres_password}@{$this->database->uuid}:5432/{$this->database->postgres_db}";
|
$this->db_url = "postgres://{$this->database->postgres_user}:{$this->database->postgres_password}@{$this->database->uuid}:5432/{$this->database->postgres_db}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ class DockerCompose extends Component
|
|||||||
- type: volume
|
- type: volume
|
||||||
source: mydata
|
source: mydata
|
||||||
target: /data
|
target: /data
|
||||||
volume:
|
|
||||||
nocopy: true
|
|
||||||
- type: bind
|
- type: bind
|
||||||
source: ./var/lib/ghost/data
|
source: ./var/lib/ghost/data
|
||||||
target: /data
|
target: /data
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use App\Models\StandaloneDocker;
|
|||||||
use App\Models\SwarmDocker;
|
use App\Models\SwarmDocker;
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class GithubPrivateRepositoryDeployKey extends Component
|
class GithubPrivateRepositoryDeployKey extends Component
|
||||||
{
|
{
|
||||||
@@ -29,7 +30,7 @@ class GithubPrivateRepositoryDeployKey extends Component
|
|||||||
public string $repository_url;
|
public string $repository_url;
|
||||||
public string $branch;
|
public string $branch;
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'repository_url' => 'required|url',
|
'repository_url' => 'required',
|
||||||
'branch' => 'required|string',
|
'branch' => 'required|string',
|
||||||
'port' => 'required|numeric',
|
'port' => 'required|numeric',
|
||||||
'is_static' => 'required|boolean',
|
'is_static' => 'required|boolean',
|
||||||
@@ -43,8 +44,8 @@ class GithubPrivateRepositoryDeployKey extends Component
|
|||||||
'publish_directory' => 'Publish directory',
|
'publish_directory' => 'Publish directory',
|
||||||
];
|
];
|
||||||
private object $repository_url_parsed;
|
private object $repository_url_parsed;
|
||||||
private GithubApp|GitlabApp|null $git_source = null;
|
private GithubApp|GitlabApp|string $git_source = 'other';
|
||||||
private string $git_host;
|
private ?string $git_host = null;
|
||||||
private string $git_repository;
|
private string $git_repository;
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
@@ -92,6 +93,21 @@ class GithubPrivateRepositoryDeployKey extends Component
|
|||||||
|
|
||||||
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
|
||||||
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
||||||
|
if ($this->git_source === 'other') {
|
||||||
|
$application_init = [
|
||||||
|
'name' => generate_random_name(),
|
||||||
|
'git_repository' => $this->git_repository,
|
||||||
|
'git_branch' => $this->branch,
|
||||||
|
'git_full_url' => $this->git_repository,
|
||||||
|
'build_pack' => 'nixpacks',
|
||||||
|
'ports_exposes' => $this->port,
|
||||||
|
'publish_directory' => $this->publish_directory,
|
||||||
|
'environment_id' => $environment->id,
|
||||||
|
'destination_id' => $destination->id,
|
||||||
|
'destination_type' => $destination_class,
|
||||||
|
'private_key_id' => $this->private_key_id,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
$application_init = [
|
$application_init = [
|
||||||
'name' => generate_random_name(),
|
'name' => generate_random_name(),
|
||||||
'git_repository' => $this->git_repository,
|
'git_repository' => $this->git_repository,
|
||||||
@@ -107,6 +123,8 @@ class GithubPrivateRepositoryDeployKey extends Component
|
|||||||
'source_id' => $this->git_source->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 = Application::create($application_init);
|
||||||
$application->settings->is_static = $this->is_static;
|
$application->settings->is_static = $this->is_static;
|
||||||
$application->settings->save();
|
$application->settings->save();
|
||||||
@@ -134,10 +152,13 @@ class GithubPrivateRepositoryDeployKey extends Component
|
|||||||
|
|
||||||
if ($this->git_host == 'github.com') {
|
if ($this->git_host == 'github.com') {
|
||||||
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
|
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
|
||||||
} elseif ($this->git_host == 'gitlab.com') {
|
return;
|
||||||
$this->git_source = GitlabApp::where('name', 'Public GitLab')->first();
|
}
|
||||||
} elseif ($this->git_host == 'bitbucket.org') {
|
if (Str::of($this->repository_url)->startsWith('http')) {
|
||||||
// Not supported yet
|
$this->git_host = $this->repository_url_parsed->getHost();
|
||||||
}
|
$this->git_repository = $this->repository_url_parsed->getSegment(1) . '/' . $this->repository_url_parsed->getSegment(2);
|
||||||
|
$this->git_repository = Str::finish("git@$this->git_host:$this->git_repository", '.git');
|
||||||
|
}
|
||||||
|
$this->git_source = 'other';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ class PublicGitRepository extends Component
|
|||||||
public string $git_branch = 'main';
|
public string $git_branch = 'main';
|
||||||
public int $rate_limit_remaining = 0;
|
public int $rate_limit_remaining = 0;
|
||||||
public $rate_limit_reset = 0;
|
public $rate_limit_reset = 0;
|
||||||
|
private object $repository_url_parsed;
|
||||||
|
public GithubApp|GitlabApp|string $git_source = 'other';
|
||||||
|
public string $git_host;
|
||||||
|
public string $git_repository;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'repository_url' => 'required|url',
|
'repository_url' => 'required|url',
|
||||||
'port' => 'required|numeric',
|
'port' => 'required|numeric',
|
||||||
@@ -38,10 +43,6 @@ class PublicGitRepository extends Component
|
|||||||
'is_static' => 'static',
|
'is_static' => 'static',
|
||||||
'publish_directory' => 'publish directory',
|
'publish_directory' => 'publish directory',
|
||||||
];
|
];
|
||||||
private object $repository_url_parsed;
|
|
||||||
private GithubApp|GitlabApp|null $git_source = null;
|
|
||||||
private string $git_host;
|
|
||||||
private string $git_repository;
|
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
@@ -64,7 +65,10 @@ class PublicGitRepository extends Component
|
|||||||
}
|
}
|
||||||
$this->emit('success', 'Application settings updated!');
|
$this->emit('success', 'Application settings updated!');
|
||||||
}
|
}
|
||||||
|
public function load_any_git()
|
||||||
|
{
|
||||||
|
$this->branch_found = true;
|
||||||
|
}
|
||||||
public function load_branch()
|
public function load_branch()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -76,6 +80,7 @@ class PublicGitRepository extends Component
|
|||||||
$this->get_branch();
|
$this->get_branch();
|
||||||
$this->selected_branch = $this->git_branch;
|
$this->selected_branch = $this->git_branch;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
ray($e->getMessage());
|
||||||
if (!$this->branch_found && $this->git_branch == 'main') {
|
if (!$this->branch_found && $this->git_branch == 'main') {
|
||||||
try {
|
try {
|
||||||
$this->git_branch = 'master';
|
$this->git_branch = 'master';
|
||||||
@@ -98,22 +103,24 @@ class PublicGitRepository extends Component
|
|||||||
|
|
||||||
if ($this->git_host == 'github.com') {
|
if ($this->git_host == 'github.com') {
|
||||||
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
|
$this->git_source = GithubApp::where('name', 'Public GitHub')->first();
|
||||||
} elseif ($this->git_host == 'gitlab.com') {
|
return;
|
||||||
$this->git_source = GitlabApp::where('name', 'Public GitLab')->first();
|
|
||||||
} elseif ($this->git_host == 'bitbucket.org') {
|
|
||||||
// Not supported yet
|
|
||||||
}
|
|
||||||
if (is_null($this->git_source)) {
|
|
||||||
throw new \Exception('Git source not found. What?!');
|
|
||||||
}
|
}
|
||||||
|
$this->git_repository = $this->repository_url;
|
||||||
|
$this->git_source = 'other';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function get_branch()
|
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}");
|
if ($this->git_source === 'other') {
|
||||||
|
$this->branch_found = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($this->git_source->getMorphClass() === 'App\Models\GithubApp') {
|
||||||
|
['rate_limit_remaining' => $this->rate_limit_remaining, 'rate_limit_reset' => $this->rate_limit_reset] = githubApi(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->rate_limit_reset = Carbon::parse((int)$this->rate_limit_reset)->format('Y-M-d H:i:s');
|
||||||
$this->branch_found = true;
|
$this->branch_found = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
@@ -123,9 +130,6 @@ class PublicGitRepository extends Component
|
|||||||
$project_uuid = $this->parameters['project_uuid'];
|
$project_uuid = $this->parameters['project_uuid'];
|
||||||
$environment_name = $this->parameters['environment_name'];
|
$environment_name = $this->parameters['environment_name'];
|
||||||
|
|
||||||
$this->get_git_source();
|
|
||||||
$this->git_branch = $this->selected_branch ?? $this->git_branch;
|
|
||||||
|
|
||||||
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
|
$destination = StandaloneDocker::where('uuid', $destination_uuid)->first();
|
||||||
if (!$destination) {
|
if (!$destination) {
|
||||||
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
|
$destination = SwarmDocker::where('uuid', $destination_uuid)->first();
|
||||||
@@ -138,6 +142,19 @@ class PublicGitRepository extends Component
|
|||||||
$project = Project::where('uuid', $project_uuid)->first();
|
$project = Project::where('uuid', $project_uuid)->first();
|
||||||
$environment = $project->load(['environments'])->environments->where('name', $environment_name)->first();
|
$environment = $project->load(['environments'])->environments->where('name', $environment_name)->first();
|
||||||
|
|
||||||
|
if ($this->git_source === 'other') {
|
||||||
|
$application_init = [
|
||||||
|
'name' => generate_random_name(),
|
||||||
|
'git_repository' => $this->git_repository,
|
||||||
|
'git_branch' => $this->git_branch,
|
||||||
|
'build_pack' => 'nixpacks',
|
||||||
|
'ports_exposes' => $this->port,
|
||||||
|
'publish_directory' => $this->publish_directory,
|
||||||
|
'environment_id' => $environment->id,
|
||||||
|
'destination_id' => $destination->id,
|
||||||
|
'destination_type' => $destination_class,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
$application_init = [
|
$application_init = [
|
||||||
'name' => generate_application_name($this->git_repository, $this->git_branch),
|
'name' => generate_application_name($this->git_repository, $this->git_branch),
|
||||||
'git_repository' => $this->git_repository,
|
'git_repository' => $this->git_repository,
|
||||||
@@ -151,6 +168,8 @@ class PublicGitRepository extends Component
|
|||||||
'source_id' => $this->git_source->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 = Application::create($application_init);
|
||||||
|
|
||||||
@@ -159,7 +178,6 @@ class PublicGitRepository extends Component
|
|||||||
|
|
||||||
$fqdn = generateFqdn($destination->server, $application->uuid);
|
$fqdn = generateFqdn($destination->server, $application->uuid);
|
||||||
$application->fqdn = $fqdn;
|
$application->fqdn = $fqdn;
|
||||||
$application->name = generate_application_name($this->git_repository, $this->git_branch, $application->uuid);
|
|
||||||
$application->save();
|
$application->save();
|
||||||
|
|
||||||
return redirect()->route('project.application.configuration', [
|
return redirect()->route('project.application.configuration', [
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ CMD ["nginx", "-g", "daemon off;"]
|
|||||||
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
|
||||||
|
|
||||||
$port = get_port_from_dockerfile($this->dockerfile);
|
$port = get_port_from_dockerfile($this->dockerfile);
|
||||||
|
if (!$port) {
|
||||||
|
$port = 80;
|
||||||
|
}
|
||||||
$application = Application::create([
|
$application = Application::create([
|
||||||
'name' => 'dockerfile-' . new Cuid2(7),
|
'name' => 'dockerfile-' . new Cuid2(7),
|
||||||
'repository_project_id' => 0,
|
'repository_project_id' => 0,
|
||||||
@@ -56,6 +59,7 @@ CMD ["nginx", "-g", "daemon off;"]
|
|||||||
'environment_id' => $environment->id,
|
'environment_id' => $environment->id,
|
||||||
'destination_id' => $destination->id,
|
'destination_id' => $destination->id,
|
||||||
'destination_type' => $destination_class,
|
'destination_type' => $destination_class,
|
||||||
|
'health_check_enabled' => false,
|
||||||
'source_id' => 0,
|
'source_id' => 0,
|
||||||
'source_type' => GithubApp::class
|
'source_type' => GithubApp::class
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ class Index extends Component
|
|||||||
$this->parameters = get_route_parameters();
|
$this->parameters = get_route_parameters();
|
||||||
$this->query = request()->query();
|
$this->query = request()->query();
|
||||||
$this->service = Service::whereUuid($this->parameters['service_uuid'])->firstOrFail();
|
$this->service = Service::whereUuid($this->parameters['service_uuid'])->firstOrFail();
|
||||||
$this->refreshStack();
|
$this->applications = $this->service->applications->sort();
|
||||||
|
$this->databases = $this->service->databases->sort();
|
||||||
}
|
}
|
||||||
public function saveCompose($raw)
|
public function saveCompose($raw)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ class Navbar extends Component
|
|||||||
}
|
}
|
||||||
public function serviceStatusUpdated()
|
public function serviceStatusUpdated()
|
||||||
{
|
{
|
||||||
ray('serviceStatusUpdated');
|
|
||||||
$this->check_status();
|
$this->check_status();
|
||||||
}
|
}
|
||||||
public function check_status()
|
public function check_status()
|
||||||
|
|||||||
@@ -33,9 +33,6 @@ class Show extends Component
|
|||||||
$this->serviceDatabase = $this->service->databases()->whereName($this->parameters['service_name'])->first();
|
$this->serviceDatabase = $this->service->databases()->whereName($this->parameters['service_name'])->first();
|
||||||
$this->serviceDatabase->getFilesFromServer();
|
$this->serviceDatabase->getFilesFromServer();
|
||||||
}
|
}
|
||||||
if (is_null($service)) {
|
|
||||||
throw new \Exception("Service not found.");
|
|
||||||
}
|
|
||||||
} catch(\Throwable $e) {
|
} catch(\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
|||||||
35
app/Http/Livewire/Project/Service/Storage.php
Normal file
35
app/Http/Livewire/Project/Service/Storage.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Project\Service;
|
||||||
|
|
||||||
|
use App\Models\LocalPersistentVolume;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Storage extends Component
|
||||||
|
{
|
||||||
|
protected $listeners = ['addNewVolume'];
|
||||||
|
public $resource;
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.project.service.storage');
|
||||||
|
}
|
||||||
|
public function addNewVolume($data)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
LocalPersistentVolume::create([
|
||||||
|
'name' => $data['name'],
|
||||||
|
'mount_path' => $data['mount_path'],
|
||||||
|
'host_path' => $data['host_path'],
|
||||||
|
'resource_id' => $this->resource->id,
|
||||||
|
'resource_type' => $this->resource->getMorphClass(),
|
||||||
|
]);
|
||||||
|
$this->resource->refresh();
|
||||||
|
$this->emit('success', 'Storage added successfully');
|
||||||
|
$this->emit('clearAddStorage');
|
||||||
|
$this->emit('refreshStorages');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
app/Http/Livewire/Project/Shared/GetLogs.php
Normal file
40
app/Http/Livewire/Project/Shared/GetLogs.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Project\Shared;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Support\Facades\Process;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class GetLogs extends Component
|
||||||
|
{
|
||||||
|
public string $outputs = '';
|
||||||
|
public string $errors = '';
|
||||||
|
public Server $server;
|
||||||
|
public ?string $container = null;
|
||||||
|
public ?bool $streamLogs = false;
|
||||||
|
public int $numberOfLines = 100;
|
||||||
|
public function doSomethingWithThisChunkOfOutput($output)
|
||||||
|
{
|
||||||
|
$this->outputs .= $output;
|
||||||
|
}
|
||||||
|
public function instantSave()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public function getLogs($refresh = false)
|
||||||
|
{
|
||||||
|
if ($this->container) {
|
||||||
|
$sshCommand = generateSshCommand($this->server, "docker logs -n {$this->numberOfLines} -t {$this->container}");
|
||||||
|
if ($refresh) {
|
||||||
|
$this->outputs = '';
|
||||||
|
}
|
||||||
|
Process::run($sshCommand, function (string $type, string $output) {
|
||||||
|
$this->doSomethingWithThisChunkOfOutput($output);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.project.shared.get-logs');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ class HealthChecks extends Component
|
|||||||
|
|
||||||
public $resource;
|
public $resource;
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
|
'resource.health_check_enabled' => 'boolean',
|
||||||
'resource.health_check_path' => 'string',
|
'resource.health_check_path' => 'string',
|
||||||
'resource.health_check_port' => 'nullable|string',
|
'resource.health_check_port' => 'nullable|string',
|
||||||
'resource.health_check_host' => 'string',
|
'resource.health_check_host' => 'string',
|
||||||
@@ -22,12 +23,19 @@ class HealthChecks extends Component
|
|||||||
'resource.health_check_start_period' => 'integer',
|
'resource.health_check_start_period' => 'integer',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
public function instantSave()
|
||||||
|
{
|
||||||
|
$this->resource->save();
|
||||||
|
$this->emit('success', 'Health check updated.');
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->validate();
|
$this->validate();
|
||||||
$this->resource->save();
|
$this->resource->save();
|
||||||
$this->emit('saved');
|
$this->emit('success', 'Health check updated.');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
|
|||||||
53
app/Http/Livewire/Project/Shared/Logs.php
Normal file
53
app/Http/Livewire/Project/Shared/Logs.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Project\Shared;
|
||||||
|
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\Service;
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Logs extends Component
|
||||||
|
{
|
||||||
|
public ?string $type = null;
|
||||||
|
public Application|StandalonePostgresql|Service $resource;
|
||||||
|
public Server $server;
|
||||||
|
public ?string $container = null;
|
||||||
|
public $parameters;
|
||||||
|
public $query;
|
||||||
|
public $status;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
$this->query = request()->query();
|
||||||
|
if (data_get($this->parameters, 'application_uuid')) {
|
||||||
|
$this->type = 'application';
|
||||||
|
$this->resource = Application::where('uuid', $this->parameters['application_uuid'])->firstOrFail();
|
||||||
|
$this->status = $this->resource->status;
|
||||||
|
$this->server = $this->resource->destination->server;
|
||||||
|
$containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id);
|
||||||
|
if ($containers->count() > 0) {
|
||||||
|
$this->container = data_get($containers[0], 'Names');
|
||||||
|
}
|
||||||
|
} else if (data_get($this->parameters, 'database_uuid')) {
|
||||||
|
$this->type = 'database';
|
||||||
|
$this->resource = StandalonePostgresql::where('uuid', $this->parameters['database_uuid'])->firstOrFail();
|
||||||
|
$this->status = $this->resource->status;
|
||||||
|
$this->server = $this->resource->destination->server;
|
||||||
|
$this->container = $this->resource->uuid;
|
||||||
|
} else if (data_get($this->parameters, 'service_uuid')) {
|
||||||
|
$this->type = 'service';
|
||||||
|
$this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
||||||
|
$this->status = $this->resource->status;
|
||||||
|
$this->server = $this->resource->server;
|
||||||
|
$this->container = data_get($this->parameters, 'service_name') . '-' . $this->resource->uuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.project.shared.logs');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ use Livewire\Component;
|
|||||||
|
|
||||||
class Add extends Component
|
class Add extends Component
|
||||||
{
|
{
|
||||||
|
public $uuid;
|
||||||
public $parameters;
|
public $parameters;
|
||||||
public string $name;
|
public string $name;
|
||||||
public string $mount_path;
|
public string $mount_path;
|
||||||
@@ -31,8 +32,9 @@ class Add extends Component
|
|||||||
public function submit()
|
public function submit()
|
||||||
{
|
{
|
||||||
$this->validate();
|
$this->validate();
|
||||||
$this->emitUp('submit', [
|
$name = $this->uuid . '-' . $this->name;
|
||||||
'name' => $this->name,
|
$this->emit('addNewVolume', [
|
||||||
|
'name' => $name,
|
||||||
'mount_path' => $this->mount_path,
|
'mount_path' => $this->mount_path,
|
||||||
'host_path' => $this->host_path,
|
'host_path' => $this->host_path,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -8,28 +8,10 @@ use Livewire\Component;
|
|||||||
class All extends Component
|
class All extends Component
|
||||||
{
|
{
|
||||||
public $resource;
|
public $resource;
|
||||||
protected $listeners = ['refreshStorages', 'submit'];
|
protected $listeners = ['refreshStorages'];
|
||||||
|
|
||||||
public function refreshStorages()
|
public function refreshStorages()
|
||||||
{
|
{
|
||||||
$this->resource->refresh();
|
$this->resource->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function submit($data)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
LocalPersistentVolume::create([
|
|
||||||
'name' => $data['name'],
|
|
||||||
'mount_path' => $data['mount_path'],
|
|
||||||
'host_path' => $data['host_path'],
|
|
||||||
'resource_id' => $this->resource->id,
|
|
||||||
'resource_type' => $this->resource->getMorphClass(),
|
|
||||||
]);
|
|
||||||
$this->resource->refresh();
|
|
||||||
$this->emit('success', 'Storage added successfully');
|
|
||||||
$this->emit('clearAddStorage');
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return handleError($e, $this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class Show extends Component
|
|||||||
public LocalPersistentVolume $storage;
|
public LocalPersistentVolume $storage;
|
||||||
public bool $isReadOnly = false;
|
public bool $isReadOnly = false;
|
||||||
public ?string $modalId = null;
|
public ?string $modalId = null;
|
||||||
public ?string $realName = null;
|
public bool $isFirst = true;
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'storage.name' => 'required|string',
|
'storage.name' => 'required|string',
|
||||||
@@ -26,11 +26,6 @@ class Show extends Component
|
|||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
if ($this->storage->resource_type === 'App\Models\ServiceApplication' || $this->storage->resource_type === 'App\Models\ServiceDatabase') {
|
|
||||||
$this->realName = "{$this->storage->service->service->uuid}_{$this->storage->name}";
|
|
||||||
} else {
|
|
||||||
$this->realName = $this->storage->name;
|
|
||||||
}
|
|
||||||
$this->modalId = new Cuid2(7);
|
$this->modalId = new Cuid2(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
app/Http/Livewire/Server/Create.php
Normal file
29
app/Http/Livewire/Server/Create.php
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Server;
|
||||||
|
|
||||||
|
use App\Models\PrivateKey;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Create extends Component
|
||||||
|
{
|
||||||
|
public $private_keys = [];
|
||||||
|
public bool $limit_reached = false;
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->private_keys = PrivateKey::ownedByCurrentTeam()->get();
|
||||||
|
if (!isCloud()) {
|
||||||
|
$this->limit_reached = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$team = currentTeam();
|
||||||
|
$servers = $team->servers->count();
|
||||||
|
['serverLimit' => $serverLimit] = $team->limits;
|
||||||
|
|
||||||
|
$this->limit_reached = $servers >= $serverLimit;
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.create');
|
||||||
|
}
|
||||||
|
}
|
||||||
28
app/Http/Livewire/Server/Destination/Show.php
Normal file
28
app/Http/Livewire/Server/Destination/Show.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Server\Destination;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Show extends Component
|
||||||
|
{
|
||||||
|
public ?Server $server = null;
|
||||||
|
public $parameters = [];
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
try {
|
||||||
|
$this->server = Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
||||||
|
if (is_null($this->server)) {
|
||||||
|
return redirect()->route('server.all');
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.destination.show');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,11 +11,12 @@ class Form extends Component
|
|||||||
{
|
{
|
||||||
use AuthorizesRequests;
|
use AuthorizesRequests;
|
||||||
public Server $server;
|
public Server $server;
|
||||||
public $uptime;
|
public bool $isValidConnection = false;
|
||||||
public $dockerVersion;
|
public bool $isValidDocker = false;
|
||||||
public string|null $wildcard_domain = null;
|
public ?string $wildcard_domain = null;
|
||||||
public int $cleanup_after_percentage;
|
public int $cleanup_after_percentage;
|
||||||
public bool $dockerInstallationStarted = false;
|
public bool $dockerInstallationStarted = false;
|
||||||
|
protected $listeners = ['serverRefresh'];
|
||||||
|
|
||||||
protected $rules = [
|
protected $rules = [
|
||||||
'server.name' => 'required|min:6',
|
'server.name' => 'required|min:6',
|
||||||
@@ -44,37 +45,49 @@ class Form extends Component
|
|||||||
$this->wildcard_domain = $this->server->settings->wildcard_domain;
|
$this->wildcard_domain = $this->server->settings->wildcard_domain;
|
||||||
$this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage;
|
$this->cleanup_after_percentage = $this->server->settings->cleanup_after_percentage;
|
||||||
}
|
}
|
||||||
public function instantSave() {
|
public function serverRefresh() {
|
||||||
|
$this->validateServer();
|
||||||
|
}
|
||||||
|
public function instantSave()
|
||||||
|
{
|
||||||
refresh_server_connection($this->server->privateKey);
|
refresh_server_connection($this->server->privateKey);
|
||||||
$this->validateServer();
|
$this->validateServer();
|
||||||
$this->server->settings->save();
|
$this->server->settings->save();
|
||||||
}
|
}
|
||||||
public function installDocker()
|
public function installDocker()
|
||||||
{
|
{
|
||||||
|
$this->emit('installDocker');
|
||||||
$this->dockerInstallationStarted = true;
|
$this->dockerInstallationStarted = true;
|
||||||
$activity = resolve(InstallDocker::class)($this->server);
|
$activity = InstallDocker::run($this->server);
|
||||||
$this->emit('newMonitorActivity', $activity->id);
|
$this->emit('newMonitorActivity', $activity->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validateServer()
|
public function validateServer($install = true)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server, true);
|
$uptime = $this->server->validateConnection();
|
||||||
if ($uptime) {
|
if ($uptime) {
|
||||||
$this->uptime = $uptime;
|
$install && $this->emit('success', 'Server is reachable.');
|
||||||
$this->emit('success', 'Server is reachable.');
|
|
||||||
} else {
|
} else {
|
||||||
$this->emit('error', 'Server is not reachable.');
|
$install &&$this->emit('error', 'Server is not reachable. Please check your connection and private key configuration.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($dockerVersion) {
|
$dockerInstalled = $this->server->validateDockerEngine();
|
||||||
$this->dockerVersion = $dockerVersion;
|
if ($dockerInstalled) {
|
||||||
$this->emit('success', 'Docker Engine 23+ is installed!');
|
$install && $this->emit('success', 'Docker Engine is installed.<br> Checking version.');
|
||||||
} else {
|
} else {
|
||||||
$this->emit('error', 'No Docker Engine or older than 23 version installed.');
|
$install && $this->installDocker();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$dockerVersion = $this->server->validateDockerEngineVersion();
|
||||||
|
if ($dockerVersion) {
|
||||||
|
$install && $this->emit('success', 'Docker Engine version is 23+.');
|
||||||
|
} else {
|
||||||
|
$install && $this->installDocker();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this, customErrorMessage: "Server is not reachable: ");
|
return handleError($e, $this);
|
||||||
} finally {
|
} finally {
|
||||||
$this->emit('proxyStatusUpdated');
|
$this->emit('proxyStatusUpdated');
|
||||||
}
|
}
|
||||||
|
|||||||
31
app/Http/Livewire/Server/PrivateKey/Show.php
Normal file
31
app/Http/Livewire/Server/PrivateKey/Show.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Server\PrivateKey;
|
||||||
|
|
||||||
|
use App\Models\PrivateKey;
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Show extends Component
|
||||||
|
{
|
||||||
|
public ?Server $server = null;
|
||||||
|
public $privateKeys = [];
|
||||||
|
public $parameters = [];
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
try {
|
||||||
|
$this->server = Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
||||||
|
if (is_null($this->server)) {
|
||||||
|
return redirect()->route('server.all');
|
||||||
|
}
|
||||||
|
$this->privateKeys = PrivateKey::ownedByCurrentTeam()->get()->where('is_git_related', false);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.private-key.show');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ class Deploy extends Component
|
|||||||
public Server $server;
|
public Server $server;
|
||||||
public bool $traefikDashboardAvailable = false;
|
public bool $traefikDashboardAvailable = false;
|
||||||
public ?string $currentRoute = null;
|
public ?string $currentRoute = null;
|
||||||
protected $listeners = ['proxyStatusUpdated', 'traefikDashboardAvailable'];
|
protected $listeners = ['proxyStatusUpdated', 'traefikDashboardAvailable', 'serverRefresh' => 'proxyStatusUpdated'];
|
||||||
|
|
||||||
public function mount() {
|
public function mount() {
|
||||||
$this->currentRoute = request()->route()->getName();
|
$this->currentRoute = request()->route()->getName();
|
||||||
|
|||||||
28
app/Http/Livewire/Server/Proxy/Show.php
Normal file
28
app/Http/Livewire/Server/Proxy/Show.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Server\Proxy;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Show extends Component
|
||||||
|
{
|
||||||
|
public ?Server $server = null;
|
||||||
|
public $parameters = [];
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
try {
|
||||||
|
$this->server = Server::ownedByCurrentTeam(['name', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
||||||
|
if (is_null($this->server)) {
|
||||||
|
return redirect()->route('server.all');
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.proxy.show');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,9 @@ class Status extends Component
|
|||||||
}
|
}
|
||||||
public function getProxyStatusWithNoti()
|
public function getProxyStatusWithNoti()
|
||||||
{
|
{
|
||||||
|
if ($this->server->isFunctional()) {
|
||||||
$this->emit('success', 'Refreshed proxy status.');
|
$this->emit('success', 'Refreshed proxy status.');
|
||||||
$this->getProxyStatus();
|
$this->getProxyStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ class Show extends Component
|
|||||||
{
|
{
|
||||||
use AuthorizesRequests;
|
use AuthorizesRequests;
|
||||||
public ?Server $server = null;
|
public ?Server $server = null;
|
||||||
|
public $parameters = [];
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
try {
|
try {
|
||||||
$this->server = Server::ownedByCurrentTeam(['name', 'description', 'ip', 'port', 'user', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
$this->server = Server::ownedByCurrentTeam(['name', 'description', 'ip', 'port', 'user', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
||||||
if (is_null($this->server)) {
|
if (is_null($this->server)) {
|
||||||
@@ -21,6 +23,10 @@ class Show extends Component
|
|||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public function submit()
|
||||||
|
{
|
||||||
|
$this->emit('serverRefresh');
|
||||||
|
}
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.server.show');
|
return view('livewire.server.show');
|
||||||
|
|||||||
@@ -32,36 +32,34 @@ class ShowPrivateKey extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkConnection()
|
public function checkConnection($install = false)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server, true);
|
$uptime = $this->server->validateConnection();
|
||||||
if ($uptime) {
|
if ($uptime) {
|
||||||
$this->server->settings->update([
|
$install && $this->emit('success', 'Server is reachable.');
|
||||||
'is_reachable' => true
|
|
||||||
]);
|
|
||||||
$this->emit('success', 'Server is reachable with this private key.');
|
|
||||||
} else {
|
} else {
|
||||||
$this->server->settings->update([
|
$install && $this->emit('error', 'Server is not reachable. Please check your connection and private key configuration.');
|
||||||
'is_reachable' => false,
|
|
||||||
'is_usable' => false
|
|
||||||
]);
|
|
||||||
$this->emit('error', 'Server is not reachable with this private key.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($dockerVersion) {
|
$dockerInstalled = $this->server->validateDockerEngine();
|
||||||
$this->server->settings->update([
|
if ($dockerInstalled) {
|
||||||
'is_usable' => true
|
$install && $this->emit('success', 'Docker Engine is installed.<br> Checking version.');
|
||||||
]);
|
|
||||||
$this->emit('success', 'Server is usable for Coolify.');
|
|
||||||
} else {
|
} else {
|
||||||
$this->server->settings->update([
|
$install && $this->installDocker();
|
||||||
'is_usable' => false
|
return;
|
||||||
]);
|
}
|
||||||
$this->emit('error', 'Old (lower than 23) or no Docker version detected. Install Docker Engine on the General tab.');
|
$dockerVersion = $this->server->validateDockerEngineVersion();
|
||||||
|
if ($dockerVersion) {
|
||||||
|
$install && $this->emit('success', 'Docker Engine version is 23+.');
|
||||||
|
} else {
|
||||||
|
$install && $this->installDocker();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
|
} finally {
|
||||||
|
$this->emit('proxyStatusUpdated');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ class Index extends Component
|
|||||||
}
|
}
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
|
if (config('coolify.waitlist') == false) {
|
||||||
|
return redirect()->route('register');
|
||||||
|
}
|
||||||
$this->waitingInLine = Waitlist::whereVerified(true)->count();
|
$this->waitingInLine = Waitlist::whereVerified(true)->count();
|
||||||
$this->users = User::count();
|
$this->users = User::count();
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
|
|||||||
@@ -45,16 +45,16 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
private string $commit;
|
private string $commit;
|
||||||
private bool $force_rebuild;
|
private bool $force_rebuild;
|
||||||
|
|
||||||
private GithubApp|GitlabApp $source;
|
private GithubApp|GitlabApp|string $source = 'other';
|
||||||
private StandaloneDocker|SwarmDocker $destination;
|
private StandaloneDocker|SwarmDocker $destination;
|
||||||
private Server $server;
|
private Server $server;
|
||||||
private ApplicationPreview|null $preview = null;
|
private ApplicationPreview|null $preview = null;
|
||||||
|
|
||||||
private string $container_name;
|
private string $container_name;
|
||||||
private string|null $currently_running_container_name = null;
|
private string|null $currently_running_container_name = null;
|
||||||
|
private string $basedir;
|
||||||
private string $workdir;
|
private string $workdir;
|
||||||
private string $configuration_dir;
|
private string $configuration_dir;
|
||||||
private string $build_workdir;
|
|
||||||
private string $build_image_name;
|
private string $build_image_name;
|
||||||
private string $production_image_name;
|
private string $production_image_name;
|
||||||
private bool $is_debug_enabled;
|
private bool $is_debug_enabled;
|
||||||
@@ -80,16 +80,20 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->commit = $this->application_deployment_queue->commit;
|
$this->commit = $this->application_deployment_queue->commit;
|
||||||
$this->force_rebuild = $this->application_deployment_queue->force_rebuild;
|
$this->force_rebuild = $this->application_deployment_queue->force_rebuild;
|
||||||
|
|
||||||
$this->source = $this->application->source->getMorphClass()::where('id', $this->application->source->id)->first();
|
$source = data_get($this->application, 'source');
|
||||||
|
if ($source) {
|
||||||
|
$this->source = $source->getMorphClass()::where('id', $this->application->source->id)->first();
|
||||||
|
}
|
||||||
$this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
|
$this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
|
||||||
$this->server = $this->destination->server;
|
$this->server = $this->destination->server;
|
||||||
|
|
||||||
$this->workdir = "/artifacts/{$this->deployment_uuid}";
|
$this->basedir = "/artifacts/{$this->deployment_uuid}";
|
||||||
|
$this->workdir = "{$this->basedir}" . rtrim($this->application->base_directory, '/');
|
||||||
$this->configuration_dir = application_configuration_dir() . "/{$this->application->uuid}";
|
$this->configuration_dir = application_configuration_dir() . "/{$this->application->uuid}";
|
||||||
$this->build_workdir = "{$this->workdir}" . rtrim($this->application->base_directory, '/');
|
|
||||||
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
|
||||||
|
|
||||||
$this->container_name = generateApplicationContainerName($this->application);
|
ray($this->basedir, $this->workdir);
|
||||||
|
$this->container_name = generateApplicationContainerName($this->application, $this->pull_request_id);
|
||||||
savePrivateKeyToFs($this->server);
|
savePrivateKeyToFs($this->server);
|
||||||
$this->saved_outputs = collect();
|
$this->saved_outputs = collect();
|
||||||
|
|
||||||
@@ -97,7 +101,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
if ($this->pull_request_id !== 0) {
|
if ($this->pull_request_id !== 0) {
|
||||||
$this->preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->application->id, $this->pull_request_id);
|
$this->preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->application->id, $this->pull_request_id);
|
||||||
if ($this->application->fqdn) {
|
if ($this->application->fqdn) {
|
||||||
|
if (data_get($this->preview, 'fqdn')) {
|
||||||
$preview_fqdn = getFqdnWithoutPort(data_get($this->preview, 'fqdn'));
|
$preview_fqdn = getFqdnWithoutPort(data_get($this->preview, 'fqdn'));
|
||||||
|
}
|
||||||
$template = $this->application->preview_url_template;
|
$template = $this->application->preview_url_template;
|
||||||
$url = Url::fromString($this->application->fqdn);
|
$url = Url::fromString($this->application->fqdn);
|
||||||
$host = $url->getHost();
|
$host = $url->getHost();
|
||||||
@@ -231,7 +237,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
);
|
);
|
||||||
$this->build_image_name = Str::lower("{$this->application->git_repository}:build");
|
$this->build_image_name = Str::lower("{$this->application->git_repository}:build");
|
||||||
$this->production_image_name = Str::lower("{$this->application->uuid}:latest");
|
$this->production_image_name = Str::lower("{$this->application->uuid}:latest");
|
||||||
ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
|
// ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
|
||||||
$this->generate_compose_file();
|
$this->generate_compose_file();
|
||||||
$this->generate_build_env_variables();
|
$this->generate_build_env_variables();
|
||||||
$this->add_build_env_variables_to_dockerfile();
|
$this->add_build_env_variables_to_dockerfile();
|
||||||
@@ -248,7 +254,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
);
|
);
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->clone_repository();
|
$this->clone_repository();
|
||||||
|
$this->set_base_dir();
|
||||||
$tag = Str::of("{$this->commit}-{$this->application->id}-{$this->pull_request_id}");
|
$tag = Str::of("{$this->commit}-{$this->application->id}-{$this->pull_request_id}");
|
||||||
if (strlen($tag) > 128) {
|
if (strlen($tag) > 128) {
|
||||||
$tag = $tag->substr(0, 128);
|
$tag = $tag->substr(0, 128);
|
||||||
@@ -256,7 +262,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
|
|
||||||
$this->build_image_name = Str::lower("{$this->application->git_repository}:{$tag}-build");
|
$this->build_image_name = Str::lower("{$this->application->git_repository}:{$tag}-build");
|
||||||
$this->production_image_name = Str::lower("{$this->application->uuid}:{$tag}");
|
$this->production_image_name = Str::lower("{$this->application->uuid}:{$tag}");
|
||||||
ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
|
// ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
|
||||||
|
|
||||||
if (!$this->force_rebuild) {
|
if (!$this->force_rebuild) {
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
@@ -301,7 +307,11 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
}
|
}
|
||||||
private function health_check()
|
private function health_check()
|
||||||
{
|
{
|
||||||
ray('New container name: ', $this->container_name);
|
if ($this->application->isHealthcheckDisabled()) {
|
||||||
|
$this->newVersionIsHealthy = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ray('New container name: ', $this->container_name);
|
||||||
if ($this->container_name) {
|
if ($this->container_name) {
|
||||||
$counter = 0;
|
$counter = 0;
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
@@ -329,9 +339,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
if (Str::of($this->saved_outputs->get('health_check'))->contains('healthy')) {
|
if (Str::of($this->saved_outputs->get('health_check'))->contains('healthy')) {
|
||||||
$this->newVersionIsHealthy = true;
|
$this->newVersionIsHealthy = true;
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
|
||||||
"echo 'New version of your application is healthy.'"
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
"echo 'Rolling update completed.'"
|
"echo 'Rolling update completed.'"
|
||||||
],
|
],
|
||||||
@@ -348,12 +355,13 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
{
|
{
|
||||||
$this->build_image_name = Str::lower("{$this->application->uuid}:pr-{$this->pull_request_id}-build");
|
$this->build_image_name = Str::lower("{$this->application->uuid}:pr-{$this->pull_request_id}-build");
|
||||||
$this->production_image_name = Str::lower("{$this->application->uuid}:pr-{$this->pull_request_id}");
|
$this->production_image_name = Str::lower("{$this->application->uuid}:pr-{$this->pull_request_id}");
|
||||||
ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
|
// ray('Build Image Name: ' . $this->build_image_name . ' & Production Image Name: ' . $this->production_image_name)->green();
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
"echo 'Starting pull request (#{$this->pull_request_id}) deployment of {$this->application->git_repository}:{$this->application->git_branch}.'",
|
"echo 'Starting pull request (#{$this->pull_request_id}) deployment of {$this->application->git_repository}:{$this->application->git_branch}.'",
|
||||||
]);
|
]);
|
||||||
$this->prepare_builder_image();
|
$this->prepare_builder_image();
|
||||||
$this->clone_repository();
|
$this->clone_repository();
|
||||||
|
$this->set_base_dir();
|
||||||
$this->cleanup_git();
|
$this->cleanup_git();
|
||||||
if ($this->application->build_pack === 'nixpacks') {
|
if ($this->application->build_pack === 'nixpacks') {
|
||||||
$this->generate_nixpacks_confs();
|
$this->generate_nixpacks_confs();
|
||||||
@@ -373,9 +381,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
private function prepare_builder_image()
|
private function prepare_builder_image()
|
||||||
{
|
{
|
||||||
$pull = "--pull=always";
|
$pull = "--pull=always";
|
||||||
if (isDev()) {
|
|
||||||
$pull = "--pull=never";
|
|
||||||
}
|
|
||||||
$helperImage = config('coolify.helper_image');
|
$helperImage = config('coolify.helper_image');
|
||||||
$runCommand = "docker run {$pull} -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
$runCommand = "docker run {$pull} -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
|
||||||
|
|
||||||
@@ -388,24 +393,30 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
"hidden" => true,
|
"hidden" => true,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->workdir}")
|
"command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->basedir}")
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function set_base_dir() {
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[
|
||||||
|
"echo -n 'Setting base directory to {$this->workdir}.'"
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private function clone_repository()
|
private function clone_repository()
|
||||||
{
|
{
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
"echo -n 'Importing {$this->application->git_repository}:{$this->application->git_branch} to {$this->workdir}. '"
|
"echo -n 'Importing {$this->application->git_repository}:{$this->application->git_branch} (commit sha {$this->application->git_commit_sha}) to {$this->basedir}. '"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
$this->importing_git_repository()
|
$this->importing_git_repository(), "hidden" => true
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
executeInDocker($this->deployment_uuid, "cd {$this->workdir} && git rev-parse HEAD"),
|
executeInDocker($this->deployment_uuid, "cd {$this->basedir} && git rev-parse HEAD"),
|
||||||
"hidden" => true,
|
"hidden" => true,
|
||||||
"save" => "git_commit_sha"
|
"save" => "git_commit_sha"
|
||||||
],
|
],
|
||||||
@@ -429,23 +440,23 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
|
|
||||||
if ($this->source->getMorphClass() == 'App\Models\GithubApp') {
|
if ($this->source->getMorphClass() == 'App\Models\GithubApp') {
|
||||||
if ($this->source->is_public) {
|
if ($this->source->is_public) {
|
||||||
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->workdir}";
|
$git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->application->git_repository} {$this->basedir}";
|
||||||
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
||||||
|
|
||||||
$commands->push(executeInDocker($this->deployment_uuid, $git_clone_command));
|
$commands->push(executeInDocker($this->deployment_uuid, $git_clone_command));
|
||||||
} else {
|
} else {
|
||||||
$github_access_token = generate_github_installation_token($this->source);
|
$github_access_token = generate_github_installation_token($this->source);
|
||||||
$commands->push(executeInDocker($this->deployment_uuid, "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}"));
|
$commands->push(executeInDocker($this->deployment_uuid, "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->basedir}"));
|
||||||
}
|
}
|
||||||
if ($this->pull_request_id !== 0) {
|
if ($this->pull_request_id !== 0) {
|
||||||
$commands->push(executeInDocker($this->deployment_uuid, "cd {$this->workdir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name"));
|
$commands->push(executeInDocker($this->deployment_uuid, "cd {$this->basedir} && git fetch origin pull/{$this->pull_request_id}/head:$pr_branch_name && git checkout $pr_branch_name"));
|
||||||
}
|
}
|
||||||
return $commands->implode(' && ');
|
return $commands->implode(' && ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->application->deploymentType() === 'deploy_key') {
|
if ($this->application->deploymentType() === 'deploy_key') {
|
||||||
$private_key = base64_encode($this->application->private_key->private_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 = "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->basedir}";
|
||||||
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
||||||
$commands = collect([
|
$commands = collect([
|
||||||
executeInDocker($this->deployment_uuid, "mkdir -p /root/.ssh"),
|
executeInDocker($this->deployment_uuid, "mkdir -p /root/.ssh"),
|
||||||
@@ -455,18 +466,25 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
]);
|
]);
|
||||||
return $commands->implode(' && ');
|
return $commands->implode(' && ');
|
||||||
}
|
}
|
||||||
|
if ($this->application->deploymentType() === 'other') {
|
||||||
|
$git_clone_command = "{$git_clone_command} {$this->application->git_repository} {$this->basedir}";
|
||||||
|
$git_clone_command = $this->set_git_import_settings($git_clone_command);
|
||||||
|
$commands->push(executeInDocker($this->deployment_uuid, $git_clone_command));
|
||||||
|
ray($commands);
|
||||||
|
return $commands->implode(' && ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function set_git_import_settings($git_clone_command)
|
private function set_git_import_settings($git_clone_command)
|
||||||
{
|
{
|
||||||
if ($this->application->git_commit_sha !== 'HEAD') {
|
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";
|
$git_clone_command = "{$git_clone_command} && cd {$this->basedir} && git -c advice.detachedHead=false checkout {$this->application->git_commit_sha} >/dev/null 2>&1";
|
||||||
}
|
}
|
||||||
if ($this->application->settings->is_git_submodules_enabled) {
|
if ($this->application->settings->is_git_submodules_enabled) {
|
||||||
$git_clone_command = "{$git_clone_command} && cd {$this->workdir} && git submodule update --init --recursive";
|
$git_clone_command = "{$git_clone_command} && cd {$this->basedir} && git submodule update --init --recursive";
|
||||||
}
|
}
|
||||||
if ($this->application->settings->is_git_lfs_enabled) {
|
if ($this->application->settings->is_git_lfs_enabled) {
|
||||||
$git_clone_command = "{$git_clone_command} && cd {$this->workdir} && git lfs pull";
|
$git_clone_command = "{$git_clone_command} && cd {$this->basedir} && git lfs pull";
|
||||||
}
|
}
|
||||||
return $git_clone_command;
|
return $git_clone_command;
|
||||||
}
|
}
|
||||||
@@ -474,17 +492,24 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
private function cleanup_git()
|
private function cleanup_git()
|
||||||
{
|
{
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[executeInDocker($this->deployment_uuid, "rm -fr {$this->workdir}/.git")],
|
[executeInDocker($this->deployment_uuid, "rm -fr {$this->basedir}/.git")],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generate_nixpacks_confs()
|
private function generate_nixpacks_confs()
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
"echo -n 'Generating nixpacks configuration.'",
|
"echo -n 'Generating nixpacks configuration.'",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$nixpacks_command = $this->nixpacks_build_cmd();
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[
|
||||||
|
"echo -n Running: $nixpacks_command",
|
||||||
],
|
],
|
||||||
[$this->nixpacks_build_cmd()],
|
[executeInDocker($this->deployment_uuid, $nixpacks_command)],
|
||||||
[executeInDocker($this->deployment_uuid, "cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")],
|
[executeInDocker($this->deployment_uuid, "cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")],
|
||||||
[executeInDocker($this->deployment_uuid, "rm -f {$this->workdir}/.nixpacks/Dockerfile")]
|
[executeInDocker($this->deployment_uuid, "rm -f {$this->workdir}/.nixpacks/Dockerfile")]
|
||||||
);
|
);
|
||||||
@@ -493,7 +518,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
private function nixpacks_build_cmd()
|
private function nixpacks_build_cmd()
|
||||||
{
|
{
|
||||||
$this->generate_env_variables();
|
$this->generate_env_variables();
|
||||||
$nixpacks_command = "nixpacks build -o {$this->workdir} {$this->env_args} --no-error-without-start";
|
$nixpacks_command = "nixpacks build --no-cache -o {$this->workdir} {$this->env_args} --no-error-without-start";
|
||||||
if ($this->application->build_command) {
|
if ($this->application->build_command) {
|
||||||
$nixpacks_command .= " --build-cmd \"{$this->application->build_command}\"";
|
$nixpacks_command .= " --build-cmd \"{$this->application->build_command}\"";
|
||||||
}
|
}
|
||||||
@@ -504,7 +529,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
|
$nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
|
||||||
}
|
}
|
||||||
$nixpacks_command .= " {$this->workdir}";
|
$nixpacks_command .= " {$this->workdir}";
|
||||||
return executeInDocker($this->deployment_uuid, $nixpacks_command);
|
return $nixpacks_command;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generate_env_variables()
|
private function generate_env_variables()
|
||||||
@@ -571,6 +596,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
if ($this->application->isHealthcheckDisabled()) {
|
||||||
|
data_forget($docker_compose, 'services.' . $this->container_name . '.healthcheck');
|
||||||
|
}
|
||||||
if (count($this->application->ports_mappings_array) > 0 && $this->pull_request_id === 0) {
|
if (count($this->application->ports_mappings_array) > 0 && $this->pull_request_id === 0) {
|
||||||
$docker_compose['services'][$this->container_name]['ports'] = $this->application->ports_mappings_array;
|
$docker_compose['services'][$this->container_name]['ports'] = $this->application->ports_mappings_array;
|
||||||
}
|
}
|
||||||
@@ -622,14 +650,14 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
private function generate_environment_variables($ports)
|
private function generate_environment_variables($ports)
|
||||||
{
|
{
|
||||||
$environment_variables = collect();
|
$environment_variables = collect();
|
||||||
ray('Generate Environment Variables')->green();
|
// ray('Generate Environment Variables')->green();
|
||||||
if ($this->pull_request_id === 0) {
|
if ($this->pull_request_id === 0) {
|
||||||
ray($this->application->runtime_environment_variables)->green();
|
// ray($this->application->runtime_environment_variables)->green();
|
||||||
foreach ($this->application->runtime_environment_variables as $env) {
|
foreach ($this->application->runtime_environment_variables as $env) {
|
||||||
$environment_variables->push("$env->key=$env->value");
|
$environment_variables->push("$env->key=$env->value");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ray($this->application->runtime_environment_variables_preview)->green();
|
// ray($this->application->runtime_environment_variables_preview)->green();
|
||||||
foreach ($this->application->runtime_environment_variables_preview as $env) {
|
foreach ($this->application->runtime_environment_variables_preview as $env) {
|
||||||
$environment_variables->push("$env->key=$env->value");
|
$environment_variables->push("$env->key=$env->value");
|
||||||
}
|
}
|
||||||
@@ -667,7 +695,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
private function build_image()
|
private function build_image()
|
||||||
{
|
{
|
||||||
$this->execute_remote_command([
|
$this->execute_remote_command([
|
||||||
"echo -n 'Building docker image for your application.'",
|
"echo -n 'Building docker image for your application. To check the current progress, click on Show Debug Logs.'",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($this->application->settings->is_static) {
|
if ($this->application->settings->is_static) {
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class ApplicationPullRequestUpdateJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
|
|
||||||
private function update_comment()
|
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: [
|
['data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/comments/{$this->preview->pull_request_issue_comment_id}", method: 'patch', data: [
|
||||||
'body' => $this->body,
|
'body' => $this->body,
|
||||||
], throwError: false);
|
], throwError: false);
|
||||||
if (data_get($data, 'message') === 'Not Found') {
|
if (data_get($data, 'message') === 'Not Found') {
|
||||||
@@ -77,7 +77,7 @@ class ApplicationPullRequestUpdateJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
|
|
||||||
private function 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: [
|
['data' => $data] = githubApi(source: $this->application->source, endpoint: "/repos/{$this->application->git_repository}/issues/{$this->pull_request_id}/comments", method: 'post', data: [
|
||||||
'body' => $this->body,
|
'body' => $this->body,
|
||||||
]);
|
]);
|
||||||
$this->preview->pull_request_issue_comment_id = $data['id'];
|
$this->preview->pull_request_issue_comment_id = $data['id'];
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Models\ApplicationPreview;
|
|||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use App\Notifications\Container\ContainerRestarted;
|
use App\Notifications\Container\ContainerRestarted;
|
||||||
use App\Notifications\Container\ContainerStopped;
|
use App\Notifications\Container\ContainerStopped;
|
||||||
|
use App\Notifications\Server\Revived;
|
||||||
use App\Notifications\Server\Unreachable;
|
use App\Notifications\Server\Unreachable;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
@@ -40,33 +41,49 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
{
|
{
|
||||||
return $this->server->uuid;
|
return $this->server->uuid;
|
||||||
}
|
}
|
||||||
|
public function handle()
|
||||||
private function checkServerConnection()
|
|
||||||
{
|
|
||||||
$uptime = instant_remote_process(['uptime'], $this->server, false);
|
|
||||||
if (!is_null($uptime)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function handle(): void
|
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
ray("checking server status for {$this->server->name}");
|
||||||
// ray()->clearAll();
|
// ray()->clearAll();
|
||||||
$serverUptimeCheckNumber = 0;
|
$serverUptimeCheckNumber = 0;
|
||||||
$serverUptimeCheckNumberMax = 3;
|
$serverUptimeCheckNumberMax = 3;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
ray('checking # ' . $serverUptimeCheckNumber);
|
||||||
if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) {
|
if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) {
|
||||||
$this->server->settings()->update(['is_reachable' => false]);
|
send_internal_notification('Server unreachable: ' . $this->server->name);
|
||||||
|
if ($this->server->unreachable_email_sent === false) {
|
||||||
|
ray('Server unreachable, sending notification...');
|
||||||
$this->server->team->notify(new Unreachable($this->server));
|
$this->server->team->notify(new Unreachable($this->server));
|
||||||
|
}
|
||||||
|
$this->server->settings()->update([
|
||||||
|
'is_reachable' => false,
|
||||||
|
]);
|
||||||
|
$this->server->update(['unreachable_email_sent' => true]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$result = $this->checkServerConnection();
|
$result = $this->server->validateConnection();
|
||||||
if ($result) {
|
if ($result) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$serverUptimeCheckNumber++;
|
$serverUptimeCheckNumber++;
|
||||||
sleep(5);
|
sleep(5);
|
||||||
}
|
}
|
||||||
|
if (data_get($this->server, 'unreachable_email_sent') === true) {
|
||||||
|
ray('Server is reachable again, sending notification...');
|
||||||
|
$this->server->team->notify(new Revived($this->server));
|
||||||
|
$this->server->update(['unreachable_email_sent' => false]);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
data_get($this->server, 'settings.is_reachable') === false ||
|
||||||
|
data_get($this->server, 'settings.is_usable') === false
|
||||||
|
) {
|
||||||
|
$this->server->settings()->update([
|
||||||
|
'is_reachable' => true,
|
||||||
|
'is_usable' => true
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$this->server->validateDockerEngine(true);
|
||||||
$containers = instant_remote_process(["docker container ls -q"], $this->server);
|
$containers = instant_remote_process(["docker container ls -q"], $this->server);
|
||||||
if (!$containers) {
|
if (!$containers) {
|
||||||
return;
|
return;
|
||||||
@@ -108,9 +125,9 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$labelId = data_get($labels, 'coolify.applicationId');
|
$labelId = data_get($labels, 'coolify.applicationId');
|
||||||
if ($labelId) {
|
if ($labelId) {
|
||||||
if (str_contains($labelId, '-pr-')) {
|
if (str_contains($labelId, '-pr-')) {
|
||||||
$previewId = (int) Str::after($labelId, '-pr-');
|
$pullRequestId = data_get($labels, 'coolify.pullRequestId');
|
||||||
$applicationId = (int) Str::before($labelId, '-pr-');
|
$applicationId = (int) Str::before($labelId, '-pr-');
|
||||||
$preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $previewId)->first();
|
$preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $pullRequestId)->first();
|
||||||
if ($preview) {
|
if ($preview) {
|
||||||
$foundApplicationPreviews[] = $preview->id;
|
$foundApplicationPreviews[] = $preview->id;
|
||||||
$statusFromDb = $preview->status;
|
$statusFromDb = $preview->status;
|
||||||
@@ -266,7 +283,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
send_internal_notification('ContainerStatusJob failed with: ' . $e->getMessage());
|
send_internal_notification('ContainerStatusJob failed with: ' . $e->getMessage());
|
||||||
ray($e->getMessage());
|
ray($e->getMessage());
|
||||||
throw $e;
|
return handleError($e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (data_get($this->database, 'status') !== 'running') {
|
$status = Str::of(data_get($this->database, 'status'));
|
||||||
|
if (!$status->startsWith('running') && $this->database->id !== 0) {
|
||||||
ray('database not running');
|
ray('database not running');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -89,7 +90,6 @@ class DatabaseBackupJob implements ShouldQueue, ShouldBeEncrypted
|
|||||||
$this->upload_to_s3();
|
$this->upload_to_s3();
|
||||||
}
|
}
|
||||||
$this->save_backup_logs();
|
$this->save_backup_logs();
|
||||||
// TODO: Notify user
|
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ray($e->getMessage());
|
ray($e->getMessage());
|
||||||
send_internal_notification('DatabaseBackupJob failed with: ' . $e->getMessage());
|
send_internal_notification('DatabaseBackupJob failed with: ' . $e->getMessage());
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Models;
|
|||||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Spatie\Activitylog\Models\Activity;
|
use Spatie\Activitylog\Models\Activity;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class Application extends BaseModel
|
class Application extends BaseModel
|
||||||
{
|
{
|
||||||
@@ -12,16 +13,35 @@ class Application extends BaseModel
|
|||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
|
static::saving(function ($application) {
|
||||||
|
if ($application->fqdn == '') {
|
||||||
|
$application->fqdn = null;
|
||||||
|
}
|
||||||
|
$application->forceFill([
|
||||||
|
'fqdn' => $application->fqdn,
|
||||||
|
'install_command' => Str::of($application->install_command)->trim(),
|
||||||
|
'build_command' => Str::of($application->build_command)->trim(),
|
||||||
|
'start_command' => Str::of($application->start_command)->trim(),
|
||||||
|
'base_directory' => Str::of($application->base_directory)->trim(),
|
||||||
|
'publish_directory' => Str::of($application->publish_directory)->trim(),
|
||||||
|
]);
|
||||||
|
});
|
||||||
static::created(function ($application) {
|
static::created(function ($application) {
|
||||||
ApplicationSetting::create([
|
ApplicationSetting::create([
|
||||||
'application_id' => $application->id,
|
'application_id' => $application->id,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
static::deleting(function ($application) {
|
static::deleting(function ($application) {
|
||||||
|
// Stop Container
|
||||||
|
instant_remote_process(
|
||||||
|
["docker rm -f {$application->uuid}"],
|
||||||
|
$application->destination->server,
|
||||||
|
false
|
||||||
|
);
|
||||||
$application->settings()->delete();
|
$application->settings()->delete();
|
||||||
$storages = $application->persistentStorages()->get();
|
$storages = $application->persistentStorages()->get();
|
||||||
foreach ($storages as $storage) {
|
foreach ($storages as $storage) {
|
||||||
instant_remote_process(["docker volume rm -f $storage->name"], $application->destination->server);
|
instant_remote_process(["docker volume rm -f $storage->name"], $application->destination->server, false);
|
||||||
}
|
}
|
||||||
$application->persistentStorages()->delete();
|
$application->persistentStorages()->delete();
|
||||||
$application->environment_variables()->delete();
|
$application->environment_variables()->delete();
|
||||||
@@ -38,6 +58,10 @@ class Application extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->morphMany(LocalPersistentVolume::class, 'resource');
|
return $this->morphMany(LocalPersistentVolume::class, 'resource');
|
||||||
}
|
}
|
||||||
|
public function fileStorages()
|
||||||
|
{
|
||||||
|
return $this->morphMany(LocalFileVolume::class, 'resource');
|
||||||
|
}
|
||||||
|
|
||||||
public function type()
|
public function type()
|
||||||
{
|
{
|
||||||
@@ -58,6 +82,7 @@ class Application extends BaseModel
|
|||||||
if (!is_null($this->source?->html_url) && !is_null($this->git_repository) && !is_null($this->git_branch)) {
|
if (!is_null($this->source?->html_url) && !is_null($this->git_repository) && !is_null($this->git_branch)) {
|
||||||
return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}";
|
return "{$this->source->html_url}/{$this->git_repository}/tree/{$this->git_branch}";
|
||||||
}
|
}
|
||||||
|
return $this->git_repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
);
|
);
|
||||||
@@ -70,6 +95,7 @@ class Application extends BaseModel
|
|||||||
if (!is_null($this->source?->html_url) && !is_null($this->git_repository) && !is_null($this->git_branch)) {
|
if (!is_null($this->source?->html_url) && !is_null($this->git_repository) && !is_null($this->git_branch)) {
|
||||||
return "{$this->source->html_url}/{$this->git_repository}/commits/{$this->git_branch}";
|
return "{$this->source->html_url}/{$this->git_repository}/commits/{$this->git_branch}";
|
||||||
}
|
}
|
||||||
|
return $this->git_repository;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -214,6 +240,8 @@ class Application extends BaseModel
|
|||||||
return 'deploy_key';
|
return 'deploy_key';
|
||||||
} else if (data_get($this, 'source')) {
|
} else if (data_get($this, 'source')) {
|
||||||
return 'source';
|
return 'source';
|
||||||
|
} else {
|
||||||
|
return 'other';
|
||||||
}
|
}
|
||||||
throw new \Exception('No deployment type found');
|
throw new \Exception('No deployment type found');
|
||||||
}
|
}
|
||||||
@@ -229,6 +257,15 @@ class Application extends BaseModel
|
|||||||
if ($this->dockerfile) {
|
if ($this->dockerfile) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
public function isHealthcheckDisabled(): bool
|
||||||
|
{
|
||||||
|
if (data_get($this, 'dockerfile') || data_get($this, 'build_pack') === 'dockerfile' || data_get($this, 'health_check_enabled') === false) {
|
||||||
|
ray('dockerfile');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,23 +31,18 @@ class LocalFileVolume extends BaseModel
|
|||||||
}
|
}
|
||||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||||
ray($isFile);
|
|
||||||
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
||||||
throw new \Exception("File $path is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.");
|
throw new \Exception("File $path is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.");
|
||||||
} else if ($isDir == 'OK' && !$fileVolume->is_directory) {
|
} else if ($isDir == 'OK' && !$fileVolume->is_directory) {
|
||||||
throw new \Exception("File $path is a directory on the server, but you are trying to mark it as a file. Please delete the directory on the server or mark it as directory.");
|
throw new \Exception("File $path is a directory on the server, but you are trying to mark it as a file. Please delete the directory on the server or mark it as directory.");
|
||||||
}
|
}
|
||||||
if (($isFile == 'NOK' && !$fileVolume->is_directory) || $isFile == 'OK') {
|
if (!$fileVolume->is_directory && $isDir == 'NOK') {
|
||||||
$rootDir = Str::of($path)->dirname();
|
|
||||||
$commands->push("mkdir -p $rootDir > /dev/null 2>&1 || true");
|
|
||||||
$commands->push("touch $path > /dev/null 2>&1 || true");
|
|
||||||
if ($content) {
|
|
||||||
$content = base64_encode($content);
|
$content = base64_encode($content);
|
||||||
$commands->push("echo '$content' | base64 -d > $path");
|
$commands->push("echo '$content' | base64 -d > $path");
|
||||||
}
|
|
||||||
} else if ($isDir == 'NOK' && $fileVolume->is_directory) {
|
} else if ($isDir == 'NOK' && $fileVolume->is_directory) {
|
||||||
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
||||||
}
|
}
|
||||||
|
ray($commands->toArray());
|
||||||
return instant_remote_process($commands, $server);
|
return instant_remote_process($commands, $server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class Project extends BaseModel
|
|||||||
'project_id' => $project->id,
|
'project_id' => $project->id,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
static::deleted(function ($project) {
|
static::deleting(function ($project) {
|
||||||
$project->environments()->delete();
|
$project->environments()->delete();
|
||||||
$project->settings()->delete();
|
$project->settings()->delete();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ namespace App\Models;
|
|||||||
use App\Enums\ProxyStatus;
|
use App\Enums\ProxyStatus;
|
||||||
use App\Enums\ProxyTypes;
|
use App\Enums\ProxyTypes;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
|
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
|
||||||
use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
|
use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class Server extends BaseModel
|
class Server extends BaseModel
|
||||||
{
|
{
|
||||||
@@ -14,6 +16,13 @@ class Server extends BaseModel
|
|||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
|
static::saving(function ($server) {
|
||||||
|
$server->forceFill([
|
||||||
|
'ip' => Str::of($server->ip)->trim(),
|
||||||
|
'user' => Str::of($server->user)->trim(),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
static::created(function ($server) {
|
static::created(function ($server) {
|
||||||
ServerSetting::create([
|
ServerSetting::create([
|
||||||
'server_id' => $server->id,
|
'server_id' => $server->id,
|
||||||
@@ -120,7 +129,20 @@ class Server extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Service::class);
|
return $this->hasMany(Service::class);
|
||||||
}
|
}
|
||||||
|
public function getIp(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: function () {
|
||||||
|
if (isDev()) {
|
||||||
|
return '127.0.0.1';
|
||||||
|
}
|
||||||
|
if ($this->ip === 'host.docker.internal') {
|
||||||
|
return base_ip();
|
||||||
|
}
|
||||||
|
return $this->ip;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
public function previews()
|
public function previews()
|
||||||
{
|
{
|
||||||
return $this->destinations()->map(function ($standaloneDocker) {
|
return $this->destinations()->map(function ($standaloneDocker) {
|
||||||
@@ -185,4 +207,48 @@ class Server extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->settings->is_reachable && $this->settings->is_usable;
|
return $this->settings->is_reachable && $this->settings->is_usable;
|
||||||
}
|
}
|
||||||
|
public function validateConnection()
|
||||||
|
{
|
||||||
|
$uptime = instant_remote_process(['uptime'], $this, false);
|
||||||
|
if (!$uptime) {
|
||||||
|
$this->settings->is_reachable = false;
|
||||||
|
$this->settings->save();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->settings->is_reachable = true;
|
||||||
|
$this->settings->save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public function validateDockerEngine($throwError = false)
|
||||||
|
{
|
||||||
|
$dockerBinary = instant_remote_process(["command -v docker"], $this, false);
|
||||||
|
if (is_null($dockerBinary)) {
|
||||||
|
$this->settings->is_usable = false;
|
||||||
|
$this->settings->save();
|
||||||
|
if ($throwError) {
|
||||||
|
throw new \Exception('Server is not usable.');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->settings->is_usable = true;
|
||||||
|
$this->settings->save();
|
||||||
|
$this->validateCoolifyNetwork();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public function validateDockerEngineVersion()
|
||||||
|
{
|
||||||
|
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this, false);
|
||||||
|
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
|
||||||
|
if (is_null($dockerVersion)) {
|
||||||
|
$this->settings->is_usable = false;
|
||||||
|
$this->settings->save();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$this->settings->is_usable = true;
|
||||||
|
$this->settings->save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public function validateCoolifyNetwork() {
|
||||||
|
return instant_remote_process(["docker network create coolify --attachable >/dev/null 2>&1 || true"], $this, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use Illuminate\Support\Collection;
|
|||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Spatie\Url\Url;
|
|
||||||
|
|
||||||
class Service extends BaseModel
|
class Service extends BaseModel
|
||||||
{
|
{
|
||||||
@@ -17,9 +16,10 @@ class Service extends BaseModel
|
|||||||
|
|
||||||
protected static function booted()
|
protected static function booted()
|
||||||
{
|
{
|
||||||
static::deleted(function ($service) {
|
static::deleting(function ($service) {
|
||||||
$storagesToDelete = collect([]);
|
$storagesToDelete = collect([]);
|
||||||
foreach ($service->applications()->get() as $application) {
|
foreach ($service->applications()->get() as $application) {
|
||||||
|
instant_remote_process(["docker rm -f {$application->name}-{$service->uuid}"], $service->server, false);
|
||||||
$storages = $application->persistentStorages()->get();
|
$storages = $application->persistentStorages()->get();
|
||||||
foreach ($storages as $storage) {
|
foreach ($storages as $storage) {
|
||||||
$storagesToDelete->push($storage);
|
$storagesToDelete->push($storage);
|
||||||
@@ -27,6 +27,7 @@ class Service extends BaseModel
|
|||||||
$application->persistentStorages()->delete();
|
$application->persistentStorages()->delete();
|
||||||
}
|
}
|
||||||
foreach ($service->databases()->get() as $database) {
|
foreach ($service->databases()->get() as $database) {
|
||||||
|
instant_remote_process(["docker rm -f {$database->name}-{$service->uuid}"], $service->server, false);
|
||||||
$storages = $database->persistentStorages()->get();
|
$storages = $database->persistentStorages()->get();
|
||||||
foreach ($storages as $storage) {
|
foreach ($storages as $storage) {
|
||||||
$storagesToDelete->push($storage);
|
$storagesToDelete->push($storage);
|
||||||
@@ -63,6 +64,10 @@ class Service extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->hasMany(ServiceDatabase::class);
|
return $this->hasMany(ServiceDatabase::class);
|
||||||
}
|
}
|
||||||
|
public function destination()
|
||||||
|
{
|
||||||
|
return $this->morphTo();
|
||||||
|
}
|
||||||
public function environment()
|
public function environment()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Environment::class);
|
return $this->belongsTo(Environment::class);
|
||||||
@@ -112,7 +117,7 @@ class Service extends BaseModel
|
|||||||
|
|
||||||
public function parse(bool $isNew = false): Collection
|
public function parse(bool $isNew = false): Collection
|
||||||
{
|
{
|
||||||
// ray()->clearAll();
|
ray()->clearAll();
|
||||||
if ($this->docker_compose_raw) {
|
if ($this->docker_compose_raw) {
|
||||||
try {
|
try {
|
||||||
$yaml = Yaml::parse($this->docker_compose_raw);
|
$yaml = Yaml::parse($this->docker_compose_raw);
|
||||||
@@ -124,9 +129,16 @@ class Service extends BaseModel
|
|||||||
$topLevelNetworks = collect(data_get($yaml, 'networks', []));
|
$topLevelNetworks = collect(data_get($yaml, 'networks', []));
|
||||||
$dockerComposeVersion = data_get($yaml, 'version') ?? '3.8';
|
$dockerComposeVersion = data_get($yaml, 'version') ?? '3.8';
|
||||||
$services = data_get($yaml, 'services');
|
$services = data_get($yaml, 'services');
|
||||||
$definedNetwork = $this->uuid;
|
|
||||||
|
|
||||||
$generatedServiceFQDNS = collect([]);
|
$generatedServiceFQDNS = collect([]);
|
||||||
|
if (is_null($this->destination)) {
|
||||||
|
$destination = $this->server->destinations()->first();
|
||||||
|
if ($destination) {
|
||||||
|
$this->destination()->associate($destination);
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$definedNetwork = collect([$this->uuid]);
|
||||||
|
|
||||||
$services = collect($services)->map(function ($service, $serviceName) use ($topLevelVolumes, $topLevelNetworks, $definedNetwork, $isNew, $generatedServiceFQDNS) {
|
$services = collect($services)->map(function ($service, $serviceName) use ($topLevelVolumes, $topLevelNetworks, $definedNetwork, $isNew, $generatedServiceFQDNS) {
|
||||||
$serviceVolumes = collect(data_get($service, 'volumes', []));
|
$serviceVolumes = collect(data_get($service, 'volumes', []));
|
||||||
@@ -237,18 +249,24 @@ class Service extends BaseModel
|
|||||||
return $value == $definedNetwork;
|
return $value == $definedNetwork;
|
||||||
});
|
});
|
||||||
if (!$definedNetworkExists) {
|
if (!$definedNetworkExists) {
|
||||||
$topLevelNetworks->put($definedNetwork, [
|
foreach ($definedNetwork as $network) {
|
||||||
'name' => $definedNetwork,
|
$topLevelNetworks->put($network, [
|
||||||
|
'name' => $network,
|
||||||
'external' => true
|
'external' => true
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$networks = $serviceNetworks->toArray();
|
$networks = $serviceNetworks->toArray();
|
||||||
$networks = array_merge($networks, [$definedNetwork]);
|
foreach ($definedNetwork as $key => $network) {
|
||||||
|
$networks = array_merge($networks, [
|
||||||
|
$network
|
||||||
|
]);
|
||||||
|
}
|
||||||
data_set($service, 'networks', $networks);
|
data_set($service, 'networks', $networks);
|
||||||
|
|
||||||
// Collect/create/update volumes
|
// Collect/create/update volumes
|
||||||
if ($serviceVolumes->count() > 0) {
|
if ($serviceVolumes->count() > 0) {
|
||||||
foreach ($serviceVolumes as $volume) {
|
$serviceVolumes = $serviceVolumes->map(function ($volume) use ($savedService, $topLevelVolumes) {
|
||||||
$type = null;
|
$type = null;
|
||||||
$source = null;
|
$source = null;
|
||||||
$target = null;
|
$target = null;
|
||||||
@@ -270,16 +288,19 @@ class Service extends BaseModel
|
|||||||
$isDirectory = (bool) data_get($volume, 'isDirectory', false);
|
$isDirectory = (bool) data_get($volume, 'isDirectory', false);
|
||||||
$foundConfig = $savedService->fileStorages()->whereMountPath($target)->first();
|
$foundConfig = $savedService->fileStorages()->whereMountPath($target)->first();
|
||||||
if ($foundConfig) {
|
if ($foundConfig) {
|
||||||
$content = data_get($foundConfig, 'content');
|
$contentNotNull = data_get($foundConfig, 'content');
|
||||||
|
if ($contentNotNull) {
|
||||||
|
$content = $contentNotNull;
|
||||||
|
}
|
||||||
$isDirectory = (bool) data_get($foundConfig, 'is_directory');
|
$isDirectory = (bool) data_get($foundConfig, 'is_directory');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($type->value() === 'bind') {
|
if ($type->value() === 'bind') {
|
||||||
if ($source->value() === "/var/run/docker.sock") {
|
if ($source->value() === "/var/run/docker.sock") {
|
||||||
continue;
|
return $volume;
|
||||||
}
|
}
|
||||||
if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
|
if ($source->value() === '/tmp' || $source->value() === '/tmp/') {
|
||||||
continue;
|
return $volume;
|
||||||
}
|
}
|
||||||
LocalFileVolume::updateOrCreate(
|
LocalFileVolume::updateOrCreate(
|
||||||
[
|
[
|
||||||
@@ -297,7 +318,19 @@ class Service extends BaseModel
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
} else if ($type->value() === 'volume') {
|
} else if ($type->value() === 'volume') {
|
||||||
$topLevelVolumes->put($source->value(), null);
|
$slugWithoutUuid = Str::slug($source, '-');
|
||||||
|
$name = "{$savedService->service->uuid}_{$slugWithoutUuid}";
|
||||||
|
if (is_string($volume)) {
|
||||||
|
$source = Str::of($volume)->before(':');
|
||||||
|
$target = Str::of($volume)->after(':')->beforeLast(':');
|
||||||
|
$source = $name;
|
||||||
|
$volume = "$source:$target";
|
||||||
|
} else if (is_array($volume)) {
|
||||||
|
data_set($volume, 'source', $name);
|
||||||
|
}
|
||||||
|
$topLevelVolumes->put($name, [
|
||||||
|
'name' => $name,
|
||||||
|
]);
|
||||||
LocalPersistentVolume::updateOrCreate(
|
LocalPersistentVolume::updateOrCreate(
|
||||||
[
|
[
|
||||||
'mount_path' => $target,
|
'mount_path' => $target,
|
||||||
@@ -305,15 +338,17 @@ class Service extends BaseModel
|
|||||||
'resource_type' => get_class($savedService)
|
'resource_type' => get_class($savedService)
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => Str::slug($source, '-'),
|
'name' => $name,
|
||||||
'mount_path' => $target,
|
'mount_path' => $target,
|
||||||
'resource_id' => $savedService->id,
|
'resource_id' => $savedService->id,
|
||||||
'resource_type' => get_class($savedService)
|
'resource_type' => get_class($savedService)
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$savedService->getFilesFromServer();
|
$savedService->getFilesFromServer(isInit: true);
|
||||||
}
|
return $volume;
|
||||||
|
});
|
||||||
|
data_set($service, 'volumes', $serviceVolumes->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add env_file with at least .env to the service
|
// Add env_file with at least .env to the service
|
||||||
@@ -349,9 +384,23 @@ class Service extends BaseModel
|
|||||||
$value = Str::of($variable);
|
$value = Str::of($variable);
|
||||||
}
|
}
|
||||||
if ($key->startsWith('SERVICE_FQDN')) {
|
if ($key->startsWith('SERVICE_FQDN')) {
|
||||||
if (is_null(data_get($savedService, 'fqdn'))) {
|
if ($isNew) {
|
||||||
$fqdn = generateFqdn($this->server, $containerName);
|
$name = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower();
|
||||||
if (substr_count($key->value(), '_') === 2 && $key->contains("=")) {
|
$fqdn = generateFqdn($this->server, "{$name->value()}-{$this->uuid}");
|
||||||
|
if (substr_count($key->value(), '_') === 3) {
|
||||||
|
// SERVICE_FQDN_UMAMI_1000
|
||||||
|
$port = $key->afterLast('_');
|
||||||
|
} else {
|
||||||
|
// SERVICE_FQDN_UMAMI
|
||||||
|
$port = null;
|
||||||
|
}
|
||||||
|
if ($port) {
|
||||||
|
$fqdn = "$fqdn:$port";
|
||||||
|
}
|
||||||
|
if (substr_count($key->value(), '_') >= 2) {
|
||||||
|
if (is_null($value)) {
|
||||||
|
$value = Str::of('/');
|
||||||
|
}
|
||||||
$path = $value->value();
|
$path = $value->value();
|
||||||
if ($generatedServiceFQDNS->count() > 0) {
|
if ($generatedServiceFQDNS->count() > 0) {
|
||||||
$alreadyGenerated = $generatedServiceFQDNS->has($key->value());
|
$alreadyGenerated = $generatedServiceFQDNS->has($key->value());
|
||||||
@@ -365,11 +414,22 @@ class Service extends BaseModel
|
|||||||
}
|
}
|
||||||
$fqdn = "$fqdn$path";
|
$fqdn = "$fqdn$path";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$isDatabase) {
|
if (!$isDatabase) {
|
||||||
|
if ($savedService->fqdn) {
|
||||||
|
$fqdn = $savedService->fqdn . ',' . $fqdn;
|
||||||
|
} else {
|
||||||
|
$fqdn = $fqdn;
|
||||||
|
}
|
||||||
$savedService->fqdn = $fqdn;
|
$savedService->fqdn = $fqdn;
|
||||||
$savedService->save();
|
$savedService->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// data_forget($service, "environment.$variableName");
|
||||||
|
// $yaml = data_forget($yaml, "services.$serviceName.environment.$variableName");
|
||||||
|
// if (count(data_get($yaml, 'services.' . $serviceName . '.environment')) === 0) {
|
||||||
|
// $yaml = data_forget($yaml, "services.$serviceName.environment");
|
||||||
|
// }
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($value?->startsWith('$')) {
|
if ($value?->startsWith('$')) {
|
||||||
@@ -384,10 +444,17 @@ class Service extends BaseModel
|
|||||||
$forService = $value->afterLast('_');
|
$forService = $value->afterLast('_');
|
||||||
$generatedValue = null;
|
$generatedValue = null;
|
||||||
if ($command->value() === 'FQDN' || $command->value() === 'URL') {
|
if ($command->value() === 'FQDN' || $command->value() === 'URL') {
|
||||||
|
if (Str::lower($forService) === $serviceName) {
|
||||||
$fqdn = generateFqdn($this->server, $containerName);
|
$fqdn = generateFqdn($this->server, $containerName);
|
||||||
|
} else {
|
||||||
|
$fqdn = generateFqdn($this->server, Str::lower($forService) . '-' . $this->uuid);
|
||||||
|
}
|
||||||
if ($foundEnv) {
|
if ($foundEnv) {
|
||||||
$fqdn = data_get($foundEnv, 'value');
|
$fqdn = data_get($foundEnv, 'value');
|
||||||
} else {
|
} else {
|
||||||
|
if ($command->value() === 'URL') {
|
||||||
|
$fqdn = Str::of($fqdn)->after('://')->value();
|
||||||
|
}
|
||||||
EnvironmentVariable::create([
|
EnvironmentVariable::create([
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'value' => $fqdn,
|
'value' => $fqdn,
|
||||||
@@ -396,11 +463,12 @@ class Service extends BaseModel
|
|||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$isDatabase) {
|
if (!$isDatabase) {
|
||||||
|
if ($command->value() === 'FQDN') {
|
||||||
$savedService->fqdn = $fqdn;
|
$savedService->fqdn = $fqdn;
|
||||||
$savedService->save();
|
$savedService->save();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
switch ($command) {
|
switch ($command) {
|
||||||
case 'PASSWORD':
|
case 'PASSWORD':
|
||||||
@@ -472,25 +540,27 @@ class Service extends BaseModel
|
|||||||
$serviceLabels = $serviceLabels->merge($defaultLabels);
|
$serviceLabels = $serviceLabels->merge($defaultLabels);
|
||||||
if (!$isDatabase && $fqdns->count() > 0) {
|
if (!$isDatabase && $fqdns->count() > 0) {
|
||||||
if ($fqdns) {
|
if ($fqdns) {
|
||||||
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($fqdns, $containerName, true));
|
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($fqdns, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data_set($service, 'labels', $serviceLabels->toArray());
|
data_set($service, 'labels', $serviceLabels->toArray());
|
||||||
data_forget($service, 'is_database');
|
data_forget($service, 'is_database');
|
||||||
data_set($service, 'restart', RESTART_MODE);
|
data_set($service, 'restart', RESTART_MODE);
|
||||||
data_set($service, 'container_name', $containerName);
|
data_set($service, 'container_name', $containerName);
|
||||||
data_forget($service, 'volumes.*.content');
|
data_forget($service, 'volumes.*.content');
|
||||||
data_forget($service, 'volumes.*.isDirectory');
|
data_forget($service, 'volumes.*.isDirectory');
|
||||||
|
|
||||||
// Remove unnecessary variables from service.environment
|
// Remove unnecessary variables from service.environment
|
||||||
$withoutServiceEnvs = collect([]);
|
// $withoutServiceEnvs = collect([]);
|
||||||
collect(data_get($service, 'environment'))->each(function ($value, $key) use ($withoutServiceEnvs) {
|
// collect(data_get($service, 'environment'))->each(function ($value, $key) use ($withoutServiceEnvs) {
|
||||||
if (!Str::of($key)->startsWith('$SERVICE_')) {
|
// ray($key, $value);
|
||||||
$withoutServiceEnvs->put($key, $value);
|
// if (!Str::of($key)->startsWith('$SERVICE_') && !Str::of($value)->startsWith('SERVICE_')) {
|
||||||
}
|
// $k = Str::of($value)->before("=");
|
||||||
});
|
// $v = Str::of($value)->after("=");
|
||||||
data_set($service, 'environment', $withoutServiceEnvs->toArray());
|
// $withoutServiceEnvs->put($k->value(), $v->value());
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// ray($withoutServiceEnvs);
|
||||||
|
// data_set($service, 'environment', $withoutServiceEnvs->toArray());
|
||||||
return $service;
|
return $service;
|
||||||
});
|
});
|
||||||
$finalServices = [
|
$finalServices = [
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ class ServiceApplication extends BaseModel
|
|||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public function getFilesFromServer()
|
public function getFilesFromServer(bool $isInit = false)
|
||||||
{
|
{
|
||||||
getFilesystemVolumesFromServer($this);
|
getFilesystemVolumesFromServer($this, $isInit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Symfony\Component\Yaml\Yaml;
|
|
||||||
|
|
||||||
class ServiceDatabase extends BaseModel
|
class ServiceDatabase extends BaseModel
|
||||||
{
|
{
|
||||||
@@ -26,8 +25,8 @@ class ServiceDatabase extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->morphMany(LocalFileVolume::class, 'resource');
|
return $this->morphMany(LocalFileVolume::class, 'resource');
|
||||||
}
|
}
|
||||||
public function getFilesFromServer()
|
public function getFilesFromServer(bool $isInit = false)
|
||||||
{
|
{
|
||||||
getFilesystemVolumesFromServer($this);
|
getFilesystemVolumesFromServer($this, $isInit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,21 @@ class StandalonePostgresql extends BaseModel
|
|||||||
'is_readonly' => true
|
'is_readonly' => true
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
static::deleted(function ($database) {
|
static::deleting(function ($database) {
|
||||||
|
// Stop Container
|
||||||
|
instant_remote_process(
|
||||||
|
["docker rm -f {$database->uuid}"],
|
||||||
|
$database->destination->server,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
// Stop TCP Proxy
|
||||||
|
if ($database->is_public) {
|
||||||
|
instant_remote_process(["docker rm -f {$database->uuid}-proxy"], $database->destination->server, false);
|
||||||
|
}
|
||||||
$database->scheduledBackups()->delete();
|
$database->scheduledBackups()->delete();
|
||||||
$database->persistentStorages()->delete();
|
$database->persistentStorages()->delete();
|
||||||
$database->environment_variables()->delete();
|
$database->environment_variables()->delete();
|
||||||
|
// Remove Volume
|
||||||
instant_remote_process(['docker volume rm postgres-data-' . $database->uuid], $database->destination->server, false);
|
instant_remote_process(['docker volume rm postgres-data-' . $database->uuid], $database->destination->server, false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -65,6 +76,11 @@ class StandalonePostgresql extends BaseModel
|
|||||||
return $this->belongsTo(Environment::class);
|
return $this->belongsTo(Environment::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function fileStorages()
|
||||||
|
{
|
||||||
|
return $this->morphMany(LocalFileVolume::class, 'resource');
|
||||||
|
}
|
||||||
|
|
||||||
public function destination()
|
public function destination()
|
||||||
{
|
{
|
||||||
return $this->morphTo();
|
return $this->morphTo();
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ class EmailChannel
|
|||||||
try {
|
try {
|
||||||
$this->bootConfigs($notifiable);
|
$this->bootConfigs($notifiable);
|
||||||
$recepients = $notifiable->getRecepients($notification);
|
$recepients = $notifiable->getRecepients($notification);
|
||||||
ray($recepients);
|
|
||||||
if (count($recepients) === 0) {
|
if (count($recepients) === 0) {
|
||||||
throw new Exception('No email recipients found');
|
throw new Exception('No email recipients found');
|
||||||
}
|
}
|
||||||
|
|||||||
66
app/Notifications/Server/Revived.php
Normal file
66
app/Notifications/Server/Revived.php
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Notifications\Server;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use App\Notifications\Channels\DiscordChannel;
|
||||||
|
use App\Notifications\Channels\EmailChannel;
|
||||||
|
use App\Notifications\Channels\TelegramChannel;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
|
||||||
|
class Revived extends Notification implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
public $tries = 1;
|
||||||
|
public function __construct(public Server $server)
|
||||||
|
{
|
||||||
|
if ($this->server->unreachable_email_sent === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function via(object $notifiable): array
|
||||||
|
{
|
||||||
|
$channels = [];
|
||||||
|
$isEmailEnabled = isEmailEnabled($notifiable);
|
||||||
|
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||||
|
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||||
|
|
||||||
|
if ($isDiscordEnabled) {
|
||||||
|
$channels[] = DiscordChannel::class;
|
||||||
|
}
|
||||||
|
if ($isEmailEnabled ) {
|
||||||
|
$channels[] = EmailChannel::class;
|
||||||
|
}
|
||||||
|
if ($isTelegramEnabled) {
|
||||||
|
$channels[] = TelegramChannel::class;
|
||||||
|
}
|
||||||
|
return $channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toMail(): MailMessage
|
||||||
|
{
|
||||||
|
$mail = new MailMessage();
|
||||||
|
$mail->subject("✅ Server ({$this->server->name}) revived.");
|
||||||
|
$mail->view('emails.server-revived', [
|
||||||
|
'name' => $this->server->name,
|
||||||
|
]);
|
||||||
|
return $mail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toDiscord(): string
|
||||||
|
{
|
||||||
|
$message = "✅ Server '{$this->server->name}' revived. All automations & integrations are turned on again!";
|
||||||
|
return $message;
|
||||||
|
}
|
||||||
|
public function toTelegram(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
"message" => "✅ Server '{$this->server->name}' revived. All automations & integrations are turned on again!"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,9 @@
|
|||||||
namespace App\Notifications\Server;
|
namespace App\Notifications\Server;
|
||||||
|
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Notifications\Channels\DiscordChannel;
|
||||||
|
use App\Notifications\Channels\EmailChannel;
|
||||||
|
use App\Notifications\Channels\TelegramChannel;
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
@@ -20,7 +23,21 @@ class Unreachable extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function via(object $notifiable): array
|
public function via(object $notifiable): array
|
||||||
{
|
{
|
||||||
return setNotificationChannels($notifiable, 'status_changes');
|
$channels = [];
|
||||||
|
$isEmailEnabled = isEmailEnabled($notifiable);
|
||||||
|
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||||
|
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||||
|
|
||||||
|
if ($isDiscordEnabled) {
|
||||||
|
$channels[] = DiscordChannel::class;
|
||||||
|
}
|
||||||
|
if ($isEmailEnabled ) {
|
||||||
|
$channels[] = EmailChannel::class;
|
||||||
|
}
|
||||||
|
if ($isTelegramEnabled) {
|
||||||
|
$channels[] = TelegramChannel::class;
|
||||||
|
}
|
||||||
|
return $channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
@@ -35,13 +52,13 @@ class Unreachable extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toDiscord(): string
|
public function toDiscord(): string
|
||||||
{
|
{
|
||||||
$message = "⛔ Server '{$this->server->name}' is unreachable after trying to connect to it 5 times. All automations & integrations are turned off! Please check your server! IMPORTANT: You have to validate your server again after you fix the issue.";
|
$message = "⛔ Server '{$this->server->name}' is unreachable after trying to connect to it 5 times. All automations & integrations are turned off! Please check your server! IMPORTANT: We automatically try to revive your server. If your server is back online, we will automatically turn on all automations & integrations.";
|
||||||
return $message;
|
return $message;
|
||||||
}
|
}
|
||||||
public function toTelegram(): array
|
public function toTelegram(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
"message" => "⛔ Server '{$this->server->name}' is unreachable after trying to connect to it 5 times. All automations & integrations are turned off! Please check your server! IMPORTANT: You have to validate your server again after you fix the issue."
|
"message" => "⛔ Server '{$this->server->name}' is unreachable after trying to connect to it 5 times. All automations & integrations are turned off! Please check your server! IMPORTANT: We automatically try to revive your server. If your server is back online, we will automatically turn on all automations & integrations."
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Enums\ProxyTypes;
|
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\ApplicationPreview;
|
use App\Models\ApplicationPreview;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Spatie\Url\Url;
|
use Spatie\Url\Url;
|
||||||
|
use Visus\Cuid2\Cuid2;
|
||||||
|
|
||||||
function getCurrentApplicationContainerStatus(Server $server, int $id): Collection
|
function getCurrentApplicationContainerStatus(Server $server, int $id): Collection
|
||||||
{
|
{
|
||||||
@@ -104,16 +104,16 @@ function getContainerStatus(Server $server, string $container_id, bool $all_data
|
|||||||
return data_get($container[0], 'State.Status', 'exited');
|
return data_get($container[0], 'State.Status', 'exited');
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateApplicationContainerName(Application $application)
|
function generateApplicationContainerName(Application $application, $pull_request_id = 0)
|
||||||
{
|
{
|
||||||
$now = now()->format('Hisu');
|
$now = now()->format('Hisu');
|
||||||
if ($application->pull_request_id !== 0 && $application->pull_request_id !== null) {
|
if ($pull_request_id !== 0 && $pull_request_id !== null) {
|
||||||
return $application->uuid . '-pr-' . $application->pull_request_id;
|
return $application->uuid . '-pr-' . $pull_request_id;
|
||||||
} else {
|
} else {
|
||||||
return $application->uuid . '-' . $now;
|
return $application->uuid . '-' . $now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function get_port_from_dockerfile($dockerfile): int
|
function get_port_from_dockerfile($dockerfile): int|null
|
||||||
{
|
{
|
||||||
$dockerfile_array = explode("\n", $dockerfile);
|
$dockerfile_array = explode("\n", $dockerfile);
|
||||||
$found_exposed_port = null;
|
$found_exposed_port = null;
|
||||||
@@ -127,7 +127,7 @@ function get_port_from_dockerfile($dockerfile): int
|
|||||||
if ($found_exposed_port) {
|
if ($found_exposed_port) {
|
||||||
return (int)$found_exposed_port->value();
|
return (int)$found_exposed_port->value();
|
||||||
}
|
}
|
||||||
return 80;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'application', $subType = null, $subId = null)
|
function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'application', $subType = null, $subId = null)
|
||||||
@@ -147,20 +147,20 @@ function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'applica
|
|||||||
}
|
}
|
||||||
return $labels;
|
return $labels;
|
||||||
}
|
}
|
||||||
function fqdnLabelsForTraefik(Collection $domains, $container_name, $is_force_https_enabled)
|
function fqdnLabelsForTraefik(Collection $domains, bool $is_force_https_enabled)
|
||||||
{
|
{
|
||||||
$labels = collect([]);
|
$labels = collect([]);
|
||||||
$labels->push('traefik.enable=true');
|
$labels->push('traefik.enable=true');
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
|
$uuid = (string)new Cuid2(7);
|
||||||
$url = Url::fromString($domain);
|
$url = Url::fromString($domain);
|
||||||
$host = $url->getHost();
|
$host = $url->getHost();
|
||||||
$path = $url->getPath();
|
$path = $url->getPath();
|
||||||
$schema = $url->getScheme();
|
$schema = $url->getScheme();
|
||||||
$port = $url->getPort();
|
$port = $url->getPort();
|
||||||
$slug = Str::slug($host . $path);
|
|
||||||
|
|
||||||
$http_label = "{$container_name}-{$slug}-http";
|
$http_label = "{$uuid}-http";
|
||||||
$https_label = "{$container_name}-{$slug}-https";
|
$https_label = "{$uuid}-https";
|
||||||
|
|
||||||
if ($schema === 'https') {
|
if ($schema === 'https') {
|
||||||
// Set labels for https
|
// Set labels for https
|
||||||
@@ -207,10 +207,10 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
|||||||
{
|
{
|
||||||
|
|
||||||
$pull_request_id = data_get($preview, 'pull_request_id', 0);
|
$pull_request_id = data_get($preview, 'pull_request_id', 0);
|
||||||
$container_name = generateApplicationContainerName($application);
|
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
||||||
$appId = $application->id;
|
$appId = $application->id;
|
||||||
if ($pull_request_id !== 0) {
|
if ($pull_request_id !== 0 && $pull_request_id !== null) {
|
||||||
$appId = $appId . '-pr-' . $application->pull_request_id;
|
$appId = $appId . '-pr-' . $pull_request_id;
|
||||||
}
|
}
|
||||||
$labels = collect([]);
|
$labels = collect([]);
|
||||||
$labels = $labels->merge(defaultLabels($appId, $container_name, $pull_request_id));
|
$labels = $labels->merge(defaultLabels($appId, $container_name, $pull_request_id));
|
||||||
@@ -221,7 +221,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
|
|||||||
$domains = Str::of(data_get($application, 'fqdn'))->explode(',');
|
$domains = Str::of(data_get($application, 'fqdn'))->explode(',');
|
||||||
}
|
}
|
||||||
// Add Traefik labels no matter which proxy is selected
|
// Add Traefik labels no matter which proxy is selected
|
||||||
$labels = $labels->merge(fqdnLabelsForTraefik($domains, $container_name, $application->settings->is_force_https_enabled));
|
$labels = $labels->merge(fqdnLabelsForTraefik($domains, $application->settings->is_force_https_enabled));
|
||||||
}
|
}
|
||||||
return $labels->all();
|
return $labels->all();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ function generate_github_jwt_token(GithubApp $source)
|
|||||||
return $issuedToken;
|
return $issuedToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
function git_api(GithubApp|GitlabApp $source, string $endpoint, string $method = 'get', array|null $data = null, bool $throwError = true)
|
function githubApi(GithubApp|GitlabApp $source, string $endpoint, string $method = 'get', array|null $data = null, bool $throwError = true)
|
||||||
{
|
{
|
||||||
if ($source->getMorphClass() == 'App\Models\GithubApp') {
|
if ($source->getMorphClass() == 'App\Models\GithubApp') {
|
||||||
if ($source->is_public) {
|
if ($source->is_public) {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use App\Models\Application;
|
|||||||
use App\Models\ApplicationDeploymentQueue;
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
use App\Models\PrivateKey;
|
use App\Models\PrivateKey;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
|
use App\Notifications\Server\Revived;
|
||||||
|
use App\Notifications\Server\Unreachable;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -122,7 +124,8 @@ function instant_remote_process(Collection|array $command, Server $server, $thro
|
|||||||
}
|
}
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
function excludeCertainErrors(string $errorOutput, ?int $exitCode = null) {
|
function excludeCertainErrors(string $errorOutput, ?int $exitCode = null)
|
||||||
|
{
|
||||||
$ignoredErrors = collect([
|
$ignoredErrors = collect([
|
||||||
'Permission denied (publickey',
|
'Permission denied (publickey',
|
||||||
'Could not resolve hostname',
|
'Could not resolve hostname',
|
||||||
@@ -183,6 +186,9 @@ function validateServer(Server $server, bool $throwError = false)
|
|||||||
$uptime = instant_remote_process(['uptime'], $server, $throwError);
|
$uptime = instant_remote_process(['uptime'], $server, $throwError);
|
||||||
if (!$uptime) {
|
if (!$uptime) {
|
||||||
$server->settings->is_reachable = false;
|
$server->settings->is_reachable = false;
|
||||||
|
$server->team->notify(new Unreachable($server));
|
||||||
|
$server->unreachable_email_sent = true;
|
||||||
|
$server->save();
|
||||||
return [
|
return [
|
||||||
"uptime" => null,
|
"uptime" => null,
|
||||||
"dockerVersion" => null,
|
"dockerVersion" => null,
|
||||||
@@ -203,6 +209,11 @@ function validateServer(Server $server, bool $throwError = false)
|
|||||||
$server->settings->is_usable = false;
|
$server->settings->is_usable = false;
|
||||||
} else {
|
} else {
|
||||||
$server->settings->is_usable = true;
|
$server->settings->is_usable = true;
|
||||||
|
if (data_get($server, 'unreachable_email_sent') === true) {
|
||||||
|
$server->team->notify(new Revived($server));
|
||||||
|
$server->unreachable_email_sent = false;
|
||||||
|
$server->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
"uptime" => $uptime,
|
"uptime" => $uptime,
|
||||||
@@ -213,7 +224,9 @@ function validateServer(Server $server, bool $throwError = false)
|
|||||||
$server->settings->is_usable = false;
|
$server->settings->is_usable = false;
|
||||||
throw $e;
|
throw $e;
|
||||||
} finally {
|
} finally {
|
||||||
if (data_get($server, 'settings')) $server->settings->save();
|
if (data_get($server, 'settings')) {
|
||||||
|
$server->settings->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ function serviceStatus(Service $service)
|
|||||||
}
|
}
|
||||||
return 'exited';
|
return 'exited';
|
||||||
}
|
}
|
||||||
function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase $oneService)
|
function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase $oneService, bool $isInit = false)
|
||||||
{
|
{
|
||||||
// TODO: make this async
|
// TODO: make this async
|
||||||
try {
|
try {
|
||||||
@@ -85,24 +85,39 @@ function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase $oneS
|
|||||||
} else {
|
} else {
|
||||||
$fileLocation = $path;
|
$fileLocation = $path;
|
||||||
}
|
}
|
||||||
|
ray($path,$fileLocation);
|
||||||
|
// Exists and is a file
|
||||||
$isFile = instant_remote_process(["test -f $fileLocation && echo OK || echo NOK"], $server);
|
$isFile = instant_remote_process(["test -f $fileLocation && echo OK || echo NOK"], $server);
|
||||||
|
// Exists and is a directory
|
||||||
$isDir = instant_remote_process(["test -d $fileLocation && echo OK || echo NOK"], $server);
|
$isDir = instant_remote_process(["test -d $fileLocation && echo OK || echo NOK"], $server);
|
||||||
if ($isFile == 'OK' && !$fileVolume->is_directory) {
|
|
||||||
|
if ($isFile == 'OK') {
|
||||||
|
// If its a file & exists
|
||||||
$filesystemContent = instant_remote_process(["cat $fileLocation"], $server);
|
$filesystemContent = instant_remote_process(["cat $fileLocation"], $server);
|
||||||
if (base64_encode($filesystemContent) != base64_encode($content)) {
|
|
||||||
$fileVolume->content = $filesystemContent;
|
$fileVolume->content = $filesystemContent;
|
||||||
|
$fileVolume->is_directory = false;
|
||||||
$fileVolume->save();
|
$fileVolume->save();
|
||||||
}
|
} else if ($isDir == 'OK') {
|
||||||
} else {
|
// If its a directory & exists
|
||||||
if ($isDir == 'OK') {
|
|
||||||
$fileVolume->content = null;
|
$fileVolume->content = null;
|
||||||
$fileVolume->is_directory = true;
|
$fileVolume->is_directory = true;
|
||||||
$fileVolume->save();
|
$fileVolume->save();
|
||||||
} else {
|
} else if ($isFile == 'NOK' && $isDir == 'NOK' && !$fileVolume->is_directory && $isInit && $content) {
|
||||||
$fileVolume->content = null;
|
// Does not exists (no dir or file), not flagged as directory, is init, has content
|
||||||
|
$fileVolume->content = $content;
|
||||||
$fileVolume->is_directory = false;
|
$fileVolume->is_directory = false;
|
||||||
$fileVolume->save();
|
$fileVolume->save();
|
||||||
}
|
$content = base64_encode($content);
|
||||||
|
$dir = Str::of($fileLocation)->dirname();
|
||||||
|
instant_remote_process([
|
||||||
|
"mkdir -p $dir",
|
||||||
|
"echo '$content' | base64 -d > $fileLocation"
|
||||||
|
], $server);
|
||||||
|
} else if ($isFile == 'NOK' && $isDir == 'NOK' && $fileVolume->is_directory && $isInit) {
|
||||||
|
$fileVolume->content = null;
|
||||||
|
$fileVolume->is_directory = true;
|
||||||
|
$fileVolume->save();
|
||||||
|
instant_remote_process(["mkdir -p $fileLocation"], $server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
@@ -122,13 +137,18 @@ function updateCompose($resource)
|
|||||||
|
|
||||||
// Update FQDN
|
// Update FQDN
|
||||||
$variableName = "SERVICE_FQDN_" . Str::of($resource->name)->upper();
|
$variableName = "SERVICE_FQDN_" . Str::of($resource->name)->upper();
|
||||||
ray($variableName);
|
|
||||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
if ($generatedEnv) {
|
if ($generatedEnv) {
|
||||||
$generatedEnv->value = $resource->fqdn;
|
$generatedEnv->value = $resource->fqdn;
|
||||||
$generatedEnv->save();
|
$generatedEnv->save();
|
||||||
}
|
}
|
||||||
|
$variableName = "SERVICE_URL_" . Str::of($resource->name)->upper();
|
||||||
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
|
if ($generatedEnv) {
|
||||||
|
$url = Str::of($resource->fqdn)->after('://');
|
||||||
|
$generatedEnv->value = $url;
|
||||||
|
$generatedEnv->save();
|
||||||
|
}
|
||||||
|
|
||||||
$dockerComposeRaw = Yaml::dump($dockerCompose, 10, 2);
|
$dockerComposeRaw = Yaml::dump($dockerCompose, 10, 2);
|
||||||
$resource->service->docker_compose_raw = $dockerComposeRaw;
|
$resource->service->docker_compose_raw = $dockerComposeRaw;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use Illuminate\Mail\Message;
|
|||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Mail;
|
use Illuminate\Support\Facades\Mail;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
@@ -309,6 +310,7 @@ function send_internal_notification(string $message): void
|
|||||||
$baseUrl = config('app.name');
|
$baseUrl = config('app.name');
|
||||||
$team = Team::find(0);
|
$team = Team::find(0);
|
||||||
$team->notify(new GeneralNotification("👀 {$baseUrl}: " . $message));
|
$team->notify(new GeneralNotification("👀 {$baseUrl}: " . $message));
|
||||||
|
ray("👀 {$baseUrl}: " . $message);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
ray($e->getMessage());
|
ray($e->getMessage());
|
||||||
}
|
}
|
||||||
@@ -342,6 +344,15 @@ function send_user_an_email(MailMessage $mail, string $email, ?string $cc = null
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function isTestEmailEnabled($notifiable)
|
||||||
|
{
|
||||||
|
if (data_get($notifiable, 'use_instance_email_settings') && isInstanceAdmin()) {
|
||||||
|
return true;
|
||||||
|
} else if (data_get($notifiable, 'smtp_enabled') || data_get($notifiable, 'resend_enabled') && auth()->user()->isAdminFromSession()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
function isEmailEnabled($notifiable)
|
function isEmailEnabled($notifiable)
|
||||||
{
|
{
|
||||||
return data_get($notifiable, 'smtp_enabled') || data_get($notifiable, 'resend_enabled') || data_get($notifiable, 'use_instance_email_settings');
|
return data_get($notifiable, 'smtp_enabled') || data_get($notifiable, 'resend_enabled') || data_get($notifiable, 'use_instance_email_settings');
|
||||||
@@ -352,13 +363,14 @@ function setNotificationChannels($notifiable, $event)
|
|||||||
$isEmailEnabled = isEmailEnabled($notifiable);
|
$isEmailEnabled = isEmailEnabled($notifiable);
|
||||||
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
$isDiscordEnabled = data_get($notifiable, 'discord_enabled');
|
||||||
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
$isTelegramEnabled = data_get($notifiable, 'telegram_enabled');
|
||||||
|
$isSubscribedToEmailEvent = data_get($notifiable, "smtp_notifications_$event");
|
||||||
$isSubscribedToDiscordEvent = data_get($notifiable, "discord_notifications_$event");
|
$isSubscribedToDiscordEvent = data_get($notifiable, "discord_notifications_$event");
|
||||||
$isSubscribedToTelegramEvent = data_get($notifiable, "telegram_notifications_$event");
|
$isSubscribedToTelegramEvent = data_get($notifiable, "telegram_notifications_$event");
|
||||||
|
|
||||||
if ($isDiscordEnabled && $isSubscribedToDiscordEvent) {
|
if ($isDiscordEnabled && $isSubscribedToDiscordEvent) {
|
||||||
$channels[] = DiscordChannel::class;
|
$channels[] = DiscordChannel::class;
|
||||||
}
|
}
|
||||||
if ($isEmailEnabled) {
|
if ($isEmailEnabled && $isSubscribedToEmailEvent) {
|
||||||
$channels[] = EmailChannel::class;
|
$channels[] = EmailChannel::class;
|
||||||
}
|
}
|
||||||
if ($isTelegramEnabled && $isSubscribedToTelegramEvent) {
|
if ($isTelegramEnabled && $isSubscribedToTelegramEvent) {
|
||||||
@@ -425,6 +437,16 @@ function getServiceTemplates()
|
|||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$services = File::get(base_path('templates/service-templates.json'));
|
$services = File::get(base_path('templates/service-templates.json'));
|
||||||
$services = collect(json_decode($services))->sortKeys();
|
$services = collect(json_decode($services))->sortKeys();
|
||||||
|
$deprecated = File::get(base_path('templates/deprecated.json'));
|
||||||
|
$deprecated = collect(json_decode($deprecated))->sortKeys();
|
||||||
|
$services = $services->merge($deprecated);
|
||||||
|
$version = config('version');
|
||||||
|
$services = $services->map(function ($service) use ($version) {
|
||||||
|
if (version_compare($version, data_get($service, 'minVersion', '0.0.0'), '<')) {
|
||||||
|
$service->disabled = true;
|
||||||
|
}
|
||||||
|
return $service;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$services = Http::get(config('constants.services.official'));
|
$services = Http::get(config('constants.services.official'));
|
||||||
if ($services->failed()) {
|
if ($services->failed()) {
|
||||||
|
|||||||
313
composer.lock
generated
313
composer.lock
generated
@@ -62,16 +62,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "aws/aws-sdk-php",
|
"name": "aws/aws-sdk-php",
|
||||||
"version": "3.281.12",
|
"version": "3.283.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||||
"reference": "22a92f08758db2b152843ea0875eeee5a467d8ff"
|
"reference": "5084c03431ecda0003e35d7fc7a12eeca4242685"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/22a92f08758db2b152843ea0875eeee5a467d8ff",
|
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5084c03431ecda0003e35d7fc7a12eeca4242685",
|
||||||
"reference": "22a92f08758db2b152843ea0875eeee5a467d8ff",
|
"reference": "5084c03431ecda0003e35d7fc7a12eeca4242685",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -151,9 +151,9 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.281.12"
|
"source": "https://github.com/aws/aws-sdk-php/tree/3.283.0"
|
||||||
},
|
},
|
||||||
"time": "2023-09-22T18:12:27+00:00"
|
"time": "2023-10-04T18:08:32+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bacon/bacon-qr-code",
|
"name": "bacon/bacon-qr-code",
|
||||||
@@ -603,16 +603,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/dbal",
|
"name": "doctrine/dbal",
|
||||||
"version": "3.6.7",
|
"version": "3.7.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/doctrine/dbal.git",
|
"url": "https://github.com/doctrine/dbal.git",
|
||||||
"reference": "8e0e268052b4a8974cb00215bb2892787021614f"
|
"reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/8e0e268052b4a8974cb00215bb2892787021614f",
|
"url": "https://api.github.com/repos/doctrine/dbal/zipball/00d03067f07482f025d41ab55e4ba0db5eca2cdf",
|
||||||
"reference": "8e0e268052b4a8974cb00215bb2892787021614f",
|
"reference": "00d03067f07482f025d41ab55e4ba0db5eca2cdf",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -628,9 +628,9 @@
|
|||||||
"doctrine/coding-standard": "12.0.0",
|
"doctrine/coding-standard": "12.0.0",
|
||||||
"fig/log-test": "^1",
|
"fig/log-test": "^1",
|
||||||
"jetbrains/phpstorm-stubs": "2023.1",
|
"jetbrains/phpstorm-stubs": "2023.1",
|
||||||
"phpstan/phpstan": "1.10.34",
|
"phpstan/phpstan": "1.10.35",
|
||||||
"phpstan/phpstan-strict-rules": "^1.5",
|
"phpstan/phpstan-strict-rules": "^1.5",
|
||||||
"phpunit/phpunit": "9.6.12",
|
"phpunit/phpunit": "9.6.13",
|
||||||
"psalm/plugin-phpunit": "0.18.4",
|
"psalm/plugin-phpunit": "0.18.4",
|
||||||
"slevomat/coding-standard": "8.13.1",
|
"slevomat/coding-standard": "8.13.1",
|
||||||
"squizlabs/php_codesniffer": "3.7.2",
|
"squizlabs/php_codesniffer": "3.7.2",
|
||||||
@@ -696,7 +696,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/doctrine/dbal/issues",
|
"issues": "https://github.com/doctrine/dbal/issues",
|
||||||
"source": "https://github.com/doctrine/dbal/tree/3.6.7"
|
"source": "https://github.com/doctrine/dbal/tree/3.7.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -712,20 +712,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-09-19T20:15:41+00:00"
|
"time": "2023-09-26T20:56:55+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/deprecations",
|
"name": "doctrine/deprecations",
|
||||||
"version": "v1.1.1",
|
"version": "1.1.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/doctrine/deprecations.git",
|
"url": "https://github.com/doctrine/deprecations.git",
|
||||||
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3"
|
"reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
|
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931",
|
||||||
"reference": "612a3ee5ab0d5dd97b7cf3874a6efe24325efac3",
|
"reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -757,9 +757,9 @@
|
|||||||
"homepage": "https://www.doctrine-project.org/",
|
"homepage": "https://www.doctrine-project.org/",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/doctrine/deprecations/issues",
|
"issues": "https://github.com/doctrine/deprecations/issues",
|
||||||
"source": "https://github.com/doctrine/deprecations/tree/v1.1.1"
|
"source": "https://github.com/doctrine/deprecations/tree/1.1.2"
|
||||||
},
|
},
|
||||||
"time": "2023-06-03T09:27:29+00:00"
|
"time": "2023-09-27T20:04:15+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/event-manager",
|
"name": "doctrine/event-manager",
|
||||||
@@ -1869,16 +1869,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/framework",
|
"name": "laravel/framework",
|
||||||
"version": "v10.24.0",
|
"version": "v10.26.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/framework.git",
|
"url": "https://github.com/laravel/framework.git",
|
||||||
"reference": "bcebd0a4c015d5c38aeec299d355a42451dd3726"
|
"reference": "6e5440f7c518f26b4495e5d7e4796ec239e26df9"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/framework/zipball/bcebd0a4c015d5c38aeec299d355a42451dd3726",
|
"url": "https://api.github.com/repos/laravel/framework/zipball/6e5440f7c518f26b4495e5d7e4796ec239e26df9",
|
||||||
"reference": "bcebd0a4c015d5c38aeec299d355a42451dd3726",
|
"reference": "6e5440f7c518f26b4495e5d7e4796ec239e26df9",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -1896,7 +1896,7 @@
|
|||||||
"ext-tokenizer": "*",
|
"ext-tokenizer": "*",
|
||||||
"fruitcake/php-cors": "^1.2",
|
"fruitcake/php-cors": "^1.2",
|
||||||
"guzzlehttp/uri-template": "^1.0",
|
"guzzlehttp/uri-template": "^1.0",
|
||||||
"laravel/prompts": "^0.1",
|
"laravel/prompts": "^0.1.9",
|
||||||
"laravel/serializable-closure": "^1.3",
|
"laravel/serializable-closure": "^1.3",
|
||||||
"league/commonmark": "^2.2.1",
|
"league/commonmark": "^2.2.1",
|
||||||
"league/flysystem": "^3.8.0",
|
"league/flysystem": "^3.8.0",
|
||||||
@@ -1978,7 +1978,7 @@
|
|||||||
"league/flysystem-read-only": "^3.3",
|
"league/flysystem-read-only": "^3.3",
|
||||||
"league/flysystem-sftp-v3": "^3.0",
|
"league/flysystem-sftp-v3": "^3.0",
|
||||||
"mockery/mockery": "^1.5.1",
|
"mockery/mockery": "^1.5.1",
|
||||||
"orchestra/testbench-core": "^8.10",
|
"orchestra/testbench-core": "^8.12",
|
||||||
"pda/pheanstalk": "^4.0",
|
"pda/pheanstalk": "^4.0",
|
||||||
"phpstan/phpstan": "^1.4.7",
|
"phpstan/phpstan": "^1.4.7",
|
||||||
"phpunit/phpunit": "^10.0.7",
|
"phpunit/phpunit": "^10.0.7",
|
||||||
@@ -2065,7 +2065,7 @@
|
|||||||
"issues": "https://github.com/laravel/framework/issues",
|
"issues": "https://github.com/laravel/framework/issues",
|
||||||
"source": "https://github.com/laravel/framework"
|
"source": "https://github.com/laravel/framework"
|
||||||
},
|
},
|
||||||
"time": "2023-09-19T15:25:04+00:00"
|
"time": "2023-10-03T14:24:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/horizon",
|
"name": "laravel/horizon",
|
||||||
@@ -2147,16 +2147,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/prompts",
|
"name": "laravel/prompts",
|
||||||
"version": "v0.1.8",
|
"version": "v0.1.11",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/prompts.git",
|
"url": "https://github.com/laravel/prompts.git",
|
||||||
"reference": "68dcc65babf92e1fb43cba0b3f78fc3d8002709c"
|
"reference": "cce65a90e64712909ea1adc033e1d88de8455ffd"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/prompts/zipball/68dcc65babf92e1fb43cba0b3f78fc3d8002709c",
|
"url": "https://api.github.com/repos/laravel/prompts/zipball/cce65a90e64712909ea1adc033e1d88de8455ffd",
|
||||||
"reference": "68dcc65babf92e1fb43cba0b3f78fc3d8002709c",
|
"reference": "cce65a90e64712909ea1adc033e1d88de8455ffd",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -2165,6 +2165,10 @@
|
|||||||
"php": "^8.1",
|
"php": "^8.1",
|
||||||
"symfony/console": "^6.2"
|
"symfony/console": "^6.2"
|
||||||
},
|
},
|
||||||
|
"conflict": {
|
||||||
|
"illuminate/console": ">=10.17.0 <10.25.0",
|
||||||
|
"laravel/framework": ">=10.17.0 <10.25.0"
|
||||||
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"mockery/mockery": "^1.5",
|
"mockery/mockery": "^1.5",
|
||||||
"pestphp/pest": "^2.3",
|
"pestphp/pest": "^2.3",
|
||||||
@@ -2175,6 +2179,11 @@
|
|||||||
"ext-pcntl": "Required for the spinner to be animated."
|
"ext-pcntl": "Required for the spinner to be animated."
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "0.1.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"files": [
|
"files": [
|
||||||
"src/helpers.php"
|
"src/helpers.php"
|
||||||
@@ -2189,9 +2198,9 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/laravel/prompts/issues",
|
"issues": "https://github.com/laravel/prompts/issues",
|
||||||
"source": "https://github.com/laravel/prompts/tree/v0.1.8"
|
"source": "https://github.com/laravel/prompts/tree/v0.1.11"
|
||||||
},
|
},
|
||||||
"time": "2023-09-19T15:33:56+00:00"
|
"time": "2023-10-03T01:07:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/sanctum",
|
"name": "laravel/sanctum",
|
||||||
@@ -3442,16 +3451,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nesbot/carbon",
|
"name": "nesbot/carbon",
|
||||||
"version": "2.70.0",
|
"version": "2.71.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/briannesbitt/Carbon.git",
|
"url": "https://github.com/briannesbitt/Carbon.git",
|
||||||
"reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d"
|
"reference": "98276233188583f2ff845a0f992a235472d9466a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d3298b38ea8612e5f77d38d1a99438e42f70341d",
|
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/98276233188583f2ff845a0f992a235472d9466a",
|
||||||
"reference": "d3298b38ea8612e5f77d38d1a99438e42f70341d",
|
"reference": "98276233188583f2ff845a0f992a235472d9466a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -3544,7 +3553,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-09-07T16:43:50+00:00"
|
"time": "2023-09-25T11:31:05+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "nette/schema",
|
"name": "nette/schema",
|
||||||
@@ -4767,16 +4776,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpdoc-parser",
|
"name": "phpstan/phpdoc-parser",
|
||||||
"version": "1.24.1",
|
"version": "1.24.2",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
"url": "https://github.com/phpstan/phpdoc-parser.git",
|
||||||
"reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01"
|
"reference": "bcad8d995980440892759db0c32acae7c8e79442"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01",
|
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/bcad8d995980440892759db0c32acae7c8e79442",
|
||||||
"reference": "9f854d275c2dbf84915a5c0ec9a2d17d2cd86b01",
|
"reference": "bcad8d995980440892759db0c32acae7c8e79442",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -4808,9 +4817,9 @@
|
|||||||
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
"description": "PHPDoc parser with support for nullable, intersection and generic types",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
|
||||||
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.1"
|
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.24.2"
|
||||||
},
|
},
|
||||||
"time": "2023-09-18T12:18:02+00:00"
|
"time": "2023-09-26T12:28:12+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pimple/pimple",
|
"name": "pimple/pimple",
|
||||||
@@ -6011,16 +6020,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sentry/sentry-laravel",
|
"name": "sentry/sentry-laravel",
|
||||||
"version": "3.8.0",
|
"version": "3.8.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/getsentry/sentry-laravel.git",
|
"url": "https://github.com/getsentry/sentry-laravel.git",
|
||||||
"reference": "c7e7611553f9f90af10ed98dde1a680220f02e4d"
|
"reference": "b6142a80fa9360a10b786d2da032339602d0e362"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/c7e7611553f9f90af10ed98dde1a680220f02e4d",
|
"url": "https://api.github.com/repos/getsentry/sentry-laravel/zipball/b6142a80fa9360a10b786d2da032339602d0e362",
|
||||||
"reference": "c7e7611553f9f90af10ed98dde1a680220f02e4d",
|
"reference": "b6142a80fa9360a10b786d2da032339602d0e362",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -6087,7 +6096,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/getsentry/sentry-laravel/issues",
|
"issues": "https://github.com/getsentry/sentry-laravel/issues",
|
||||||
"source": "https://github.com/getsentry/sentry-laravel/tree/3.8.0"
|
"source": "https://github.com/getsentry/sentry-laravel/tree/3.8.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -6099,7 +6108,7 @@
|
|||||||
"type": "custom"
|
"type": "custom"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-09-05T11:02:34+00:00"
|
"time": "2023-10-04T10:21:16+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "spatie/backtrace",
|
"name": "spatie/backtrace",
|
||||||
@@ -6748,16 +6757,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "stripe/stripe-php",
|
"name": "stripe/stripe-php",
|
||||||
"version": "v12.4.0",
|
"version": "v12.5.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/stripe/stripe-php.git",
|
"url": "https://github.com/stripe/stripe-php.git",
|
||||||
"reference": "7d0a90772fc1c179e370971264318208533324b9"
|
"reference": "a4249b4a90437844f6c35e8701f8c68acd206f56"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/7d0a90772fc1c179e370971264318208533324b9",
|
"url": "https://api.github.com/repos/stripe/stripe-php/zipball/a4249b4a90437844f6c35e8701f8c68acd206f56",
|
||||||
"reference": "7d0a90772fc1c179e370971264318208533324b9",
|
"reference": "a4249b4a90437844f6c35e8701f8c68acd206f56",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -6802,9 +6811,9 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/stripe/stripe-php/issues",
|
"issues": "https://github.com/stripe/stripe-php/issues",
|
||||||
"source": "https://github.com/stripe/stripe-php/tree/v12.4.0"
|
"source": "https://github.com/stripe/stripe-php/tree/v12.5.0"
|
||||||
},
|
},
|
||||||
"time": "2023-09-21T22:55:47+00:00"
|
"time": "2023-09-28T23:06:27+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
@@ -7030,16 +7039,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/error-handler",
|
"name": "symfony/error-handler",
|
||||||
"version": "v6.3.2",
|
"version": "v6.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/error-handler.git",
|
"url": "https://github.com/symfony/error-handler.git",
|
||||||
"reference": "85fd65ed295c4078367c784e8a5a6cee30348b7a"
|
"reference": "1f69476b64fb47105c06beef757766c376b548c4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/error-handler/zipball/85fd65ed295c4078367c784e8a5a6cee30348b7a",
|
"url": "https://api.github.com/repos/symfony/error-handler/zipball/1f69476b64fb47105c06beef757766c376b548c4",
|
||||||
"reference": "85fd65ed295c4078367c784e8a5a6cee30348b7a",
|
"reference": "1f69476b64fb47105c06beef757766c376b548c4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -7084,7 +7093,7 @@
|
|||||||
"description": "Provides tools to manage errors and ease debugging PHP code",
|
"description": "Provides tools to manage errors and ease debugging PHP code",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/error-handler/tree/v6.3.2"
|
"source": "https://github.com/symfony/error-handler/tree/v6.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -7100,7 +7109,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-07-16T17:05:46+00:00"
|
"time": "2023-09-12T06:57:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/event-dispatcher",
|
"name": "symfony/event-dispatcher",
|
||||||
@@ -7260,16 +7269,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/finder",
|
"name": "symfony/finder",
|
||||||
"version": "v6.3.3",
|
"version": "v6.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/finder.git",
|
"url": "https://github.com/symfony/finder.git",
|
||||||
"reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e"
|
"reference": "a1b31d88c0e998168ca7792f222cbecee47428c4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/finder/zipball/9915db259f67d21eefee768c1abcf1cc61b1fc9e",
|
"url": "https://api.github.com/repos/symfony/finder/zipball/a1b31d88c0e998168ca7792f222cbecee47428c4",
|
||||||
"reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e",
|
"reference": "a1b31d88c0e998168ca7792f222cbecee47428c4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -7304,7 +7313,7 @@
|
|||||||
"description": "Finds files and directories via an intuitive fluent interface",
|
"description": "Finds files and directories via an intuitive fluent interface",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/finder/tree/v6.3.3"
|
"source": "https://github.com/symfony/finder/tree/v6.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -7320,20 +7329,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-07-31T08:31:44+00:00"
|
"time": "2023-09-26T12:56:25+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-client",
|
"name": "symfony/http-client",
|
||||||
"version": "v6.3.2",
|
"version": "v6.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/http-client.git",
|
"url": "https://github.com/symfony/http-client.git",
|
||||||
"reference": "15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00"
|
"reference": "213e564da4cbf61acc9728d97e666bcdb868c10d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00",
|
"url": "https://api.github.com/repos/symfony/http-client/zipball/213e564da4cbf61acc9728d97e666bcdb868c10d",
|
||||||
"reference": "15f9f4bad62bfcbe48b5dedd866f04a08fc7ff00",
|
"reference": "213e564da4cbf61acc9728d97e666bcdb868c10d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -7396,7 +7405,7 @@
|
|||||||
"http"
|
"http"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/http-client/tree/v6.3.2"
|
"source": "https://github.com/symfony/http-client/tree/v6.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -7412,7 +7421,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-07-05T08:41:27+00:00"
|
"time": "2023-09-29T15:57:12+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-client-contracts",
|
"name": "symfony/http-client-contracts",
|
||||||
@@ -7494,16 +7503,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-foundation",
|
"name": "symfony/http-foundation",
|
||||||
"version": "v6.3.4",
|
"version": "v6.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/http-foundation.git",
|
"url": "https://github.com/symfony/http-foundation.git",
|
||||||
"reference": "cac1556fdfdf6719668181974104e6fcfa60e844"
|
"reference": "b50f5e281d722cb0f4c296f908bacc3e2b721957"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/cac1556fdfdf6719668181974104e6fcfa60e844",
|
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/b50f5e281d722cb0f4c296f908bacc3e2b721957",
|
||||||
"reference": "cac1556fdfdf6719668181974104e6fcfa60e844",
|
"reference": "b50f5e281d722cb0f4c296f908bacc3e2b721957",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -7551,7 +7560,7 @@
|
|||||||
"description": "Defines an object-oriented layer for the HTTP specification",
|
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/http-foundation/tree/v6.3.4"
|
"source": "https://github.com/symfony/http-foundation/tree/v6.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -7567,20 +7576,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-22T08:20:46+00:00"
|
"time": "2023-09-04T21:33:54+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-kernel",
|
"name": "symfony/http-kernel",
|
||||||
"version": "v6.3.4",
|
"version": "v6.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/http-kernel.git",
|
"url": "https://github.com/symfony/http-kernel.git",
|
||||||
"reference": "36abb425b4af863ae1fe54d8a8b8b4c76a2bccdb"
|
"reference": "9f991a964368bee8d883e8d57ced4fe9fff04dfc"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/36abb425b4af863ae1fe54d8a8b8b4c76a2bccdb",
|
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f991a964368bee8d883e8d57ced4fe9fff04dfc",
|
||||||
"reference": "36abb425b4af863ae1fe54d8a8b8b4c76a2bccdb",
|
"reference": "9f991a964368bee8d883e8d57ced4fe9fff04dfc",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -7664,7 +7673,7 @@
|
|||||||
"description": "Provides a structured process for converting a Request into a Response",
|
"description": "Provides a structured process for converting a Request into a Response",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/http-kernel/tree/v6.3.4"
|
"source": "https://github.com/symfony/http-kernel/tree/v6.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -7680,20 +7689,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-26T13:54:49+00:00"
|
"time": "2023-09-30T06:37:04+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/mailer",
|
"name": "symfony/mailer",
|
||||||
"version": "v6.3.0",
|
"version": "v6.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/mailer.git",
|
"url": "https://github.com/symfony/mailer.git",
|
||||||
"reference": "7b03d9be1dea29bfec0a6c7b603f5072a4c97435"
|
"reference": "d89611a7830d51b5e118bca38e390dea92f9ea06"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/mailer/zipball/7b03d9be1dea29bfec0a6c7b603f5072a4c97435",
|
"url": "https://api.github.com/repos/symfony/mailer/zipball/d89611a7830d51b5e118bca38e390dea92f9ea06",
|
||||||
"reference": "7b03d9be1dea29bfec0a6c7b603f5072a4c97435",
|
"reference": "d89611a7830d51b5e118bca38e390dea92f9ea06",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -7744,7 +7753,7 @@
|
|||||||
"description": "Helps sending emails",
|
"description": "Helps sending emails",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/mailer/tree/v6.3.0"
|
"source": "https://github.com/symfony/mailer/tree/v6.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -7760,20 +7769,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-05-29T12:49:39+00:00"
|
"time": "2023-09-06T09:47:15+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/mime",
|
"name": "symfony/mime",
|
||||||
"version": "v6.3.3",
|
"version": "v6.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/mime.git",
|
"url": "https://github.com/symfony/mime.git",
|
||||||
"reference": "9a0cbd52baa5ba5a5b1f0cacc59466f194730f98"
|
"reference": "d5179eedf1cb2946dbd760475ebf05c251ef6a6e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/mime/zipball/9a0cbd52baa5ba5a5b1f0cacc59466f194730f98",
|
"url": "https://api.github.com/repos/symfony/mime/zipball/d5179eedf1cb2946dbd760475ebf05c251ef6a6e",
|
||||||
"reference": "9a0cbd52baa5ba5a5b1f0cacc59466f194730f98",
|
"reference": "d5179eedf1cb2946dbd760475ebf05c251ef6a6e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -7828,7 +7837,7 @@
|
|||||||
"mime-type"
|
"mime-type"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/mime/tree/v6.3.3"
|
"source": "https://github.com/symfony/mime/tree/v6.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -7844,7 +7853,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-07-31T07:08:24+00:00"
|
"time": "2023-09-29T06:59:36+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/options-resolver",
|
"name": "symfony/options-resolver",
|
||||||
@@ -8886,16 +8895,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/routing",
|
"name": "symfony/routing",
|
||||||
"version": "v6.3.3",
|
"version": "v6.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/routing.git",
|
"url": "https://github.com/symfony/routing.git",
|
||||||
"reference": "e7243039ab663822ff134fbc46099b5fdfa16f6a"
|
"reference": "82616e59acd3e3d9c916bba798326cb7796d7d31"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/routing/zipball/e7243039ab663822ff134fbc46099b5fdfa16f6a",
|
"url": "https://api.github.com/repos/symfony/routing/zipball/82616e59acd3e3d9c916bba798326cb7796d7d31",
|
||||||
"reference": "e7243039ab663822ff134fbc46099b5fdfa16f6a",
|
"reference": "82616e59acd3e3d9c916bba798326cb7796d7d31",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -8949,7 +8958,7 @@
|
|||||||
"url"
|
"url"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/routing/tree/v6.3.3"
|
"source": "https://github.com/symfony/routing/tree/v6.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -8965,7 +8974,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-07-31T07:08:24+00:00"
|
"time": "2023-09-20T16:05:51+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/service-contracts",
|
"name": "symfony/service-contracts",
|
||||||
@@ -9113,16 +9122,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/string",
|
"name": "symfony/string",
|
||||||
"version": "v6.3.2",
|
"version": "v6.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/string.git",
|
"url": "https://github.com/symfony/string.git",
|
||||||
"reference": "53d1a83225002635bca3482fcbf963001313fb68"
|
"reference": "13d76d0fb049051ed12a04bef4f9de8715bea339"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68",
|
"url": "https://api.github.com/repos/symfony/string/zipball/13d76d0fb049051ed12a04bef4f9de8715bea339",
|
||||||
"reference": "53d1a83225002635bca3482fcbf963001313fb68",
|
"reference": "13d76d0fb049051ed12a04bef4f9de8715bea339",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -9179,7 +9188,7 @@
|
|||||||
"utf8"
|
"utf8"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/string/tree/v6.3.2"
|
"source": "https://github.com/symfony/string/tree/v6.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -9195,7 +9204,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-07-05T08:41:27+00:00"
|
"time": "2023-09-18T10:38:32+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/translation",
|
"name": "symfony/translation",
|
||||||
@@ -9446,16 +9455,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/var-dumper",
|
"name": "symfony/var-dumper",
|
||||||
"version": "v6.3.4",
|
"version": "v6.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/var-dumper.git",
|
"url": "https://github.com/symfony/var-dumper.git",
|
||||||
"reference": "2027be14f8ae8eae999ceadebcda5b4909b81d45"
|
"reference": "3d9999376be5fea8de47752837a3e1d1c5f69ef5"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/2027be14f8ae8eae999ceadebcda5b4909b81d45",
|
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/3d9999376be5fea8de47752837a3e1d1c5f69ef5",
|
||||||
"reference": "2027be14f8ae8eae999ceadebcda5b4909b81d45",
|
"reference": "3d9999376be5fea8de47752837a3e1d1c5f69ef5",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -9510,7 +9519,7 @@
|
|||||||
"dump"
|
"dump"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/var-dumper/tree/v6.3.4"
|
"source": "https://github.com/symfony/var-dumper/tree/v6.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -9526,7 +9535,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-24T14:51:05+00:00"
|
"time": "2023-09-12T10:11:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/yaml",
|
"name": "symfony/yaml",
|
||||||
@@ -10249,16 +10258,16 @@
|
|||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "brianium/paratest",
|
"name": "brianium/paratest",
|
||||||
"version": "v7.2.7",
|
"version": "v7.2.8",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/paratestphp/paratest.git",
|
"url": "https://github.com/paratestphp/paratest.git",
|
||||||
"reference": "1526eb4fd195f65075456dee394d14742ae0a66c"
|
"reference": "882b02d197328138686bb06ce7d8cbb98fc0a16c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/1526eb4fd195f65075456dee394d14742ae0a66c",
|
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/882b02d197328138686bb06ce7d8cbb98fc0a16c",
|
||||||
"reference": "1526eb4fd195f65075456dee394d14742ae0a66c",
|
"reference": "882b02d197328138686bb06ce7d8cbb98fc0a16c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -10328,7 +10337,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/paratestphp/paratest/issues",
|
"issues": "https://github.com/paratestphp/paratest/issues",
|
||||||
"source": "https://github.com/paratestphp/paratest/tree/v7.2.7"
|
"source": "https://github.com/paratestphp/paratest/tree/v7.2.8"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -10340,7 +10349,7 @@
|
|||||||
"type": "paypal"
|
"type": "paypal"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-09-14T14:10:09+00:00"
|
"time": "2023-10-04T13:38:04+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fakerphp/faker",
|
"name": "fakerphp/faker",
|
||||||
@@ -10595,16 +10604,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/dusk",
|
"name": "laravel/dusk",
|
||||||
"version": "v7.11.0",
|
"version": "v7.11.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/dusk.git",
|
"url": "https://github.com/laravel/dusk.git",
|
||||||
"reference": "89ec34a35737303bf3e75f0e8b958d7fcd1cf486"
|
"reference": "076865d1057a4951f796342aa6a8f97a317e7638"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/dusk/zipball/89ec34a35737303bf3e75f0e8b958d7fcd1cf486",
|
"url": "https://api.github.com/repos/laravel/dusk/zipball/076865d1057a4951f796342aa6a8f97a317e7638",
|
||||||
"reference": "89ec34a35737303bf3e75f0e8b958d7fcd1cf486",
|
"reference": "076865d1057a4951f796342aa6a8f97a317e7638",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -10665,9 +10674,9 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/laravel/dusk/issues",
|
"issues": "https://github.com/laravel/dusk/issues",
|
||||||
"source": "https://github.com/laravel/dusk/tree/v7.11.0"
|
"source": "https://github.com/laravel/dusk/tree/v7.11.1"
|
||||||
},
|
},
|
||||||
"time": "2023-09-12T11:13:00+00:00"
|
"time": "2023-09-26T13:23:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/pint",
|
"name": "laravel/pint",
|
||||||
@@ -10974,16 +10983,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pestphp/pest",
|
"name": "pestphp/pest",
|
||||||
"version": "v2.19.2",
|
"version": "v2.20.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pestphp/pest.git",
|
"url": "https://github.com/pestphp/pest.git",
|
||||||
"reference": "6bc9da3fe1154d75a65262618b4a7032f267c04f"
|
"reference": "a8b785f69e44ae3f902cbf08fe6b79359ba46945"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pestphp/pest/zipball/6bc9da3fe1154d75a65262618b4a7032f267c04f",
|
"url": "https://api.github.com/repos/pestphp/pest/zipball/a8b785f69e44ae3f902cbf08fe6b79359ba46945",
|
||||||
"reference": "6bc9da3fe1154d75a65262618b4a7032f267c04f",
|
"reference": "a8b785f69e44ae3f902cbf08fe6b79359ba46945",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -11061,7 +11070,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/pestphp/pest/issues",
|
"issues": "https://github.com/pestphp/pest/issues",
|
||||||
"source": "https://github.com/pestphp/pest/tree/v2.19.2"
|
"source": "https://github.com/pestphp/pest/tree/v2.20.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -11073,7 +11082,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-09-19T10:48:16+00:00"
|
"time": "2023-09-29T18:05:52+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pestphp/pest-plugin",
|
"name": "pestphp/pest-plugin",
|
||||||
@@ -11445,16 +11454,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpstan",
|
"name": "phpstan/phpstan",
|
||||||
"version": "1.10.35",
|
"version": "1.10.37",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpstan/phpstan.git",
|
"url": "https://github.com/phpstan/phpstan.git",
|
||||||
"reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3"
|
"reference": "058ba07e92f744d4dcf6061ae75283d0c6456f2e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e730e5facb75ffe09dfb229795e8c01a459f26c3",
|
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/058ba07e92f744d4dcf6061ae75283d0c6456f2e",
|
||||||
"reference": "e730e5facb75ffe09dfb229795e8c01a459f26c3",
|
"reference": "058ba07e92f744d4dcf6061ae75283d0c6456f2e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -11503,20 +11512,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-09-19T15:27:56+00:00"
|
"time": "2023-10-02T16:18:37+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "10.1.6",
|
"version": "10.1.7",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||||
"reference": "56f33548fe522c8d82da7ff3824b42829d324364"
|
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/56f33548fe522c8d82da7ff3824b42829d324364",
|
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/355324ca4980b8916c18b9db29f3ef484078f26e",
|
||||||
"reference": "56f33548fe522c8d82da7ff3824b42829d324364",
|
"reference": "355324ca4980b8916c18b9db29f3ef484078f26e",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -11573,7 +11582,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.6"
|
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.7"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -11581,7 +11590,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-09-19T04:59:03+00:00"
|
"time": "2023-10-04T15:34:17+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-file-iterator",
|
"name": "phpunit/php-file-iterator",
|
||||||
@@ -12173,16 +12182,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/complexity",
|
"name": "sebastian/complexity",
|
||||||
"version": "3.0.1",
|
"version": "3.1.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/complexity.git",
|
"url": "https://github.com/sebastianbergmann/complexity.git",
|
||||||
"reference": "c70b73893e10757af9c6a48929fa6a333b56a97a"
|
"reference": "68cfb347a44871f01e33ab0ef8215966432f6957"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c70b73893e10757af9c6a48929fa6a333b56a97a",
|
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957",
|
||||||
"reference": "c70b73893e10757af9c6a48929fa6a333b56a97a",
|
"reference": "68cfb347a44871f01e33ab0ef8215966432f6957",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -12195,7 +12204,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-main": "3.0-dev"
|
"dev-main": "3.1-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -12219,7 +12228,7 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
||||||
"security": "https://github.com/sebastianbergmann/complexity/security/policy",
|
"security": "https://github.com/sebastianbergmann/complexity/security/policy",
|
||||||
"source": "https://github.com/sebastianbergmann/complexity/tree/3.0.1"
|
"source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -12227,7 +12236,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-31T09:55:53+00:00"
|
"time": "2023-09-28T11:50:59+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/diff",
|
"name": "sebastian/diff",
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ return [
|
|||||||
'ultimate' => 25,
|
'ultimate' => 25,
|
||||||
],
|
],
|
||||||
'email' => [
|
'email' => [
|
||||||
'zero' => false,
|
'zero' => true,
|
||||||
'self-hosted' => true,
|
'self-hosted' => true,
|
||||||
'basic' => false,
|
'basic' => true,
|
||||||
'pro' => true,
|
'pro' => true,
|
||||||
'ultimate' => true,
|
'ultimate' => true,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.51',
|
'release' => '4.0.0-beta.70',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.51';
|
return '4.0.0-beta.70';
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('applications', function (Blueprint $table) {
|
||||||
|
$table->boolean('health_check_enabled')->default(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('applications', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('health_check_enabled');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('services', function (Blueprint $table) {
|
||||||
|
$table->nullableMorphs('destination');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('services', function (Blueprint $table) {
|
||||||
|
$table->dropMorphs('destination');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('teams', function (Blueprint $table) {
|
||||||
|
$table->boolean('use_instance_email_settings')->default(true)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('teams', function (Blueprint $table) {
|
||||||
|
$table->boolean('use_instance_email_settings')->default(false)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('teams', function (Blueprint $table) {
|
||||||
|
$table->boolean('smtp_notifications_deployments')->default(true)->change();
|
||||||
|
$table->boolean('smtp_notifications_status_changes')->default(true)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('teams', function (Blueprint $table) {
|
||||||
|
$table->boolean('smtp_notifications_deployments')->default(false)->change();
|
||||||
|
$table->boolean('smtp_notifications_status_changes')->default(false)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
31
database/migrations/2023_09_23_111819_add_server_emails.php
Normal file
31
database/migrations/2023_09_23_111819_add_server_emails.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('servers', function (Blueprint $table) {
|
||||||
|
$table->boolean('unreachable_email_sent')->default(false);
|
||||||
|
$table->dropColumn('unreachable_count');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('servers', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('unreachable_email_sent');
|
||||||
|
$table->integer('unreachable_count')->default(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -34,14 +34,14 @@ services:
|
|||||||
POSTGRES_DB: "${DB_DATABASE:-coolify}"
|
POSTGRES_DB: "${DB_DATABASE:-coolify}"
|
||||||
POSTGRES_HOST_AUTH_METHOD: "trust"
|
POSTGRES_HOST_AUTH_METHOD: "trust"
|
||||||
volumes:
|
volumes:
|
||||||
- /data/coolify/_volumes/database/:/var/lib/postgresql/data
|
- coolify-pg-data-dev:/var/lib/postgresql/data
|
||||||
redis:
|
redis:
|
||||||
ports:
|
ports:
|
||||||
- "${FORWARD_REDIS_PORT:-6379}:6379"
|
- "${FORWARD_REDIS_PORT:-6379}:6379"
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
volumes:
|
volumes:
|
||||||
- /data/coolify/_volumes/redis/:/data
|
- coolify-redis-data-dev:/data
|
||||||
vite:
|
vite:
|
||||||
image: node:19
|
image: node:19
|
||||||
working_dir: /var/www/html
|
working_dir: /var/www/html
|
||||||
@@ -56,7 +56,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /:/host
|
- /:/host
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- /data/coolify/:/data/coolify
|
- coolify-data-dev:/data/coolify
|
||||||
mailpit:
|
mailpit:
|
||||||
image: "axllent/mailpit:latest"
|
image: "axllent/mailpit:latest"
|
||||||
container_name: coolify-mail
|
container_name: coolify-mail
|
||||||
@@ -76,6 +76,12 @@ services:
|
|||||||
MINIO_ACCESS_KEY: "${MINIO_ACCESS_KEY:-minioadmin}"
|
MINIO_ACCESS_KEY: "${MINIO_ACCESS_KEY:-minioadmin}"
|
||||||
MINIO_SECRET_KEY: "${MINIO_SECRET_KEY:-minioadmin}"
|
MINIO_SECRET_KEY: "${MINIO_SECRET_KEY:-minioadmin}"
|
||||||
volumes:
|
volumes:
|
||||||
- /data/coolify/_volumes/minio/:/data
|
- coolify-minio-data-dev:/data
|
||||||
networks:
|
networks:
|
||||||
- coolify
|
- coolify
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
coolify-data-dev:
|
||||||
|
coolify-pg-data-dev:
|
||||||
|
coolify-redis-data-dev:
|
||||||
|
coolify-minio-data-dev:
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ ARG DOCKER_COMPOSE_VERSION=2.21.0
|
|||||||
# https://github.com/docker/buildx/releases
|
# https://github.com/docker/buildx/releases
|
||||||
ARG DOCKER_BUILDX_VERSION=0.11.2
|
ARG DOCKER_BUILDX_VERSION=0.11.2
|
||||||
# https://github.com/buildpacks/pack/releases
|
# https://github.com/buildpacks/pack/releases
|
||||||
ARG PACK_VERSION=0.30.0
|
ARG PACK_VERSION=0.31.0
|
||||||
# https://github.com/railwayapp/nixpacks/releases
|
# https://github.com/railwayapp/nixpacks/releases
|
||||||
ARG NIXPACKS_VERSION=1.16.0
|
ARG NIXPACKS_VERSION=1.17.0
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
WORKDIR /artifacts
|
WORKDIR /artifacts
|
||||||
|
|||||||
756
examples/compose/appwrite.yaml
Normal file
756
examples/compose/appwrite.yaml
Normal file
@@ -0,0 +1,756 @@
|
|||||||
|
x-logging: &x-logging
|
||||||
|
logging:
|
||||||
|
driver: 'json-file'
|
||||||
|
options:
|
||||||
|
max-file: '5'
|
||||||
|
max-size: '10m'
|
||||||
|
|
||||||
|
x-image: &x-image
|
||||||
|
image: appwrite/appwrite:1.4.3
|
||||||
|
|
||||||
|
x-image-assistant: &x-image-assistant
|
||||||
|
image: appwrite/assistant:0.2.1
|
||||||
|
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
appwrite:
|
||||||
|
<<: *x-image
|
||||||
|
container_name: appwrite
|
||||||
|
<<: *x-logging
|
||||||
|
labels:
|
||||||
|
- traefik.constraint-label-stack=appwrite
|
||||||
|
- traefik.docker.network=appwrite
|
||||||
|
- traefik.http.services.appwrite_api.loadbalancer.server.port=80
|
||||||
|
#http
|
||||||
|
- traefik.http.routers.appwrite_api_http.entrypoints=web
|
||||||
|
- traefik.http.routers.appwrite_api_http.rule=PathPrefix(`/`)
|
||||||
|
- traefik.http.routers.appwrite_api_http.service=appwrite_api
|
||||||
|
# https
|
||||||
|
- traefik.http.routers.appwrite_api_https.entrypoints=websecure
|
||||||
|
- traefik.http.routers.appwrite_api_https.rule=PathPrefix(`/`)
|
||||||
|
- traefik.http.routers.appwrite_api_https.service=appwrite_api
|
||||||
|
- traefik.http.routers.appwrite_api_https.tls=true
|
||||||
|
volumes:
|
||||||
|
- appwrite-uploads:/storage/uploads:rw
|
||||||
|
- appwrite-cache:/storage/cache:rw
|
||||||
|
- appwrite-config:/storage/config:rw
|
||||||
|
- appwrite-certificates:/storage/certificates:rw
|
||||||
|
- appwrite-functions:/storage/functions:rw
|
||||||
|
depends_on:
|
||||||
|
- mariadb
|
||||||
|
- redis
|
||||||
|
# - clamav
|
||||||
|
- influxdb
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_APPWRITE=/
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_LOCALE
|
||||||
|
- _APP_CONSOLE_WHITELIST_ROOT
|
||||||
|
- _APP_CONSOLE_WHITELIST_EMAILS
|
||||||
|
- _APP_CONSOLE_WHITELIST_IPS
|
||||||
|
- _APP_SYSTEM_EMAIL_NAME
|
||||||
|
- _APP_SYSTEM_EMAIL_ADDRESS
|
||||||
|
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||||
|
- _APP_SYSTEM_RESPONSE_FORMAT
|
||||||
|
- _APP_OPTIONS_ABUSE
|
||||||
|
- _APP_OPTIONS_FORCE_HTTPS
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_DOMAIN
|
||||||
|
- _APP_DOMAIN_TARGET
|
||||||
|
- _APP_DOMAIN_FUNCTIONS
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_SMTP_HOST
|
||||||
|
- _APP_SMTP_PORT
|
||||||
|
- _APP_SMTP_SECURE
|
||||||
|
- _APP_SMTP_USERNAME
|
||||||
|
- _APP_SMTP_PASSWORD
|
||||||
|
- _APP_USAGE_STATS
|
||||||
|
- _APP_INFLUXDB_HOST
|
||||||
|
- _APP_INFLUXDB_PORT
|
||||||
|
- _APP_STORAGE_LIMIT
|
||||||
|
- _APP_STORAGE_PREVIEW_LIMIT
|
||||||
|
- _APP_STORAGE_ANTIVIRUS
|
||||||
|
- _APP_STORAGE_ANTIVIRUS_HOST
|
||||||
|
- _APP_STORAGE_ANTIVIRUS_PORT
|
||||||
|
- _APP_STORAGE_DEVICE
|
||||||
|
- _APP_STORAGE_S3_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_S3_SECRET
|
||||||
|
- _APP_STORAGE_S3_REGION
|
||||||
|
- _APP_STORAGE_S3_BUCKET
|
||||||
|
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_DO_SPACES_SECRET
|
||||||
|
- _APP_STORAGE_DO_SPACES_REGION
|
||||||
|
- _APP_STORAGE_DO_SPACES_BUCKET
|
||||||
|
- _APP_STORAGE_BACKBLAZE_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_BACKBLAZE_SECRET
|
||||||
|
- _APP_STORAGE_BACKBLAZE_REGION
|
||||||
|
- _APP_STORAGE_BACKBLAZE_BUCKET
|
||||||
|
- _APP_STORAGE_LINODE_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_LINODE_SECRET
|
||||||
|
- _APP_STORAGE_LINODE_REGION
|
||||||
|
- _APP_STORAGE_LINODE_BUCKET
|
||||||
|
- _APP_STORAGE_WASABI_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_WASABI_SECRET
|
||||||
|
- _APP_STORAGE_WASABI_REGION
|
||||||
|
- _APP_STORAGE_WASABI_BUCKET
|
||||||
|
- _APP_FUNCTIONS_SIZE_LIMIT
|
||||||
|
- _APP_FUNCTIONS_TIMEOUT
|
||||||
|
- _APP_FUNCTIONS_BUILD_TIMEOUT
|
||||||
|
- _APP_FUNCTIONS_CPUS
|
||||||
|
- _APP_FUNCTIONS_MEMORY
|
||||||
|
- _APP_FUNCTIONS_RUNTIMES
|
||||||
|
- _APP_EXECUTOR_SECRET
|
||||||
|
- _APP_EXECUTOR_HOST
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
- _APP_STATSD_HOST
|
||||||
|
- _APP_STATSD_PORT
|
||||||
|
- _APP_MAINTENANCE_INTERVAL
|
||||||
|
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||||
|
- _APP_MAINTENANCE_RETENTION_CACHE
|
||||||
|
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||||
|
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||||
|
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
|
||||||
|
- _APP_MAINTENANCE_RETENTION_SCHEDULES
|
||||||
|
- _APP_SMS_PROVIDER
|
||||||
|
- _APP_SMS_FROM
|
||||||
|
- _APP_GRAPHQL_MAX_BATCH_SIZE
|
||||||
|
- _APP_GRAPHQL_MAX_COMPLEXITY
|
||||||
|
- _APP_GRAPHQL_MAX_DEPTH
|
||||||
|
- _APP_VCS_GITHUB_APP_NAME
|
||||||
|
- _APP_VCS_GITHUB_PRIVATE_KEY
|
||||||
|
- _APP_VCS_GITHUB_APP_ID
|
||||||
|
- _APP_VCS_GITHUB_WEBHOOK_SECRET
|
||||||
|
- _APP_VCS_GITHUB_CLIENT_SECRET
|
||||||
|
- _APP_VCS_GITHUB_CLIENT_ID
|
||||||
|
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
|
||||||
|
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
|
||||||
|
- _APP_ASSISTANT_OPENAI_API_KEY
|
||||||
|
|
||||||
|
appwrite-realtime:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: realtime
|
||||||
|
container_name: appwrite-realtime
|
||||||
|
<<: *x-logging
|
||||||
|
labels:
|
||||||
|
- "traefik.constraint-label-stack=appwrite"
|
||||||
|
- "traefik.docker.network=appwrite"
|
||||||
|
- "traefik.http.services.appwrite_realtime.loadbalancer.server.port=80"
|
||||||
|
#ws
|
||||||
|
- traefik.http.routers.appwrite_realtime_ws.entrypoints=web
|
||||||
|
- traefik.http.routers.appwrite_realtime_ws.rule=PathPrefix(`/v1/realtime`)
|
||||||
|
- traefik.http.routers.appwrite_realtime_ws.service=appwrite_realtime
|
||||||
|
# wss
|
||||||
|
- traefik.http.routers.appwrite_realtime_wss.entrypoints=websecure
|
||||||
|
- traefik.http.routers.appwrite_realtime_wss.rule=PathPrefix(`/v1/realtime`)
|
||||||
|
- traefik.http.routers.appwrite_realtime_wss.service=appwrite_realtime
|
||||||
|
- traefik.http.routers.appwrite_realtime_wss.tls=true
|
||||||
|
- traefik.http.routers.appwrite_realtime_wss.tls.certresolver=dns
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- mariadb
|
||||||
|
- redis
|
||||||
|
environment:
|
||||||
|
- SERVICE_FQDN_APPWRITE=/v1/realtime
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPTIONS_ABUSE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_USAGE_STATS
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
|
||||||
|
appwrite-worker-audits:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: worker-audits
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-worker-audits
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- mariadb
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
|
||||||
|
appwrite-worker-webhooks:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: worker-webhooks
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-worker-webhooks
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- mariadb
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
|
||||||
|
appwrite-worker-deletes:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: worker-deletes
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-worker-deletes
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- mariadb
|
||||||
|
volumes:
|
||||||
|
- appwrite-uploads:/storage/uploads:rw
|
||||||
|
- appwrite-cache:/storage/cache:rw
|
||||||
|
- appwrite-functions:/storage/functions:rw
|
||||||
|
- appwrite-builds:/storage/builds:rw
|
||||||
|
- appwrite-certificates:/storage/certificates:rw
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_STORAGE_DEVICE
|
||||||
|
- _APP_STORAGE_S3_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_S3_SECRET
|
||||||
|
- _APP_STORAGE_S3_REGION
|
||||||
|
- _APP_STORAGE_S3_BUCKET
|
||||||
|
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_DO_SPACES_SECRET
|
||||||
|
- _APP_STORAGE_DO_SPACES_REGION
|
||||||
|
- _APP_STORAGE_DO_SPACES_BUCKET
|
||||||
|
- _APP_STORAGE_BACKBLAZE_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_BACKBLAZE_SECRET
|
||||||
|
- _APP_STORAGE_BACKBLAZE_REGION
|
||||||
|
- _APP_STORAGE_BACKBLAZE_BUCKET
|
||||||
|
- _APP_STORAGE_LINODE_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_LINODE_SECRET
|
||||||
|
- _APP_STORAGE_LINODE_REGION
|
||||||
|
- _APP_STORAGE_LINODE_BUCKET
|
||||||
|
- _APP_STORAGE_WASABI_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_WASABI_SECRET
|
||||||
|
- _APP_STORAGE_WASABI_REGION
|
||||||
|
- _APP_STORAGE_WASABI_BUCKET
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
- _APP_EXECUTOR_SECRET
|
||||||
|
- _APP_EXECUTOR_HOST
|
||||||
|
|
||||||
|
appwrite-worker-databases:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: worker-databases
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-worker-databases
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- mariadb
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
|
||||||
|
appwrite-worker-builds:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: worker-builds
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-worker-builds
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- mariadb
|
||||||
|
volumes:
|
||||||
|
- appwrite-functions:/storage/functions:rw
|
||||||
|
- appwrite-builds:/storage/builds:rw
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_EXECUTOR_SECRET
|
||||||
|
- _APP_EXECUTOR_HOST
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
- _APP_VCS_GITHUB_APP_NAME
|
||||||
|
- _APP_VCS_GITHUB_PRIVATE_KEY
|
||||||
|
- _APP_VCS_GITHUB_APP_ID
|
||||||
|
- _APP_FUNCTIONS_TIMEOUT
|
||||||
|
- _APP_FUNCTIONS_BUILD_TIMEOUT
|
||||||
|
- _APP_FUNCTIONS_CPUS
|
||||||
|
- _APP_FUNCTIONS_MEMORY
|
||||||
|
- _APP_OPTIONS_FORCE_HTTPS
|
||||||
|
- _APP_DOMAIN
|
||||||
|
- _APP_STORAGE_DEVICE
|
||||||
|
- _APP_STORAGE_S3_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_S3_SECRET
|
||||||
|
- _APP_STORAGE_S3_REGION
|
||||||
|
- _APP_STORAGE_S3_BUCKET
|
||||||
|
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_DO_SPACES_SECRET
|
||||||
|
- _APP_STORAGE_DO_SPACES_REGION
|
||||||
|
- _APP_STORAGE_DO_SPACES_BUCKET
|
||||||
|
- _APP_STORAGE_BACKBLAZE_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_BACKBLAZE_SECRET
|
||||||
|
- _APP_STORAGE_BACKBLAZE_REGION
|
||||||
|
- _APP_STORAGE_BACKBLAZE_BUCKET
|
||||||
|
- _APP_STORAGE_LINODE_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_LINODE_SECRET
|
||||||
|
- _APP_STORAGE_LINODE_REGION
|
||||||
|
- _APP_STORAGE_LINODE_BUCKET
|
||||||
|
- _APP_STORAGE_WASABI_ACCESS_KEY
|
||||||
|
- _APP_STORAGE_WASABI_SECRET
|
||||||
|
- _APP_STORAGE_WASABI_REGION
|
||||||
|
- _APP_STORAGE_WASABI_BUCKET
|
||||||
|
|
||||||
|
appwrite-worker-certificates:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: worker-certificates
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-worker-certificates
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- mariadb
|
||||||
|
volumes:
|
||||||
|
- appwrite-config:/storage/config:rw
|
||||||
|
- appwrite-certificates:/storage/certificates:rw
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_DOMAIN
|
||||||
|
- _APP_DOMAIN_TARGET
|
||||||
|
- _APP_DOMAIN_FUNCTIONS
|
||||||
|
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
|
||||||
|
appwrite-worker-functions:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: worker-functions
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-worker-functions
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- mariadb
|
||||||
|
- openruntimes-executor
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_FUNCTIONS_TIMEOUT
|
||||||
|
- _APP_FUNCTIONS_BUILD_TIMEOUT
|
||||||
|
- _APP_FUNCTIONS_CPUS
|
||||||
|
- _APP_FUNCTIONS_MEMORY
|
||||||
|
- _APP_EXECUTOR_SECRET
|
||||||
|
- _APP_EXECUTOR_HOST
|
||||||
|
- _APP_USAGE_STATS
|
||||||
|
- _APP_DOCKER_HUB_USERNAME
|
||||||
|
- _APP_DOCKER_HUB_PASSWORD
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
|
||||||
|
appwrite-worker-mails:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: worker-mails
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-worker-mails
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_SYSTEM_EMAIL_NAME
|
||||||
|
- _APP_SYSTEM_EMAIL_ADDRESS
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_SMTP_HOST
|
||||||
|
- _APP_SMTP_PORT
|
||||||
|
- _APP_SMTP_SECURE
|
||||||
|
- _APP_SMTP_USERNAME
|
||||||
|
- _APP_SMTP_PASSWORD
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
|
||||||
|
appwrite-worker-messaging:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: worker-messaging
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-worker-messaging
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_SMS_PROVIDER
|
||||||
|
- _APP_SMS_FROM
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
|
||||||
|
appwrite-worker-migrations:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: worker-migrations
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-worker-migrations
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- mariadb
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_DOMAIN
|
||||||
|
- _APP_DOMAIN_TARGET
|
||||||
|
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
|
||||||
|
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
|
||||||
|
|
||||||
|
appwrite-maintenance:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: maintenance
|
||||||
|
<<: *x-logging
|
||||||
|
container_name: appwrite-maintenance
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_DOMAIN
|
||||||
|
- _APP_DOMAIN_TARGET
|
||||||
|
- _APP_DOMAIN_FUNCTIONS
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_MAINTENANCE_INTERVAL
|
||||||
|
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||||
|
- _APP_MAINTENANCE_RETENTION_CACHE
|
||||||
|
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||||
|
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||||
|
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
|
||||||
|
- _APP_MAINTENANCE_RETENTION_SCHEDULES
|
||||||
|
|
||||||
|
appwrite-usage:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: usage
|
||||||
|
container_name: appwrite-usage
|
||||||
|
<<: *x-logging
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- influxdb
|
||||||
|
- mariadb
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
- _APP_INFLUXDB_HOST
|
||||||
|
- _APP_INFLUXDB_PORT
|
||||||
|
- _APP_USAGE_AGGREGATION_INTERVAL
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_USAGE_STATS
|
||||||
|
- _APP_LOGGING_PROVIDER
|
||||||
|
- _APP_LOGGING_CONFIG
|
||||||
|
|
||||||
|
appwrite-schedule:
|
||||||
|
<<: *x-image
|
||||||
|
entrypoint: schedule
|
||||||
|
container_name: appwrite-schedule
|
||||||
|
<<: *x-logging
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
depends_on:
|
||||||
|
- mariadb
|
||||||
|
- redis
|
||||||
|
environment:
|
||||||
|
- _APP_ENV
|
||||||
|
- _APP_WORKER_PER_CORE
|
||||||
|
- _APP_OPENSSL_KEY_V1
|
||||||
|
- _APP_REDIS_HOST
|
||||||
|
- _APP_REDIS_PORT
|
||||||
|
- _APP_REDIS_USER
|
||||||
|
- _APP_REDIS_PASS
|
||||||
|
- _APP_DB_HOST
|
||||||
|
- _APP_DB_PORT
|
||||||
|
- _APP_DB_SCHEMA
|
||||||
|
- _APP_DB_USER
|
||||||
|
- _APP_DB_PASS
|
||||||
|
|
||||||
|
appwrite-assistant:
|
||||||
|
<<: *x-image-assistant
|
||||||
|
container_name: appwrite-assistant
|
||||||
|
<<: *x-logging
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
environment:
|
||||||
|
- _APP_ASSISTANT_OPENAI_API_KEY
|
||||||
|
|
||||||
|
openruntimes-executor:
|
||||||
|
container_name: openruntimes-executor
|
||||||
|
hostname: appwrite-executor
|
||||||
|
<<: *x-logging
|
||||||
|
stop_signal: SIGINT
|
||||||
|
image: openruntimes/executor:0.4.1
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
- runtimes
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- appwrite-builds:/storage/builds:rw
|
||||||
|
- appwrite-functions:/storage/functions:rw
|
||||||
|
# Host mount nessessary to share files between executor and runtimes.
|
||||||
|
# It's not possible to share mount file between 2 containers without host mount (copying is too slow)
|
||||||
|
- /tmp:/tmp:rw
|
||||||
|
environment:
|
||||||
|
- OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_FUNCTIONS_INACTIVE_THRESHOLD
|
||||||
|
- OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_FUNCTIONS_MAINTENANCE_INTERVAL
|
||||||
|
- OPR_EXECUTOR_NETWORK=$_APP_FUNCTIONS_RUNTIMES_NETWORK
|
||||||
|
- OPR_EXECUTOR_DOCKER_HUB_USERNAME=$_APP_DOCKER_HUB_USERNAME
|
||||||
|
- OPR_EXECUTOR_DOCKER_HUB_PASSWORD=$_APP_DOCKER_HUB_PASSWORD
|
||||||
|
- OPR_EXECUTOR_ENV=$_APP_ENV
|
||||||
|
- OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES
|
||||||
|
- OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET
|
||||||
|
- OPR_EXECUTOR_LOGGING_PROVIDER=$_APP_LOGGING_PROVIDER
|
||||||
|
- OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
|
||||||
|
- OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE
|
||||||
|
- OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY
|
||||||
|
- OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET
|
||||||
|
- OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION
|
||||||
|
- OPR_EXECUTOR_STORAGE_S3_BUCKET=$_APP_STORAGE_S3_BUCKET
|
||||||
|
- OPR_EXECUTOR_STORAGE_DO_SPACES_ACCESS_KEY=$_APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||||
|
- OPR_EXECUTOR_STORAGE_DO_SPACES_SECRET=$_APP_STORAGE_DO_SPACES_SECRET
|
||||||
|
- OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION
|
||||||
|
- OPR_EXECUTOR_STORAGE_DO_SPACES_BUCKET=$_APP_STORAGE_DO_SPACES_BUCKET
|
||||||
|
- OPR_EXECUTOR_STORAGE_BACKBLAZE_ACCESS_KEY=$_APP_STORAGE_BACKBLAZE_ACCESS_KEY
|
||||||
|
- OPR_EXECUTOR_STORAGE_BACKBLAZE_SECRET=$_APP_STORAGE_BACKBLAZE_SECRET
|
||||||
|
- OPR_EXECUTOR_STORAGE_BACKBLAZE_REGION=$_APP_STORAGE_BACKBLAZE_REGION
|
||||||
|
- OPR_EXECUTOR_STORAGE_BACKBLAZE_BUCKET=$_APP_STORAGE_BACKBLAZE_BUCKET
|
||||||
|
- OPR_EXECUTOR_STORAGE_LINODE_ACCESS_KEY=$_APP_STORAGE_LINODE_ACCESS_KEY
|
||||||
|
- OPR_EXECUTOR_STORAGE_LINODE_SECRET=$_APP_STORAGE_LINODE_SECRET
|
||||||
|
- OPR_EXECUTOR_STORAGE_LINODE_REGION=$_APP_STORAGE_LINODE_REGION
|
||||||
|
- OPR_EXECUTOR_STORAGE_LINODE_BUCKET=$_APP_STORAGE_LINODE_BUCKET
|
||||||
|
- OPR_EXECUTOR_STORAGE_WASABI_ACCESS_KEY=$_APP_STORAGE_WASABI_ACCESS_KEY
|
||||||
|
- OPR_EXECUTOR_STORAGE_WASABI_SECRET=$_APP_STORAGE_WASABI_SECRET
|
||||||
|
- OPR_EXECUTOR_STORAGE_WASABI_REGION=$_APP_STORAGE_WASABI_REGION
|
||||||
|
- OPR_EXECUTOR_STORAGE_WASABI_BUCKET=$_APP_STORAGE_WASABI_BUCKET
|
||||||
|
|
||||||
|
mariadb:
|
||||||
|
image: mariadb:10.7 # fix issues when upgrading using: mysql_upgrade -u root -p
|
||||||
|
container_name: appwrite-mariadb
|
||||||
|
<<: *x-logging
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
volumes:
|
||||||
|
- appwrite-mariadb:/var/lib/mysql:rw
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
|
||||||
|
- MYSQL_DATABASE=${_APP_DB_SCHEMA}
|
||||||
|
- MYSQL_USER=${_APP_DB_USER}
|
||||||
|
- MYSQL_PASSWORD=${_APP_DB_PASS}
|
||||||
|
command: 'mysqld --innodb-flush-method=fsync'
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7.0.4-alpine
|
||||||
|
container_name: appwrite-redis
|
||||||
|
<<: *x-logging
|
||||||
|
restart: unless-stopped
|
||||||
|
command: >
|
||||||
|
redis-server
|
||||||
|
--maxmemory 512mb
|
||||||
|
--maxmemory-policy allkeys-lru
|
||||||
|
--maxmemory-samples 5
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
volumes:
|
||||||
|
- appwrite-redis:/data:rw
|
||||||
|
|
||||||
|
# clamav:
|
||||||
|
# image: appwrite/clamav:1.2.0
|
||||||
|
# container_name: appwrite-clamav
|
||||||
|
# restart: unless-stopped
|
||||||
|
# networks:
|
||||||
|
# - appwrite
|
||||||
|
# volumes:
|
||||||
|
# - appwrite-uploads:/storage/uploads
|
||||||
|
|
||||||
|
influxdb:
|
||||||
|
image: appwrite/influxdb:1.5.0
|
||||||
|
container_name: appwrite-influxdb
|
||||||
|
<<: *x-logging
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
volumes:
|
||||||
|
- appwrite-influxdb:/var/lib/influxdb:rw
|
||||||
|
|
||||||
|
telegraf:
|
||||||
|
image: appwrite/telegraf:1.4.0
|
||||||
|
container_name: appwrite-telegraf
|
||||||
|
<<: *x-logging
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- appwrite
|
||||||
|
environment:
|
||||||
|
- _APP_INFLUXDB_HOST
|
||||||
|
- _APP_INFLUXDB_PORT
|
||||||
|
|
||||||
|
networks:
|
||||||
|
gateway:
|
||||||
|
name: gateway
|
||||||
|
appwrite:
|
||||||
|
name: appwrite
|
||||||
|
runtimes:
|
||||||
|
name: runtimes
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
appwrite-mariadb:
|
||||||
|
appwrite-redis:
|
||||||
|
appwrite-cache:
|
||||||
|
appwrite-uploads:
|
||||||
|
appwrite-certificates:
|
||||||
|
appwrite-functions:
|
||||||
|
appwrite-builds:
|
||||||
|
appwrite-influxdb:
|
||||||
|
appwrite-config:
|
||||||
@@ -11,7 +11,8 @@ services:
|
|||||||
- database__connection__password=$SERVICE_PASSWORD_MYSQL
|
- database__connection__password=$SERVICE_PASSWORD_MYSQL
|
||||||
- database__connection__database=${MYSQL_DATABASE-ghost}
|
- database__connection__database=${MYSQL_DATABASE-ghost}
|
||||||
depends_on:
|
depends_on:
|
||||||
- mysql
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:8.0
|
image: mysql:8.0
|
||||||
volumes:
|
volumes:
|
||||||
@@ -20,4 +21,9 @@ services:
|
|||||||
- MYSQL_USER=${SERVICE_USER_MYSQL}
|
- MYSQL_USER=${SERVICE_USER_MYSQL}
|
||||||
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
||||||
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
||||||
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQL_ROOT}
|
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQLROOT}
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
16
examples/compose/minio.yaml
Normal file
16
examples/compose/minio.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
services:
|
||||||
|
minio:
|
||||||
|
image: quay.io/minio/minio:RELEASE.2023-09-30T07-02-29Z
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
environment:
|
||||||
|
SERVICE_FQDN_MINIO_9000:
|
||||||
|
SERVICE_FQDN_CONSOLE_9001:
|
||||||
|
MINIO_ROOT_USER: $SERVICE_USER_MINIO
|
||||||
|
MINIO_ROOT_PASSWORD: $SERVICE_PASSWORD_MINIO
|
||||||
|
volumes:
|
||||||
|
- minio-data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
@@ -20,5 +20,5 @@
|
|||||||
"input.code": "One-time code",
|
"input.code": "One-time code",
|
||||||
"input.recovery_code": "Recovery code",
|
"input.recovery_code": "Recovery code",
|
||||||
"button.save": "Save",
|
"button.save": "Save",
|
||||||
"repository.url": "<span class='text-helper'>Examples</span><br>https://github.com/coollabsio/coolify-examples <span class='text-helper'>main</span> branch will be selected<br><br>https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify <span class='text-helper'>nodejs-fastify</span> branch will be selected"
|
"repository.url": "<span class='text-helper'>Examples</span><br>For Public repositories, use <span class='text-helper'>https://...</span>.<br>For Private repositories, use <span class='text-helper'>git@...</span>.<br><br>https://github.com/coollabsio/coolify-examples <span class='text-helper'>main</span> branch will be selected<br>https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify <span class='text-helper'>nodejs-fastify</span> branch will be selected.<br>https://gitea.com/sedlav/expressjs.git <span class='text-helper'>main</span> branch will be selected.<br>https://gitlab.com/andrasbacsai/nodejs-example.git <span class='text-helper'>main</span> branch will be selected."
|
||||||
}
|
}
|
||||||
@@ -55,6 +55,9 @@ a {
|
|||||||
.box {
|
.box {
|
||||||
@apply flex items-center p-2 transition-colors cursor-pointer min-h-16 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white hover:no-underline min-w-[24rem];
|
@apply flex items-center p-2 transition-colors cursor-pointer min-h-16 bg-coolgray-200 hover:bg-coollabs-100 hover:text-white hover:no-underline min-w-[24rem];
|
||||||
}
|
}
|
||||||
|
.box-without-bg {
|
||||||
|
@apply flex items-center p-2 transition-colors min-h-16 hover:text-white hover:no-underline min-w-[24rem];
|
||||||
|
}
|
||||||
|
|
||||||
.lds-heart {
|
.lds-heart {
|
||||||
animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
|
animation: lds-heart 1.2s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||||
|
|||||||
@@ -7,6 +7,10 @@
|
|||||||
href="{{ route('project.application.deployments', $parameters) }}">
|
href="{{ route('project.application.deployments', $parameters) }}">
|
||||||
<button>Deployments</button>
|
<button>Deployments</button>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="{{ request()->routeIs('project.application.logs') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('project.application.logs', $parameters) }}">
|
||||||
|
<button>Logs</button>
|
||||||
|
</a>
|
||||||
<x-applications.links :application="$application" />
|
<x-applications.links :application="$application" />
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
<x-applications.advanced :application="$application" />
|
<x-applications.advanced :application="$application" />
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
href="{{ route('project.database.configuration', $parameters) }}">
|
href="{{ route('project.database.configuration', $parameters) }}">
|
||||||
<button>Configuration</button>
|
<button>Configuration</button>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="{{ request()->routeIs('project.database.logs') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('project.database.logs', $parameters) }}">
|
||||||
|
<button>Logs</button>
|
||||||
|
</a>
|
||||||
<a class="{{ request()->routeIs('project.database.backups.all') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('project.database.backups.all') ? 'text-white' : '' }}"
|
||||||
href="{{ route('project.database.backups.all', $parameters) }}">
|
href="{{ route('project.database.backups.all', $parameters) }}">
|
||||||
<button>Backups</button>
|
<button>Backups</button>
|
||||||
|
|||||||
@@ -3,4 +3,4 @@
|
|||||||
Thank you,<br>
|
Thank you,<br>
|
||||||
{{ config('app.name') ?? 'Coolify' }}
|
{{ config('app.name') ?? 'Coolify' }}
|
||||||
|
|
||||||
{{ Illuminate\Mail\Markdown::parse('[Contact Support](https://docs.coollabs.io/contact)') }}
|
{{ Illuminate\Mail\Markdown::parse('[Contact Support](https://coolify.io/docs/contact)') }}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||||
clip-rule="evenodd" />
|
clip-rule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
1 server <x-helper helper="Bring Your Own Server. All you need is n SSH connection." />
|
1 server <x-helper helper="Bring Your Own Server." />
|
||||||
</li>
|
</li>
|
||||||
<li class="flex gap-x-3">
|
<li class="flex gap-x-3">
|
||||||
<svg class="flex-none w-5 h-6 text-warning" viewBox="0 0 20 20" fill="currentColor"
|
<svg class="flex-none w-5 h-6 text-warning" viewBox="0 0 20 20" fill="currentColor"
|
||||||
@@ -90,7 +90,16 @@
|
|||||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||||
clip-rule="evenodd" />
|
clip-rule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
Basic Support
|
Included Email System
|
||||||
|
</li>
|
||||||
|
<li class="flex gap-x-3">
|
||||||
|
<svg class="flex-none w-5 h-6 text-warning" viewBox="0 0 20 20" fill="currentColor"
|
||||||
|
aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd"
|
||||||
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||||
|
clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
Email Support
|
||||||
</li>
|
</li>
|
||||||
<li class="flex font-bold text-white gap-x-3">
|
<li class="flex font-bold text-white gap-x-3">
|
||||||
<svg width="512" height="512" class="flex-none w-5 h-6 text-green-600"
|
<svg width="512" height="512" class="flex-none w-5 h-6 text-green-600"
|
||||||
@@ -139,7 +148,7 @@
|
|||||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||||
clip-rule="evenodd" />
|
clip-rule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
10 servers <x-helper helper="Bring Your Own Server. All you need is n SSH connection." />
|
10 servers <x-helper helper="Bring Your Own Server." />
|
||||||
</li>
|
</li>
|
||||||
<li class="flex gap-x-3">
|
<li class="flex gap-x-3">
|
||||||
<svg class="flex-none w-5 h-6 text-warning" viewBox="0 0 20 20" fill="currentColor"
|
<svg class="flex-none w-5 h-6 text-warning" viewBox="0 0 20 20" fill="currentColor"
|
||||||
@@ -157,7 +166,7 @@
|
|||||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||||
clip-rule="evenodd" />
|
clip-rule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
Email Support
|
Priority Email Support
|
||||||
</li>
|
</li>
|
||||||
<li class="flex font-bold text-white gap-x-3">
|
<li class="flex font-bold text-white gap-x-3">
|
||||||
<svg width="512" height="512" class="flex-none w-5 h-6 text-green-600"
|
<svg width="512" height="512" class="flex-none w-5 h-6 text-green-600"
|
||||||
@@ -206,7 +215,7 @@
|
|||||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
|
||||||
clip-rule="evenodd" />
|
clip-rule="evenodd" />
|
||||||
</svg>
|
</svg>
|
||||||
? servers <x-helper helper="Bring Your Own Server. All you need is n SSH connection." />
|
? servers <x-helper helper="Bring Your Own Server." />
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="flex gap-x-3">
|
<li class="flex gap-x-3">
|
||||||
|
|||||||
@@ -8,25 +8,25 @@
|
|||||||
<nav class="navbar-main">
|
<nav class="navbar-main">
|
||||||
<a class="{{ request()->routeIs('server.show') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('server.show') ? 'text-white' : '' }}"
|
||||||
href="{{ route('server.show', [
|
href="{{ route('server.show', [
|
||||||
'server_uuid' => Route::current()->parameters()['server_uuid'],
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
]) }}">
|
]) }}">
|
||||||
<button>General</button>
|
<button>General</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('server.private-key') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('server.private-key') ? 'text-white' : '' }}"
|
||||||
href="{{ route('server.private-key', [
|
href="{{ route('server.private-key', [
|
||||||
'server_uuid' => Route::current()->parameters()['server_uuid'],
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
]) }}">
|
]) }}">
|
||||||
<button>Private Key</button>
|
<button>Private Key</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('server.proxy') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('server.proxy') ? 'text-white' : '' }}"
|
||||||
href="{{ route('server.proxy', [
|
href="{{ route('server.proxy', [
|
||||||
'server_uuid' => Route::current()->parameters()['server_uuid'],
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
]) }}">
|
]) }}">
|
||||||
<button>Proxy</button>
|
<button>Proxy</button>
|
||||||
</a>
|
</a>
|
||||||
<a class="{{ request()->routeIs('server.destinations') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('server.destinations') ? 'text-white' : '' }}"
|
||||||
href="{{ route('server.destinations', [
|
href="{{ route('server.destinations', [
|
||||||
'server_uuid' => Route::current()->parameters()['server_uuid'],
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
]) }}">
|
]) }}">
|
||||||
<button>Destinations</button>
|
<button>Destinations</button>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
<div class="navbar-main">
|
<div class="navbar-main">
|
||||||
|
<a class="{{ request()->routeIs('project.service') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('project.service', $parameters) }}">
|
||||||
|
<button>Configuration</button>
|
||||||
|
</a>
|
||||||
<x-services.links :service="$service" />
|
<x-services.links :service="$service" />
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
@if (serviceStatus($service) === 'degraded')
|
@if (serviceStatus($service) === 'degraded')
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-20 hover:opacity-100 hover:text-white z-50']) }}
|
<a {{ $attributes->merge(['class' => 'text-xs cursor-pointer opacity-60 hover:opacity-100 hover:text-white z-50']) }}
|
||||||
href="https://github.com/coollabsio/coolify/releases/tag/v{{ config('version') }}">v{{ config('version') }}</a>
|
href="https://github.com/coollabsio/coolify/releases/tag/v{{ config('version') }}">v{{ config('version') }}</a>
|
||||||
|
|||||||
@@ -5,10 +5,6 @@ Container ({{ $containerName }}) has been restarted automatically on {{$serverNa
|
|||||||
@if ($containerName === 'coolify-proxy')
|
@if ($containerName === 'coolify-proxy')
|
||||||
Coolify Proxy should run on your server as you have FQDNs set up in one of your resources.
|
Coolify Proxy should run on your server as you have FQDNs set up in one of your resources.
|
||||||
|
|
||||||
Note: The proxy should not stop unexpectedly, so please check what is going on your server.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
If you don't want to use Coolify Proxy, please remove FQDN from your resources or set Proxy type to Custom(None).
|
If you don't want to use Coolify Proxy, please remove FQDN from your resources or set Proxy type to Custom(None).
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Coolify cannot connect to your server ({{$name}}). Please check your server and
|
|||||||
|
|
||||||
All automations & integrations are turned off!
|
All automations & integrations are turned off!
|
||||||
|
|
||||||
IMPORTANT: You have to validate your server again after you fix the issue.
|
IMPORTANT: We automatically try to revive your server. If your server is back online, we will automatically turn on all automations & integrations.
|
||||||
|
|
||||||
If you have any questions, please contact us.
|
If you have any questions, please contact us.
|
||||||
|
|
||||||
|
|||||||
6
resources/views/emails/server-revived.blade.php
Normal file
6
resources/views/emails/server-revived.blade.php
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<x-emails.layout>
|
||||||
|
|
||||||
|
Your server ({{$name}}) was offline for a while, but it is back online now. All automations & integrations are turned on again.
|
||||||
|
|
||||||
|
</x-emails.layout>
|
||||||
|
|
||||||
13
resources/views/livewire/dev/compose.blade.php
Normal file
13
resources/views/livewire/dev/compose.blade.php
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<div class="pb-10" x-data>
|
||||||
|
<h1>Compose</h1>
|
||||||
|
<div>All kinds of compose files.</div>
|
||||||
|
<h3 class="pt-4">Services</h3>
|
||||||
|
@foreach ($services as $serviceName => $value)
|
||||||
|
<x-forms.button wire:click="setService('{{ $serviceName }}')">{{ Str::headline($serviceName) }}</x-forms.button>
|
||||||
|
@endforeach
|
||||||
|
<h3 class="pt-4">Base64 En/Decode</h3>
|
||||||
|
<x-forms.button x-on:click="copyToClipboard('{{ $base64 }}')">Copy Base64 Compose</x-forms.button>
|
||||||
|
<div class="pt-4">
|
||||||
|
<x-forms.textarea realtimeValidation rows="40" id="compose"></x-forms.textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -22,29 +22,15 @@
|
|||||||
@if (data_get($team, 'discord_enabled'))
|
@if (data_get($team, 'discord_enabled'))
|
||||||
<h2 class="mt-4">Subscribe to events</h2>
|
<h2 class="mt-4">Subscribe to events</h2>
|
||||||
<div class="w-64">
|
<div class="w-64">
|
||||||
|
|
||||||
|
|
||||||
@if (isDev())
|
@if (isDev())
|
||||||
<h3 class="mt-4">Test</h3>
|
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_test" label="Test" />
|
||||||
<div class="flex items-end gap-10">
|
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_test" label="Enabled" />
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
<h3 class="mt-4">Container Status Changes</h3>
|
|
||||||
<div class="flex items-end gap-10">
|
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_status_changes"
|
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_status_changes"
|
||||||
label="Enabled" />
|
label="Container Status Changes" />
|
||||||
</div>
|
|
||||||
<h3 class="mt-4">Application Deployments</h3>
|
|
||||||
<div class="flex items-end gap-10">
|
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_deployments"
|
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_deployments"
|
||||||
label="Enabled" />
|
label="Application Deployments" />
|
||||||
</div>
|
|
||||||
<h3 class="mt-4">Backup Status</h3>
|
|
||||||
<div class="flex items-end gap-10">
|
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_database_backups"
|
<x-forms.checkbox instantSave="saveModel" id="team.discord_notifications_database_backups"
|
||||||
label="Enabled" />
|
label="Backup Status" />
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
@endif
|
@endif
|
||||||
@if (isEmailEnabled($team) &&
|
@if (isEmailEnabled($team) &&
|
||||||
auth()->user()->isAdminFromSession())
|
auth()->user()->isAdminFromSession() &&
|
||||||
|
isTestEmailEnabled($team))
|
||||||
<x-forms.button onclick="sendTestEmail.showModal()"
|
<x-forms.button onclick="sendTestEmail.showModal()"
|
||||||
class="text-white normal-case btn btn-xs no-animation btn-primary">
|
class="text-white normal-case btn btn-xs no-animation btn-primary">
|
||||||
Send Test Email
|
Send Test Email
|
||||||
@@ -31,15 +32,22 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@if (isCloud())
|
||||||
@if ($this->sharedEmailEnabled)
|
@if ($this->sharedEmailEnabled)
|
||||||
<div class="w-64 pb-4">
|
<div class="w-64 pb-4">
|
||||||
<x-forms.checkbox instantSave="instantSaveInstance" id="team.use_instance_email_settings"
|
<x-forms.checkbox instantSave="instantSaveInstance" id="team.use_instance_email_settings"
|
||||||
label="Use hosted email service" />
|
label="Use Hosted Email Service" />
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div class="pb-4 w-96">
|
<div class="pb-4 w-96">
|
||||||
<x-forms.checkbox disabled id="team.use_instance_email_settings"
|
<x-forms.checkbox disabled id="team.use_instance_email_settings"
|
||||||
label="Use hosted email service (Pro+ subscription required)" />
|
label="Use Hosted Email Service (Pro+ subscription required)" />
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@else
|
||||||
|
<div class="pb-4 w-96">
|
||||||
|
<x-forms.checkbox instantSave="instantSaveInstance" id="team.use_instance_email_settings"
|
||||||
|
label="Use system wide (transactional) email settings" />
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
@if (!$team->use_instance_email_settings)
|
@if (!$team->use_instance_email_settings)
|
||||||
@@ -104,24 +112,14 @@
|
|||||||
<h2 class="mt-4">Subscribe to events</h2>
|
<h2 class="mt-4">Subscribe to events</h2>
|
||||||
<div class="w-64">
|
<div class="w-64">
|
||||||
@if (isDev())
|
@if (isDev())
|
||||||
<h3 class="mt-4">Test</h3>
|
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_test" label="Test" />
|
||||||
<div class="flex items-end gap-10">
|
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_test" label="Enabled" />
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
<h3 class="mt-4">Container Status Changes</h3>
|
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_status_changes"
|
||||||
<div class="flex items-end gap-10">
|
label="Container Status Changes" />
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_status_changes" label="Enabled" />
|
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_deployments"
|
||||||
</div>
|
label="Application Deployments" />
|
||||||
<h3 class="mt-4">Application Deployments</h3>
|
|
||||||
<div class="flex items-end gap-10">
|
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_deployments" label="Enabled" />
|
|
||||||
</div>
|
|
||||||
<h3 class="mt-4">Backup Status</h3>
|
|
||||||
<div class="flex items-end gap-10">
|
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_database_backups"
|
<x-forms.checkbox instantSave="saveModel" id="team.smtp_notifications_database_backups"
|
||||||
label="Enabled" />
|
label="Backup Status" />
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -27,34 +27,30 @@
|
|||||||
<h2 class="mt-4">Subscribe to events</h2>
|
<h2 class="mt-4">Subscribe to events</h2>
|
||||||
<div class="w-96">
|
<div class="w-96">
|
||||||
@if (isDev())
|
@if (isDev())
|
||||||
<h3 class="mt-4">Test</h3>
|
<div class="w-64">
|
||||||
<div class="flex items-end gap-10">
|
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_test" label="Test" />
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_test" label="Enabled" />
|
|
||||||
<x-forms.input
|
<x-forms.input
|
||||||
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
||||||
id="team.telegram_notifications_test_message_thread_id" label="Custom Topic ID" />
|
id="team.telegram_notifications_test_message_thread_id" label="Custom Topic ID" />
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
<h3 class="mt-4">Container Status Changes</h3>
|
<div class="w-64">
|
||||||
<div class="flex items-end gap-10">
|
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_status_changes"
|
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_status_changes"
|
||||||
label="Enabled" />
|
label="Container Status Changes" />
|
||||||
<x-forms.input
|
<x-forms.input
|
||||||
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
||||||
id="team.telegram_notifications_status_changes_message_thread_id" label="Custom Topic ID" />
|
id="team.telegram_notifications_status_changes_message_thread_id" label="Custom Topic ID" />
|
||||||
</div>
|
</div>
|
||||||
<h3 class="mt-4">Application Deployments</h3>
|
<div class="w-64">
|
||||||
<div class="flex items-end gap-10">
|
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_deployments"
|
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_deployments"
|
||||||
label="Enabled" />
|
label="Application Deployments" />
|
||||||
<x-forms.input
|
<x-forms.input
|
||||||
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
||||||
id="team.telegram_notifications_deployments_message_thread_id" label="Custom Topic ID" />
|
id="team.telegram_notifications_deployments_message_thread_id" label="Custom Topic ID" />
|
||||||
</div>
|
</div>
|
||||||
<h3 class="mt-4">Backup Status</h3>
|
<div class="w-64">
|
||||||
<div class="flex items-end gap-10">
|
|
||||||
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_database_backups"
|
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_database_backups"
|
||||||
label="Enabled" />
|
label="Backup Status" />
|
||||||
<x-forms.input
|
<x-forms.input
|
||||||
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
|
||||||
id="team.telegram_notifications_database_backups_message_thread_id" label="Custom Topic ID" />
|
id="team.telegram_notifications_database_backups_message_thread_id" label="Custom Topic ID" />
|
||||||
|
|||||||
@@ -19,38 +19,50 @@
|
|||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
@if (!$application->dockerfile)
|
@if (!$application->dockerfile)
|
||||||
<div class="flex items-end gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
|
<div class="flex gap-2">
|
||||||
<x-forms.select id="application.build_pack" label="Build Pack" required>
|
<x-forms.select id="application.build_pack" label="Build Pack" required>
|
||||||
<option value="nixpacks">Nixpacks</option>
|
<option value="nixpacks">Nixpacks</option>
|
||||||
<option value="dockerfile">Dockerfile</option>
|
<option value="dockerfile">Dockerfile</option>
|
||||||
</x-forms.select>
|
</x-forms.select>
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@if ($application->settings->is_static)
|
@if ($application->settings->is_static)
|
||||||
<x-forms.select id="application.static_image" label="Static Image" required>
|
<x-forms.select id="application.static_image" label="Static Image" required>
|
||||||
<option value="nginx:alpine">nginx:alpine</option>
|
<option value="nginx:alpine">nginx:alpine</option>
|
||||||
<option disabled value="apache:alpine">apache:alpine</option>
|
<option disabled value="apache:alpine">apache:alpine</option>
|
||||||
</x-forms.select>
|
</x-forms.select>
|
||||||
@endif
|
@endif
|
||||||
|
</div>
|
||||||
@if ($application->could_set_build_commands())
|
@if ($application->could_set_build_commands())
|
||||||
|
<div class="w-64">
|
||||||
|
<x-forms.checkbox instantSave id="is_static" label="Is it a static site?"
|
||||||
|
helper="If your application is a static site or the final build assets should be served as a static site, enable this." />
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<h3>Build</h3>
|
<h3>Build</h3>
|
||||||
|
@if ($application->could_set_build_commands())
|
||||||
<div class="flex flex-col gap-2 xl:flex-row">
|
<div class="flex flex-col gap-2 xl:flex-row">
|
||||||
<x-forms.input placeholder="pnpm install" id="application.install_command"
|
<x-forms.input placeholder="pnpm install" id="application.install_command"
|
||||||
label="Install Command" />
|
label="Install Command" />
|
||||||
<x-forms.input placeholder="pnpm build" id="application.build_command" label="Build Command" />
|
<x-forms.input placeholder="pnpm build" id="application.build_command" label="Build Command" />
|
||||||
<x-forms.input placeholder="pnpm start" id="application.start_command" label="Start Command" />
|
<x-forms.input placeholder="pnpm start" id="application.start_command" label="Start Command" />
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 xl:flex-row">
|
<div class="flex flex-col gap-2 xl:flex-row">
|
||||||
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
|
<x-forms.input placeholder="/" id="application.base_directory" label="Base Directory"
|
||||||
helper="Directory to use as root. Useful for monorepos. WIP" disabled />
|
helper="Directory to use as root. Useful for monorepos." />
|
||||||
|
@if ($application->could_set_build_commands())
|
||||||
@if ($application->settings->is_static)
|
@if ($application->settings->is_static)
|
||||||
<x-forms.input placeholder="/dist" id="application.publish_directory" label="Publish Directory"
|
<x-forms.input placeholder="/dist" id="application.publish_directory" label="Publish Directory"
|
||||||
required />
|
required />
|
||||||
@else
|
@else
|
||||||
<x-forms.input placeholder="/" id="application.publish_directory" label="Publish Directory" />
|
<x-forms.input placeholder="/" id="application.publish_directory" label="Publish Directory" />
|
||||||
@endif
|
@endif
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
|
</div>
|
||||||
@if ($application->dockerfile)
|
@if ($application->dockerfile)
|
||||||
<x-forms.textarea label="Dockerfile" id="application.dockerfile" rows="6"> </x-forms.textarea>
|
<x-forms.textarea label="Dockerfile" id="application.dockerfile" rows="6"> </x-forms.textarea>
|
||||||
@endif
|
@endif
|
||||||
@@ -69,10 +81,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<h3>Advanced</h3>
|
<h3>Advanced</h3>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
@if ($application->could_set_build_commands())
|
|
||||||
<x-forms.checkbox instantSave id="is_static" label="Is it a static site?"
|
|
||||||
helper="If your application is a static site or the final build assets should be served as a static site, enable this." />
|
|
||||||
@endif
|
|
||||||
<x-forms.checkbox
|
<x-forms.checkbox
|
||||||
helper="Your application will be available only on https if your domain starts with https://..."
|
helper="Your application will be available only on https if your domain starts with https://..."
|
||||||
instantSave id="is_force_https_enabled" label="Force Https" />
|
instantSave id="is_force_https_enabled" label="Force Https" />
|
||||||
|
|||||||
@@ -54,11 +54,11 @@
|
|||||||
<div class="flex flex-col p-4 bg-coolgray-200">
|
<div class="flex flex-col p-4 bg-coolgray-200">
|
||||||
<div class="flex gap-2">PR #{{ data_get($preview, 'pull_request_id') }} |
|
<div class="flex gap-2">PR #{{ data_get($preview, 'pull_request_id') }} |
|
||||||
@if (Str::of(data_get($preview, 'status'))->startsWith('running'))
|
@if (Str::of(data_get($preview, 'status'))->startsWith('running'))
|
||||||
<x-status.running :status="$status" />
|
<x-status.running :status="data_get($preview, 'status')" />
|
||||||
@elseif(Str::of(data_get($preview, 'status'))->startsWith('restarting'))
|
@elseif(Str::of(data_get($preview, 'status'))->startsWith('restarting'))
|
||||||
<x-status.restarting :status="$status" />
|
<x-status.restarting :status="data_get($preview, 'status')" />
|
||||||
@else
|
@else
|
||||||
<x-status.stopped :status="$status" />
|
<x-status.stopped :status="data_get($preview, 'status')" />
|
||||||
@endif
|
@endif
|
||||||
@if (data_get($preview, 'status') !== 'exited')
|
@if (data_get($preview, 'status') !== 'exited')
|
||||||
| <a target="_blank" href="{{ data_get($preview, 'fqdn') }}">Open Preview
|
| <a target="_blank" href="{{ data_get($preview, 'fqdn') }}">Open Preview
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<x-external-link />
|
<x-external-link />
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</a>
|
</a>
|
||||||
@if (!$application->source->is_public)
|
@if (data_get($application, 'source.is_public') === false)
|
||||||
<a target="_blank" class="hover:no-underline" href="{{ get_installation_path($application->source) }}">
|
<a target="_blank" class="hover:no-underline" href="{{ get_installation_path($application->source) }}">
|
||||||
<x-forms.button>
|
<x-forms.button>
|
||||||
Open Git App
|
Open Git App
|
||||||
|
|||||||
@@ -26,27 +26,29 @@
|
|||||||
<x-forms.input label="Image" id="database.image" required
|
<x-forms.input label="Image" id="database.image" required
|
||||||
helper="For all available images, check here:<br><br><a target='_blank' href='https://hub.docker.com/_/postgres'>https://hub.docker.com/_/postgres</a>" />
|
helper="For all available images, check here:<br><br><a target='_blank' href='https://hub.docker.com/_/postgres'>https://hub.docker.com/_/postgres</a>" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
|
||||||
@if ($database->started_at)
|
@if ($database->started_at)
|
||||||
<x-forms.input label="Username" id="database.postgres_username" placeholder="If empty: postgres"
|
|
||||||
readonly helper="You can only modify it before the initial start." />
|
|
||||||
<x-forms.input label="Password" id="database.postgres_password" type="password" required readonly
|
|
||||||
helper="You can only modify it before the initial start." />
|
|
||||||
<x-forms.input label="Database" id="database.postgres_db"
|
|
||||||
placeholder="If empty, it will be the same as Username." readonly
|
|
||||||
helper="You can only modify it before the initial start." />
|
|
||||||
@else
|
|
||||||
<x-forms.input label="Username" id="database.postgres_user" placeholder="If empty: postgres"
|
|
||||||
helper="You can only modify it before the initial start." />
|
|
||||||
<x-forms.input label="Password" id="database.postgres_password" type="password" required
|
|
||||||
helper="You can only modify it before the initial start." />
|
|
||||||
<x-forms.input label="Database" id="database.postgres_db"
|
|
||||||
placeholder="If empty, it will be the same as Username."
|
|
||||||
helper="You can only modify it before the initial start." />
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<x-forms.input label="Initial Arguments" id="database.postgres_initdb_args"
|
<x-forms.input label="Initial Username" id="database.postgres_username" placeholder="If empty: postgres"
|
||||||
|
readonly helper="You can only change this in the database." />
|
||||||
|
<x-forms.input label="Initial Password" id="database.postgres_password" type="password" required readonly
|
||||||
|
helper="You can only change this in the database." />
|
||||||
|
<x-forms.input label="Initial Database" id="database.postgres_db"
|
||||||
|
placeholder="If empty, it will be the same as Username." readonly
|
||||||
|
helper="You can only change this in the database." />
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<div class="pt-8 text-warning">Please verify these values. You can only modify them before the initial start. After that, you need to modify it in the database.
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2 pb-8">
|
||||||
|
<x-forms.input label="Username" id="database.postgres_user" placeholder="If empty: postgres" />
|
||||||
|
<x-forms.input label="Password" id="database.postgres_password" type="password" required />
|
||||||
|
<x-forms.input label="Database" id="database.postgres_db"
|
||||||
|
placeholder="If empty, it will be the same as Username." />
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<x-forms.input label="Initial Database Arguments" id="database.postgres_initdb_args"
|
||||||
placeholder="If empty, use default. See in docker docs." />
|
placeholder="If empty, use default. See in docker docs." />
|
||||||
<x-forms.input label="Host Auth Method" id="database.postgres_host_auth_method"
|
<x-forms.input label="Host Auth Method" id="database.postgres_host_auth_method"
|
||||||
placeholder="If empty, use default. See in docker docs." />
|
placeholder="If empty, use default. See in docker docs." />
|
||||||
@@ -56,7 +58,8 @@
|
|||||||
<div class="flex items-end gap-2">
|
<div class="flex items-end gap-2">
|
||||||
<x-forms.input placeholder="3000:5432" id="database.ports_mappings" label="Ports Mappings"
|
<x-forms.input placeholder="3000:5432" id="database.ports_mappings" label="Ports Mappings"
|
||||||
helper="A comma separated list of ports you would like to map to the host system.<br><span class='inline-block font-bold text-warning'>Example</span>3000:5432,3002:5433" />
|
helper="A comma separated list of ports you would like to map to the host system.<br><span class='inline-block font-bold text-warning'>Example</span>3000:5432,3002:5433" />
|
||||||
<x-forms.input placeholder="5432" disabled="{{$database->is_public}}" id="database.public_port" label="Public Port" />
|
<x-forms.input placeholder="5432" disabled="{{ $database->is_public }}" id="database.public_port"
|
||||||
|
label="Public Port" />
|
||||||
<x-forms.checkbox instantSave id="database.is_public" label="Accessible over the internet" />
|
<x-forms.checkbox instantSave id="database.is_public" label="Accessible over the internet" />
|
||||||
</div>
|
</div>
|
||||||
<x-forms.input label="Postgres URL" readonly wire:model="db_url" />
|
<x-forms.input label="Postgres URL" readonly wire:model="db_url" />
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user