fix: move base directory path normalization to frontend (#7437)

This commit is contained in:
Andras Bacsai
2025-12-04 14:52:44 +01:00
committed by GitHub
8 changed files with 171 additions and 81 deletions
+40 -24
View File
@@ -521,7 +521,7 @@ class General extends Component
}
}
public function loadComposeFile($isInit = false, $showToast = true)
public function loadComposeFile($isInit = false, $showToast = true, ?string $restoreBaseDirectory = null, ?string $restoreDockerComposeLocation = null)
{
try {
$this->authorize('update', $this->application);
@@ -530,7 +530,7 @@ class General extends Component
return;
}
['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation] = $this->application->loadComposeFile($isInit);
['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation] = $this->application->loadComposeFile($isInit, $restoreBaseDirectory, $restoreDockerComposeLocation);
if (is_null($this->parsedServices)) {
$showToast && $this->dispatch('error', 'Failed to parse your docker-compose file. Please check the syntax and try again.');
@@ -606,13 +606,6 @@ class General extends Component
}
}
public function updatedBaseDirectory()
{
if ($this->buildPack === 'dockercompose') {
$this->loadComposeFile();
}
}
public function updatedIsStatic($value)
{
if ($value) {
@@ -786,11 +779,13 @@ class General extends Component
try {
$this->authorize('update', $this->application);
$this->resetErrorBag();
$this->validate();
$oldPortsExposes = $this->application->ports_exposes;
$oldIsContainerLabelEscapeEnabled = $this->application->settings->is_container_label_escape_enabled;
$oldDockerComposeLocation = $this->initialDockerComposeLocation;
$oldBaseDirectory = $this->application->base_directory;
// Process FQDN with intermediate variable to avoid Collection/string confusion
$this->fqdn = str($this->fqdn)->replaceEnd(',', '')->trim()->toString();
@@ -821,6 +816,42 @@ class General extends Component
return; // Stop if there are conflicts and user hasn't confirmed
}
// Normalize paths BEFORE validation
if ($this->baseDirectory && $this->baseDirectory !== '/') {
$this->baseDirectory = rtrim($this->baseDirectory, '/');
$this->application->base_directory = $this->baseDirectory;
}
if ($this->publishDirectory && $this->publishDirectory !== '/') {
$this->publishDirectory = rtrim($this->publishDirectory, '/');
$this->application->publish_directory = $this->publishDirectory;
}
// Validate docker compose file path BEFORE saving to database
// This prevents invalid paths from being persisted when validation fails
if ($this->buildPack === 'dockercompose' &&
($oldDockerComposeLocation !== $this->dockerComposeLocation ||
$oldBaseDirectory !== $this->baseDirectory)) {
// Pass original values to loadComposeFile so it can restore them on failure
// The finally block in Application::loadComposeFile will save these original
// values if validation fails, preventing invalid paths from being persisted
$compose_return = $this->loadComposeFile(
isInit: false,
showToast: false,
restoreBaseDirectory: $oldBaseDirectory,
restoreDockerComposeLocation: $oldDockerComposeLocation
);
if ($compose_return instanceof \Livewire\Features\SupportEvents\Event) {
// Validation failed - restore original values to component properties
$this->baseDirectory = $oldBaseDirectory;
$this->dockerComposeLocation = $oldDockerComposeLocation;
// The model was saved by loadComposeFile's finally block with original values
// Refresh to sync component with database state
$this->application->refresh();
return;
}
}
$this->application->save();
if (! $this->customLabels && $this->application->destination->server->proxyType() !== 'NONE' && ! $this->application->settings->is_container_label_readonly_enabled) {
$this->customLabels = str(implode('|coolify|', generateLabelsApplication($this->application)))->replace('|coolify|', "\n");
@@ -828,13 +859,6 @@ class General extends Component
$this->application->save();
}
if ($this->buildPack === 'dockercompose' && $oldDockerComposeLocation !== $this->dockerComposeLocation) {
$compose_return = $this->loadComposeFile(showToast: false);
if ($compose_return instanceof \Livewire\Features\SupportEvents\Event) {
return;
}
}
if ($oldPortsExposes !== $this->portsExposes || $oldIsContainerLabelEscapeEnabled !== $this->isContainerLabelEscapeEnabled) {
$this->resetDefaultLabels();
}
@@ -855,14 +879,6 @@ class General extends Component
$this->application->ports_exposes = $port;
}
}
if ($this->baseDirectory && $this->baseDirectory !== '/') {
$this->baseDirectory = rtrim($this->baseDirectory, '/');
$this->application->base_directory = $this->baseDirectory;
}
if ($this->publishDirectory && $this->publishDirectory !== '/') {
$this->publishDirectory = rtrim($this->publishDirectory, '/');
$this->application->publish_directory = $this->publishDirectory;
}
if ($this->buildPack === 'dockercompose') {
$this->application->docker_compose_domains = json_encode($this->parsedServiceDomains);
if ($this->application->isDirty('docker_compose_domains')) {