diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md
index b232e303b..c11930538 100644
--- a/CONTRIBUTION.md
+++ b/CONTRIBUTION.md
@@ -6,13 +6,14 @@
You can ask for guidance anytime on our
[Discord server](https://coollabs.io/discord) in the `#contribution` channel.
+## Code Contribution
-## 1) Setup your development environment
+### 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
+### 2) Set your environment variables
- Copy [.env.development.example](./.env.development.example) to .env.
@@ -23,9 +24,14 @@ You can ask for guidance anytime on our
- 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
+### 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.
Mails are caught by Mailpit: `localhost:8025`
+
+
+## New Service Contribution
+Check out the docs [here](https://coolify.io/docs/how-to-add-a-service).
+
diff --git a/README.md b/README.md
index 8d5ea5a74..031e39c2a 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,7 @@ Contact us [here](https://coolify.io/docs/contact).
## Recognitions
+
+
+
+
## 💰 Financial Contributors
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/coollabsio/contribute)]
diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php
index 730cf4113..8bbab0081 100644
--- a/app/Console/Kernel.php
+++ b/app/Console/Kernel.php
@@ -19,13 +19,9 @@ class Kernel extends ConsoleKernel
protected function schedule(Schedule $schedule): void
{
if (isDev()) {
- // $schedule->job(new ContainerStatusJob(Server::find(0)))->everyTenMinutes()->onOneServer();
- // $schedule->command('horizon:snapshot')->everyMinute();
+ $schedule->command('horizon:snapshot')->everyMinute();
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
- // $schedule->job(new CheckResaleLicenseJob)->hourly();
- // $schedule->job(new DockerCleanupJob)->everyOddHour();
- // $this->instance_auto_update($schedule);
- // $this->check_scheduled_backups($schedule);
+ $this->check_scheduled_backups($schedule);
$this->check_resources($schedule);
$this->cleanup_servers($schedule);
$this->check_scheduled_backups($schedule);
@@ -69,7 +65,6 @@ class Kernel extends ConsoleKernel
}
private function check_scheduled_backups($schedule)
{
- ray('check_scheduled_backups');
$scheduled_backups = ScheduledDatabaseBackup::all();
if ($scheduled_backups->isEmpty()) {
ray('no scheduled backups');
diff --git a/app/Http/Livewire/Dashboard.php b/app/Http/Livewire/Dashboard.php
index 723b00f7f..b46df481a 100644
--- a/app/Http/Livewire/Dashboard.php
+++ b/app/Http/Livewire/Dashboard.php
@@ -17,6 +17,10 @@ class Dashboard extends Component
$this->servers = Server::ownedByCurrentTeam()->get();
$this->projects = Project::ownedByCurrentTeam()->get();
}
+ // public function createToken() {
+ // $token = auth()->user()->createToken('test');
+ // ray($token);
+ // }
// public function getIptables()
// {
// $servers = Server::ownedByCurrentTeam()->get();
diff --git a/app/Http/Livewire/Project/Application/General.php b/app/Http/Livewire/Project/Application/General.php
index dc3bd8db6..b4ebfff5d 100644
--- a/app/Http/Livewire/Project/Application/General.php
+++ b/app/Http/Livewire/Project/Application/General.php
@@ -3,12 +3,9 @@
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
-use App\Models\InstanceSettings;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Livewire\Component;
-use Spatie\Url\Url;
-use Symfony\Component\Yaml\Yaml;
class General extends Component
{
@@ -23,6 +20,10 @@ class General extends Component
public ?string $git_commit_sha = null;
public string $build_pack;
+ public $customLabels;
+ public bool $labelsChanged = false;
+ public bool $isConfigurationChanged = false;
+
public bool $is_static;
public bool $is_git_submodules_enabled;
public bool $is_git_lfs_enabled;
@@ -52,6 +53,7 @@ class General extends Component
'application.docker_registry_image_name' => 'nullable',
'application.docker_registry_image_tag' => 'nullable',
'application.dockerfile_location' => 'nullable',
+ 'application.custom_labels' => 'nullable',
];
protected $validationAttributes = [
'application.name' => 'name',
@@ -73,19 +75,51 @@ class General extends Component
'application.docker_registry_image_name' => 'Docker registry image name',
'application.docker_registry_image_tag' => 'Docker registry image tag',
'application.dockerfile_location' => 'Dockerfile location',
-
+ 'application.custom_labels' => 'Custom labels',
];
- public function updatedApplicationBuildPack(){
+ public function mount()
+ {
+ if (str($this->application->status)->startsWith('running') && is_null($this->application->config_hash)) {
+ $this->application->isConfigurationChanged(true);
+ }
+ $this->isConfigurationChanged = $this->application->isConfigurationChanged();
+ if (is_null(data_get($this->application, 'custom_labels'))) {
+ $this->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n");
+ } else {
+ $this->customLabels = str($this->application->custom_labels)->replace(',', "\n");
+ }
+ if (data_get($this->application, 'settings')) {
+ $this->is_static = $this->application->settings->is_static;
+ $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_debug_enabled = $this->application->settings->is_debug_enabled;
+ $this->is_preview_deployments_enabled = $this->application->settings->is_preview_deployments_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->checkLabelUpdates();
+ }
+ public function updatedApplicationBuildPack()
+ {
if ($this->application->build_pack !== 'nixpacks') {
$this->application->settings->is_static = $this->is_static = false;
$this->application->settings->save();
}
$this->submit();
}
+ public function checkLabelUpdates()
+ {
+ if (md5($this->application->custom_labels) !== md5(implode(",", generateLabelsApplication($this->application)))) {
+ $this->labelsChanged = true;
+ } else {
+ $this->labelsChanged = false;
+ }
+ }
public function instantSave()
{
// @TODO: find another way - if possible
+ $force_https = $this->application->settings->is_force_https_enabled;
$this->application->settings->is_static = $this->is_static;
if ($this->is_static) {
$this->application->ports_exposes = 80;
@@ -102,37 +136,39 @@ class General extends Component
$this->application->save();
$this->application->refresh();
$this->emit('success', 'Application settings updated!');
+ $this->checkLabelUpdates();
+ $this->isConfigurationChanged = $this->application->isConfigurationChanged();
+ if ($force_https !== $this->is_force_https_enabled) {
+ $this->resetDefaultLabels(false);
+ }
}
- public function getWildcardDomain() {
+ public function getWildcardDomain()
+ {
$server = data_get($this->application, 'destination.server');
if ($server) {
$fqdn = generateFqdn($server, $this->application->uuid);
- ray($fqdn);
$this->application->fqdn = $fqdn;
$this->application->save();
$this->emit('success', 'Application settings updated!');
}
-
}
- public function mount()
+ public function resetDefaultLabels($showToaster = true)
{
- if (data_get($this->application,'settings')) {
- $this->is_static = $this->application->settings->is_static;
- $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_debug_enabled = $this->application->settings->is_debug_enabled;
- $this->is_preview_deployments_enabled = $this->application->settings->is_preview_deployments_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->customLabels = str(implode(",", generateLabelsApplication($this->application)))->replace(',', "\n");
+ $this->submit($showToaster);
}
- public function submit()
+ public function updatedApplicationFqdn()
+ {
+ $this->resetDefaultLabels(false);
+ $this->emit('success', 'Labels reseted to default!');
+ }
+ public function submit($showToaster = true)
{
try {
$this->validate();
- if (data_get($this->application,'build_pack') === 'dockerimage') {
+ if (data_get($this->application, 'build_pack') === 'dockerimage') {
$this->validate([
'application.docker_registry_image_name' => 'required',
'application.docker_registry_image_tag' => 'required',
@@ -156,10 +192,17 @@ class General extends Component
if ($this->application->publish_directory && $this->application->publish_directory !== '/') {
$this->application->publish_directory = rtrim($this->application->publish_directory, '/');
}
+ if (gettype($this->customLabels) === 'string') {
+ $this->customLabels = str($this->customLabels)->replace(',', "\n");
+ }
+ $this->application->custom_labels = $this->customLabels->explode("\n")->implode(',');
$this->application->save();
- $this->emit('success', 'Application settings updated!');
+ $showToaster && $this->emit('success', 'Application settings updated!');
} catch (\Throwable $e) {
return handleError($e, $this);
+ } finally {
+ $this->checkLabelUpdates();
+ $this->isConfigurationChanged = $this->application->isConfigurationChanged();
}
}
}
diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php
index 09e7c510d..3091bc339 100644
--- a/app/Jobs/ApplicationDeploymentJob.php
+++ b/app/Jobs/ApplicationDeploymentJob.php
@@ -54,7 +54,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
private ApplicationPreview|null $preview = null;
private string $container_name;
- private string|null $currently_running_container_name = null;
+ private ?string $currently_running_container_name = null;
private string $basedir;
private string $workdir;
private ?string $build_pack = null;
@@ -75,10 +75,12 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
private string $serverUserHomeDir = '/root';
private string $dockerConfigFileExists = 'NOK';
+ private int $customPort = 22;
+
public $tries = 1;
public function __construct(int $application_deployment_queue_id)
{
- ray()->clearScreen();
+ // ray()->clearScreen();
$this->application_deployment_queue = ApplicationDeploymentQueue::find($application_deployment_queue_id);
$this->log_model = $this->application_deployment_queue;
$this->application = Application::find($this->application_deployment_queue->application_id);
@@ -166,8 +168,16 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
// Get user home directory
$this->serverUserHomeDir = instant_remote_process(["echo \$HOME"], $this->server);
- ray("test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'");
$this->dockerConfigFileExists = instant_remote_process(["test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'"], $this->server);
+
+ // Check custom port
+ preg_match('/(?<=:)\d+(?=\/)/', $this->application->git_repository, $matches);
+ if (count($matches) === 1) {
+ $this->customPort = $matches[0];
+ $gitHost = str($this->application->git_repository)->before(':');
+ $gitRepo = str($this->application->git_repository)->after('/');
+ $this->application->git_repository = "$gitHost:$gitRepo";
+ }
try {
if ($this->application->dockerfile) {
$this->deploy_simple_dockerfile();
@@ -186,6 +196,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
dispatch(new ContainerStatusJob($this->server));
}
$this->next(ApplicationDeploymentStatus::FINISHED->value);
+ $this->application->isConfigurationChanged(true);
} catch (Exception $e) {
ray($e);
$this->fail($e);
@@ -354,14 +365,19 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->execute_remote_command([
"docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
]);
- if (Str::of($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
+ if (Str::of($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
$this->execute_remote_command([
- "echo 'Docker Image found locally with the same Git Commit SHA {$this->application->uuid}:{$this->commit}. Build step skipped...'"
+ "echo 'No configuration changed & Docker Image found locally with the same Git Commit SHA {$this->application->uuid}:{$this->commit}. Build step skipped.'",
]);
$this->generate_compose_file();
$this->rolling_update();
return;
}
+ if ($this->application->isConfigurationChanged()) {
+ $this->execute_remote_command([
+ "echo 'Configuration changed. Rebuilding image.'",
+ ]);
+ }
}
$this->cleanup_git();
$this->generate_nixpacks_confs();
@@ -544,13 +560,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
}
}
if ($this->application->deploymentType() === 'deploy_key') {
- $port = 22;
- preg_match('/(?<=:)\d+(?=\/)/', $this->application->git_repository, $matches);
- if (count($matches) === 1) {
- $port = $matches[0];
- }
$private_key = base64_encode($this->application->private_key->private_key);
- $git_clone_command = "GIT_SSH_COMMAND=\"ssh -p $port -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_repository} {$this->basedir}";
+ $git_clone_command = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->application->git_repository} {$this->basedir}";
$git_clone_command = $this->set_git_import_settings($git_clone_command);
$commands = collect([
executeInDocker($this->deployment_uuid, "mkdir -p /root/.ssh"),
@@ -650,6 +661,10 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$volume_names = $this->generate_local_persistent_volumes_only_volume_names();
$environment_variables = $this->generate_environment_variables($ports);
+ $labels = generateLabelsApplication($this->application, $this->preview);
+ if (data_get($this->application, 'custom_labels')) {
+ $labels = str($this->application->custom_labels)->explode(',')->toArray();
+ }
$docker_compose = [
'version' => '3.8',
'services' => [
@@ -658,7 +673,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
'container_name' => $this->container_name,
'restart' => RESTART_MODE,
'environment' => $environment_variables,
- 'labels' => generateLabelsApplication($this->application, $this->preview, $ports),
+ 'labels' => $labels,
'expose' => $ports,
'networks' => [
$this->destination->network,
diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php
index 1c8cf1919..24c869219 100644
--- a/app/Jobs/ContainerStatusJob.php
+++ b/app/Jobs/ContainerStatusJob.php
@@ -12,7 +12,6 @@ use App\Notifications\Server\Revived;
use App\Notifications\Server\Unreachable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
-use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
@@ -25,30 +24,23 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
- public $tries = 1;
- public $timeout = 120;
-
- public function middleware(): array
- {
- return [(new WithoutOverlapping($this->server->uuid))->dontRelease()];
- }
-
- public function uniqueId(): string
- {
- return $this->server->uuid;
- }
-
public function __construct(public Server $server)
{
- if (isDev()) {
- $this->handle();
- }
+ }
+ public function middleware(): array
+ {
+ return [(new WithoutOverlapping($this->server->id))->dontRelease()];
}
- public function handle()
+ public function uniqueId(): int
{
+ return $this->server->id;
+ }
+
+ public function handle(): void
+ {
+ ray("checking server status for {$this->server->id}");
try {
- // ray("checking server status for {$this->server->id}");
// ray()->clearAll();
$serverUptimeCheckNumber = $this->server->unreachable_count;
$serverUptimeCheckNumberMax = 3;
@@ -129,7 +121,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
} catch (\Throwable $e) {
ray($e);
}
-
} else {
$this->server->proxy->status = data_get($foundProxyContainer, 'State.Status');
$this->server->save();
@@ -308,7 +299,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
} catch (\Throwable $e) {
send_internal_notification('ContainerStatusJob failed with: ' . $e->getMessage());
ray($e->getMessage());
- return handleError($e);
+ handleError($e);
}
}
}
diff --git a/app/Models/Application.php b/app/Models/Application.php
index e5bf9db07..2e6c2814d 100644
--- a/app/Models/Application.php
+++ b/app/Models/Application.php
@@ -277,4 +277,31 @@ class Application extends BaseModel
}
return false;
}
+ public function isConfigurationChanged($save = false)
+ {
+ $newConfigHash = $this->fqdn . $this->git_repository . $this->git_branch . $this->git_commit_sha . $this->build_pack . $this->static_image . $this->install_command . $this->build_command . $this->start_command . $this->port_exposes . $this->port_mappings . $this->base_directory . $this->publish_directory . $this->health_check_path . $this->health_check_port . $this->health_check_host . $this->health_check_method . $this->health_check_return_code . $this->health_check_scheme . $this->health_check_response_text . $this->health_check_interval . $this->health_check_timeout . $this->health_check_retries . $this->health_check_start_period . $this->health_check_enabled . $this->limits_memory . $this->limits_swap . $this->limits_swappiness . $this->limits_reservation . $this->limits_cpus . $this->limits_cpuset . $this->limits_cpu_shares . $this->dockerfile . $this->dockerfile_location . $this->custom_labels;
+ if ($this->pull_request_id === 0) {
+ $newConfigHash .= json_encode($this->environment_variables->all());
+ } else {
+ $newConfigHash .= json_encode($this->environment_variables_preview->all());
+ }
+ $newConfigHash = md5($newConfigHash);
+ $oldConfigHash = data_get($this, 'config_hash');
+ if ($oldConfigHash === null) {
+ if ($save) {
+ $this->config_hash = $newConfigHash;
+ $this->save();
+ }
+ return true;
+ }
+ if ($oldConfigHash === $newConfigHash) {
+ return false;
+ } else {
+ if ($save) {
+ $this->config_hash = $newConfigHash;
+ $this->save();
+ }
+ return true;
+ }
+ }
}
diff --git a/app/Models/PersonalAccessToken.php b/app/Models/PersonalAccessToken.php
new file mode 100644
index 000000000..f5b11883a
--- /dev/null
+++ b/app/Models/PersonalAccessToken.php
@@ -0,0 +1,15 @@
+name)->beforeLast('-')->value, []);
return data_get($service, 'documentation', config('constants.docs.base_url'));
}
@@ -538,7 +538,7 @@ class Service extends BaseModel
$serviceLabels = $serviceLabels->merge($defaultLabels);
if (!$isDatabase && $fqdns->count() > 0) {
if ($fqdns) {
- $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($fqdns, true));
+ $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($this->uuid, $fqdns, true));
}
}
data_set($service, 'labels', $serviceLabels->toArray());
@@ -568,7 +568,7 @@ class Service extends BaseModel
'networks' => $topLevelNetworks->toArray(),
];
$this->docker_compose_raw = Yaml::dump($yaml, 10, 2);
- $this->docker_compose = Yaml::dump($finalServices, 10, 2);
+ $this->docker_compose = Yaml::dump($finalServices, 10, 2);
$this->save();
$this->saveComposeConfigs();
return collect([]);
diff --git a/app/Models/User.php b/app/Models/User.php
index c4275cd68..640de6381 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -4,6 +4,7 @@ namespace App\Models;
use App\Notifications\Channels\SendsEmail;
use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword;
+use DateTimeInterface;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Messages\MailMessage;
@@ -14,6 +15,8 @@ use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\URL;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens;
+use Laravel\Sanctum\NewAccessToken;
+use Illuminate\Support\Str;
class User extends Authenticatable implements SendsEmail
{
@@ -47,7 +50,26 @@ class User extends Authenticatable implements SendsEmail
$user->teams()->attach($new_team, ['role' => 'owner']);
});
}
+ public function createToken(string $name, array $abilities = ['*'], DateTimeInterface $expiresAt = null)
+ {
+ ray('asd');
+ $plainTextToken = sprintf(
+ '%s%s%s',
+ config('sanctum.token_prefix', ''),
+ $tokenEntropy = Str::random(40),
+ hash('crc32b', $tokenEntropy)
+ );
+ $token = $this->tokens()->create([
+ 'name' => $name,
+ 'token' => hash('sha256', $plainTextToken),
+ 'abilities' => $abilities,
+ 'expires_at' => $expiresAt,
+ 'team_id' => session('currentTeam')->id
+ ]);
+
+ return new NewAccessToken($token, $token->getKey().'|'.$plainTextToken);
+ }
public function teams()
{
return $this->belongsToMany(Team::class)->withPivot('role');
diff --git a/app/Notifications/Channels/EmailChannel.php b/app/Notifications/Channels/EmailChannel.php
index 5cd4ceaeb..cd6dc4b56 100644
--- a/app/Notifications/Channels/EmailChannel.php
+++ b/app/Notifications/Channels/EmailChannel.php
@@ -30,7 +30,12 @@ class EmailChannel
);
} catch (Exception $e) {
ray($e->getMessage());
- send_internal_notification("EmailChannel error: {$e->getMessage()}. Failed to send email to: " . implode(', ', $recepients) . " with subject: {$mailMessage->subject}");
+ $message = "EmailChannel error: {$e->getMessage()}. Failed to send email to:";
+ if (isset($recepients)) {
+ $message .= implode(', ', $recepients);
+ }
+ $message .= " with subject: {$mailMessage->subject}";
+ send_internal_notification($message);
throw $e;
}
}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 07d02cd03..c50a53bef 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -4,6 +4,8 @@ namespace App\Providers;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\ServiceProvider;
+use Laravel\Sanctum\Sanctum;
+use App\Models\PersonalAccessToken;
class AppServiceProvider extends ServiceProvider
{
@@ -13,6 +15,8 @@ class AppServiceProvider extends ServiceProvider
public function boot(): void
{
+ Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
+
Http::macro('github', function (string $api_url, string|null $github_access_token = null) {
if ($github_access_token) {
return Http::withHeaders([
diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php
index adf1761f1..179abecb9 100644
--- a/bootstrap/helpers/docker.php
+++ b/bootstrap/helpers/docker.php
@@ -147,12 +147,11 @@ function defaultLabels($id, $name, $pull_request_id = 0, string $type = 'applica
}
return $labels;
}
-function fqdnLabelsForTraefik(Collection $domains, bool $is_force_https_enabled, $onlyPort = null)
+function fqdnLabelsForTraefik(string $uuid, Collection $domains, bool $is_force_https_enabled, $onlyPort = null)
{
$labels = collect([]);
$labels->push('traefik.enable=true');
- foreach ($domains as $domain) {
- $uuid = (string)new Cuid2(7);
+ foreach ($domains as $loop => $domain) {
$url = Url::fromString($domain);
$host = $url->getHost();
$path = $url->getPath();
@@ -161,8 +160,8 @@ function fqdnLabelsForTraefik(Collection $domains, bool $is_force_https_enabled,
if (is_null($port) && !is_null($onlyPort)) {
$port = $onlyPort;
}
- $http_label = "{$uuid}-http";
- $https_label = "{$uuid}-https";
+ $http_label = "{$uuid}-{$loop}-http";
+ $https_label = "{$uuid}-{$loop}-https";
if ($schema === 'https') {
// Set labels for https
@@ -205,20 +204,21 @@ function fqdnLabelsForTraefik(Collection $domains, bool $is_force_https_enabled,
return $labels;
}
-function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null, $ports): array
+function generateLabelsApplication(Application $application, ?ApplicationPreview $preview = null): array
{
+ $ports = $application->settings->is_static ? [80] : $application->ports_exposes_array;
$onlyPort = null;
if (count($ports) === 1) {
$onlyPort = $ports[0];
}
$pull_request_id = data_get($preview, 'pull_request_id', 0);
- $container_name = generateApplicationContainerName($application, $pull_request_id);
+ // $container_name = generateApplicationContainerName($application, $pull_request_id);
$appId = $application->id;
if ($pull_request_id !== 0 && $pull_request_id !== null) {
$appId = $appId . '-pr-' . $pull_request_id;
}
$labels = collect([]);
- $labels = $labels->merge(defaultLabels($appId, $container_name, $pull_request_id));
+ $labels = $labels->merge(defaultLabels($appId, $application->uuid, $pull_request_id));
if ($application->fqdn) {
if ($pull_request_id !== 0) {
$domains = Str::of(data_get($preview, 'fqdn'))->explode(',');
@@ -226,7 +226,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
$domains = Str::of(data_get($application, 'fqdn'))->explode(',');
}
// Add Traefik labels no matter which proxy is selected
- $labels = $labels->merge(fqdnLabelsForTraefik($domains, $application->settings->is_force_https_enabled,$onlyPort));
+ $labels = $labels->merge(fqdnLabelsForTraefik($application->uuid, $domains, $application->settings->is_force_https_enabled, $onlyPort));
}
return $labels->all();
}
diff --git a/config/horizon.php b/config/horizon.php
index f35cbd731..14d20e1cf 100644
--- a/config/horizon.php
+++ b/config/horizon.php
@@ -210,13 +210,13 @@ return [
'production' => [
's6' => [
'autoScalingStrategy' => 'size',
- 'maxProcesses' => env('HORIZON_MAX_PROCESSES', 10),
+ 'maxProcesses' => env('HORIZON_MAX_PROCESSES', 2),
'balanceMaxShift' => env('HORIZON_BALANCE_MAX_SHIFT', 1),
'balanceCooldown' => env('HORIZON_BALANCE_COOLDOWN', 1),
],
'long-running' => [
'autoScalingStrategy' => 'size',
- 'maxProcesses' => env('HORIZON_MAX_PROCESSES', 10),
+ 'maxProcesses' => env('HORIZON_MAX_PROCESSES', 2),
'balanceMaxShift' => env('HORIZON_BALANCE_MAX_SHIFT', 1),
'balanceCooldown' => env('HORIZON_BALANCE_COOLDOWN', 1),
],
@@ -225,13 +225,13 @@ return [
'local' => [
's6' => [
'autoScalingStrategy' => 'size',
- 'maxProcesses' => env('HORIZON_MAX_PROCESSES', 10),
+ 'maxProcesses' => env('HORIZON_MAX_PROCESSES', 2),
'balanceMaxShift' => env('HORIZON_BALANCE_MAX_SHIFT', 1),
'balanceCooldown' => env('HORIZON_BALANCE_COOLDOWN', 1),
],
'long-running' => [
'autoScalingStrategy' => 'size',
- 'maxProcesses' => env('HORIZON_MAX_PROCESSES', 10),
+ 'maxProcesses' => env('HORIZON_MAX_PROCESSES', 2),
'balanceMaxShift' => env('HORIZON_BALANCE_MAX_SHIFT', 1),
'balanceCooldown' => env('HORIZON_BALANCE_COOLDOWN', 1),
],
diff --git a/config/sentry.php b/config/sentry.php
index 4a096757f..1c75b9d50 100644
--- a/config/sentry.php
+++ b/config/sentry.php
@@ -7,7 +7,7 @@ return [
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
- 'release' => '4.0.0-beta.92',
+ 'release' => '4.0.0-beta.97',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),
diff --git a/config/version.php b/config/version.php
index d889b7a6c..af0296c72 100644
--- a/config/version.php
+++ b/config/version.php
@@ -1,3 +1,3 @@
text('custom_labels')->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('applications', function (Blueprint $table) {
+ $table->dropColumn('custom_labels');
+ });
+ }
+};
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 6268f9963..0c427d233 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -27,6 +27,7 @@ services:
- QUEUE_CONNECTION
- REDIS_HOST
- REDIS_PASSWORD
+ - HORIZON_MAX_PROCESSES
- SSL_MODE=off
- PHP_PM_CONTROL=dynamic
- PHP_PM_START_SERVERS=1
diff --git a/examples/compose/uptime-kuma.yaml b/examples/compose/uptime-kuma.yaml
deleted file mode 100644
index 28e7c59bc..000000000
--- a/examples/compose/uptime-kuma.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-services:
- uptime-kuma:
- image: louislam/uptime-kuma:1
- volumes:
- - uptime-kuma:/app/data
diff --git a/resources/views/livewire/dashboard.blade.php b/resources/views/livewire/dashboard.blade.php
index 1cfec37be..7ceb40d7a 100644
--- a/resources/views/livewire/dashboard.blade.php
+++ b/resources/views/livewire/dashboard.blade.php
@@ -23,7 +23,7 @@
@if ($projects->count() === 1)
@else
-
+
@endif
@foreach ($projects as $project)
description }}
@endif
-
+ New Resource
@@ -62,7 +62,7 @@
@endforeach
@if ($projects->count() > 0)
-
Servers
+
Servers
@endif
@if ($servers->count() === 1)
@@ -97,7 +97,9 @@
@endforeach
-
+ {{--
Tokens
+ {{auth()->user()->tokens}}
+
Create Token --}}