feat: preserve git repository with advanced file storages
This commit is contained in:
@@ -157,7 +157,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
private ?string $coolify_variables = null;
|
||||
|
||||
private bool $preserveRepository = true;
|
||||
private bool $preserveRepository = false;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
@@ -480,6 +480,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
|
||||
// Start compose file
|
||||
$server_workdir = $this->application->workdir();
|
||||
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
||||
if ($this->docker_compose_custom_start_command) {
|
||||
$this->write_deployment_configurations();
|
||||
@@ -488,7 +489,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
);
|
||||
} else {
|
||||
$this->write_deployment_configurations();
|
||||
$server_workdir = $this->application->workdir();
|
||||
$this->docker_compose_location = '/docker-compose.yaml';
|
||||
|
||||
$command = "{$this->coolify_variables} docker compose";
|
||||
@@ -508,15 +508,26 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
);
|
||||
} else {
|
||||
$command = "{$this->coolify_variables} docker compose";
|
||||
if ($this->env_filename) {
|
||||
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
||||
}
|
||||
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
|
||||
if ($this->preserveRepository) {
|
||||
if ($this->env_filename) {
|
||||
$command .= " --env-file {$server_workdir}/{$this->env_filename}";
|
||||
}
|
||||
$command .= " --project-name {$this->application->uuid} --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d";
|
||||
$this->write_deployment_configurations();
|
||||
|
||||
$this->execute_remote_command(
|
||||
['command' => $command, 'hidden' => true],
|
||||
);
|
||||
} else {
|
||||
if ($this->env_filename) {
|
||||
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
||||
}
|
||||
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
|
||||
);
|
||||
}
|
||||
|
||||
$this->write_deployment_configurations();
|
||||
$this->execute_remote_command(
|
||||
[executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,6 +630,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
],
|
||||
);
|
||||
}
|
||||
$this->application->fileStorages()->each(function ($fileStorage) {
|
||||
if (! $fileStorage->is_based_on_git && ! $fileStorage->is_directory) {
|
||||
$fileStorage->saveStorageOnServer();
|
||||
}
|
||||
});
|
||||
if ($this->use_build_server) {
|
||||
$this->server = $this->build_server;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Livewire\Project\Application;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\LocalFileVolume;
|
||||
use Illuminate\Support\Collection;
|
||||
use Livewire\Component;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
@@ -30,6 +29,8 @@ class General extends Component
|
||||
|
||||
public ?string $ports_exposes = null;
|
||||
|
||||
public bool $is_preserve_repository_enabled = false;
|
||||
|
||||
public bool $is_container_label_escape_enabled = true;
|
||||
|
||||
public $customLabels;
|
||||
@@ -145,6 +146,7 @@ class General extends Component
|
||||
}
|
||||
$this->parsedServiceDomains = $this->application->docker_compose_domains ? json_decode($this->application->docker_compose_domains, true) : [];
|
||||
$this->ports_exposes = $this->application->ports_exposes;
|
||||
$this->is_preserve_repository_enabled = $this->application->settings->is_preserve_repository_enabled;
|
||||
$this->is_container_label_escape_enabled = $this->application->settings->is_container_label_escape_enabled;
|
||||
$this->customLabels = $this->application->parseContainerLabels();
|
||||
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && ! $this->application->settings->is_container_label_readonly_enabled) {
|
||||
@@ -168,9 +170,21 @@ class General extends Component
|
||||
$this->application->settings->save();
|
||||
$this->dispatch('success', 'Settings saved.');
|
||||
$this->application->refresh();
|
||||
|
||||
// If port_exposes changed, reset default labels
|
||||
if ($this->ports_exposes !== $this->application->ports_exposes || $this->is_container_label_escape_enabled !== $this->application->settings->is_container_label_escape_enabled) {
|
||||
$this->resetDefaultLabels(false);
|
||||
}
|
||||
if ($this->is_preserve_repository_enabled !== $this->application->settings->is_preserve_repository_enabled) {
|
||||
if ($this->application->settings->is_preserve_repository_enabled === false) {
|
||||
$this->application->fileStorages->each(function ($storage) {
|
||||
$storage->is_based_on_git = $this->application->settings->is_preserve_repository_enabled;
|
||||
$storage->save();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function loadComposeFile($isInit = false)
|
||||
@@ -191,32 +205,6 @@ class General extends Component
|
||||
return;
|
||||
}
|
||||
$compose = $this->application->parseCompose();
|
||||
$services = data_get($compose, 'services');
|
||||
if ($services) {
|
||||
$volumes = collect($services)->map(function ($service) {
|
||||
return data_get($service, 'volumes');
|
||||
})->flatten()->filter(function ($volume) {
|
||||
return str($volume)->startsWith('/data/coolify');
|
||||
})->unique()->values();
|
||||
foreach ($volumes as $volume) {
|
||||
$source = str($volume)->before(':');
|
||||
$target = str($volume)->after(':')->beforeLast(':');
|
||||
|
||||
LocalFileVolume::updateOrCreate(
|
||||
[
|
||||
'mount_path' => $target,
|
||||
'resource_id' => $this->application->id,
|
||||
'resource_type' => get_class($this->application),
|
||||
],
|
||||
[
|
||||
'fs_path' => $source,
|
||||
'mount_path' => $target,
|
||||
'resource_id' => $this->application->id,
|
||||
'resource_type' => get_class($this->application),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
$this->dispatch('success', 'Docker compose file loaded.');
|
||||
$this->dispatch('compose_loaded');
|
||||
$this->dispatch('refreshStorages');
|
||||
|
||||
@@ -33,6 +33,7 @@ class FileStorage extends Component
|
||||
'fileStorage.fs_path' => 'required',
|
||||
'fileStorage.mount_path' => 'required',
|
||||
'fileStorage.content' => 'nullable',
|
||||
'fileStorage.is_based_on_git' => 'required|boolean',
|
||||
];
|
||||
|
||||
public function mount()
|
||||
@@ -45,6 +46,7 @@ class FileStorage extends Component
|
||||
$this->workdir = null;
|
||||
$this->fs_path = $this->fileStorage->fs_path;
|
||||
}
|
||||
$this->fileStorage->loadStorageOnServer();
|
||||
}
|
||||
|
||||
public function convertToDirectory()
|
||||
@@ -68,6 +70,9 @@ class FileStorage extends Component
|
||||
$this->fileStorage->deleteStorageOnServer();
|
||||
$this->fileStorage->is_directory = false;
|
||||
$this->fileStorage->content = null;
|
||||
if (data_get($this->resource, 'settings.is_preserve_repository_enabled')) {
|
||||
$this->fileStorage->is_based_on_git = true;
|
||||
}
|
||||
$this->fileStorage->save();
|
||||
$this->fileStorage->saveStorageOnServer();
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
@@ -24,6 +24,32 @@ class LocalFileVolume extends BaseModel
|
||||
return $this->morphTo('resource');
|
||||
}
|
||||
|
||||
public function loadStorageOnServer()
|
||||
{
|
||||
$this->load(['service']);
|
||||
$isService = data_get($this->resource, 'service');
|
||||
if ($isService) {
|
||||
$workdir = $this->resource->service->workdir();
|
||||
$server = $this->resource->service->server;
|
||||
} else {
|
||||
$workdir = $this->resource->workdir();
|
||||
$server = $this->resource->destination->server;
|
||||
}
|
||||
$commands = collect([]);
|
||||
$path = data_get_str($this, 'fs_path');
|
||||
if ($path->startsWith('.')) {
|
||||
$path = $path->after('.');
|
||||
$path = $workdir.$path;
|
||||
}
|
||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||
if ($isFile === 'OK') {
|
||||
$content = instant_remote_process(["cat $path"], $server, false);
|
||||
$this->content = $content;
|
||||
$this->is_directory = false;
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteStorageOnServer()
|
||||
{
|
||||
$isService = data_get($this->resource, 'service');
|
||||
@@ -35,17 +61,20 @@ class LocalFileVolume extends BaseModel
|
||||
$server = $this->resource->destination->server;
|
||||
}
|
||||
$commands = collect([]);
|
||||
$fs_path = data_get($this, 'fs_path');
|
||||
$isFile = instant_remote_process(["test -f $fs_path && echo OK || echo NOK"], $server);
|
||||
$isDir = instant_remote_process(["test -d $fs_path && echo OK || echo NOK"], $server);
|
||||
if ($fs_path && $fs_path != '/' && $fs_path != '.' && $fs_path != '..') {
|
||||
ray($isFile, $isDir);
|
||||
$path = data_get_str($this, 'fs_path');
|
||||
if ($path->startsWith('.')) {
|
||||
$path = $path->after('.');
|
||||
$path = $workdir.$path;
|
||||
}
|
||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||
if ($path && $path != '/' && $path != '.' && $path != '..') {
|
||||
if ($isFile === 'OK') {
|
||||
$commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
|
||||
$commands->push("rm -rf $path > /dev/null 2>&1 || true");
|
||||
|
||||
} elseif ($isDir === 'OK') {
|
||||
$commands->push("rm -rf $fs_path > /dev/null 2>&1 || true");
|
||||
$commands->push("rmdir $fs_path > /dev/null 2>&1 || true");
|
||||
$commands->push("rm -rf $path > /dev/null 2>&1 || true");
|
||||
$commands->push("rmdir $path > /dev/null 2>&1 || true");
|
||||
}
|
||||
}
|
||||
if ($commands->count() > 0) {
|
||||
@@ -55,6 +84,7 @@ class LocalFileVolume extends BaseModel
|
||||
|
||||
public function saveStorageOnServer()
|
||||
{
|
||||
$this->load(['service']);
|
||||
$isService = data_get($this->resource, 'service');
|
||||
if ($isService) {
|
||||
$workdir = $this->resource->service->workdir();
|
||||
@@ -74,30 +104,36 @@ class LocalFileVolume extends BaseModel
|
||||
$commands->push("mkdir -p $parent_dir > /dev/null 2>&1 || true");
|
||||
}
|
||||
}
|
||||
$fileVolume = $this;
|
||||
$path = str(data_get($fileVolume, 'fs_path'));
|
||||
$content = data_get($fileVolume, 'content');
|
||||
$path = data_get_str($this, 'fs_path');
|
||||
$content = data_get($this, 'content');
|
||||
if ($path->startsWith('.')) {
|
||||
$path = $path->after('.');
|
||||
$path = $workdir.$path;
|
||||
}
|
||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
||||
if ($isFile == 'OK' && $this->is_directory) {
|
||||
$content = instant_remote_process(["cat $path"], $server, false);
|
||||
$fileVolume->is_directory = false;
|
||||
$fileVolume->content = $content;
|
||||
$fileVolume->save();
|
||||
$this->is_directory = false;
|
||||
$this->content = $content;
|
||||
$this->save();
|
||||
FileStorageChanged::dispatch(data_get($server, 'team_id'));
|
||||
throw new \Exception('The following file 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.');
|
||||
} elseif ($isDir == 'OK' && ! $fileVolume->is_directory) {
|
||||
$fileVolume->is_directory = true;
|
||||
$fileVolume->save();
|
||||
throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.');
|
||||
} elseif ($isDir == 'OK' && ! $this->is_directory) {
|
||||
if ($path == '/' || $path == '.' || $path == '..' || $path == '' || str($path)->isEmpty() || is_null($path)) {
|
||||
$this->is_directory = true;
|
||||
$this->save();
|
||||
throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.');
|
||||
}
|
||||
instant_remote_process([
|
||||
"rm -fr $path",
|
||||
"touch $path",
|
||||
], $server, false);
|
||||
FileStorageChanged::dispatch(data_get($server, 'team_id'));
|
||||
}
|
||||
if ($isDir == 'NOK' && ! $fileVolume->is_directory) {
|
||||
$chmod = data_get($fileVolume, 'chmod');
|
||||
$chown = data_get($fileVolume, 'chown');
|
||||
if ($isDir == 'NOK' && ! $this->is_directory) {
|
||||
$chmod = data_get($this, 'chmod');
|
||||
$chown = data_get($this, 'chown');
|
||||
if ($content) {
|
||||
$content = base64_encode($content);
|
||||
$commands->push("echo '$content' | base64 -d | tee $path > /dev/null");
|
||||
@@ -111,7 +147,7 @@ class LocalFileVolume extends BaseModel
|
||||
if ($chmod) {
|
||||
$commands->push("chmod $chmod $path");
|
||||
}
|
||||
} elseif ($isDir == 'NOK' && $fileVolume->is_directory) {
|
||||
} elseif ($isDir == 'NOK' && $this->is_directory) {
|
||||
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user