fix(new-resource): accept a base directory without a leading slash

Closes #12428

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras BacsaiandClaude Opus 5.5 committed 2026-11-02 13:58:15 +01:00
1 parent d8c1b926ca
commit 51029aa8b9
12 files changed
+36 -5

No files matched your search

@@ -165,6 +165,7 @@ class GiteaPrivateRepository extends Component
{
try {
$this->authorize('create', Application::class);
$this->base_directory = ValidationPatterns::normalizeDirectoryPath($this->base_directory);
$validator = validator([
'selected_repository_path' => $this->selected_repository_path,
@@ -202,6 +202,7 @@ class GithubPrivateRepository extends Component
{
try {
$this->authorize('create', Application::class);
$this->base_directory = ValidationPatterns::normalizeDirectoryPath($this->base_directory);
// Validate git repository parts and branch
$validator = validator([
@@ -155,6 +155,7 @@ class GithubPrivateRepositoryDeployKey extends Component
$privateKey = PrivateKey::ownedByCurrentTeam()->findOrFail($this->private_key_id);
$this->base_directory = ValidationPatterns::normalizeDirectoryPath($this->base_directory);
$this->validate();
try {
$destination_uuid = $this->query['destination'] ?? null;
@@ -162,6 +162,7 @@ class GitlabPrivateRepository extends Component
{
try {
$this->authorize('create', Application::class);
$this->base_directory = ValidationPatterns::normalizeDirectoryPath($this->base_directory);
$validator = validator([
'selected_repository_path' => $this->selected_repository_path,
@@ -278,6 +278,7 @@ class PublicGitRepository extends Component
{
try {
$this->authorize('create', Application::class);
$this->base_directory = ValidationPatterns::normalizeDirectoryPath($this->base_directory);
$this->validate();
+11
View File
@@ -576,6 +576,17 @@ class ValidationPatterns
return ['nullable', 'string', 'max:'.$maxLength, 'regex:'.self::DIRECTORY_PATH_PATTERN];
}
/**
* Normalize a typed directory path to the form that DIRECTORY_PATH_PATTERN expects:
* "apps/web/" becomes "/apps/web", and an empty value becomes "/".
*/
public static function normalizeDirectoryPath(?string $path): string
{
$path = trim(trim((string) $path), '/');
return '/'.$path;
}
/**
* Get validation rules for Docker build target fields
*/
@@ -135,7 +135,7 @@
file="docker_compose_location" fileLabel="Compose file"
defaultFile="/docker-compose.yaml" />
@else
<x-forms.input wire:model="base_directory" label="Base directory"
<x-forms.input id="base_directory" label="Base directory" placeholder="/"
helper="Repository directory used as the build root." />
@endif
</div>
@@ -85,7 +85,7 @@
file="docker_compose_location" fileLabel="Compose file"
defaultFile="/docker-compose.yaml" />
@else
<x-forms.input wire:model="base_directory" label="Base directory"
<x-forms.input id="base_directory" label="Base directory" placeholder="/"
helper="Repository directory used as the build root." />
@endif
@@ -162,7 +162,7 @@
file="docker_compose_location" fileLabel="Compose file"
defaultFile="/docker-compose.yaml" />
@else
<x-forms.input wire:model="base_directory" label="Base directory"
<x-forms.input id="base_directory" label="Base directory" placeholder="/"
helper="Repository directory used as the build root." />
@endif
</div>
@@ -139,7 +139,7 @@
file="docker_compose_location" fileLabel="Compose file"
defaultFile="/docker-compose.yaml" />
@else
<x-forms.input wire:model="base_directory" label="Base directory"
<x-forms.input id="base_directory" label="Base directory" placeholder="/"
helper="Repository directory used as the build root." />
@endif
</div>
@@ -111,7 +111,7 @@
file="docker_compose_location" fileLabel="Compose file"
defaultFile="/docker-compose.yaml" />
@else
<x-forms.input wire:model="base_directory" label="Base directory"
<x-forms.input id="base_directory" label="Base directory" placeholder="/"
helper="Repository directory used as the build root." />
@endif
</div>
@@ -128,6 +128,21 @@ test('deploy key application keeps the base directory for every build pack', fun
expect(Application::query()->sole()->base_directory)->toBe('/apps/api');
})->with(['dockerfile', 'railpack', 'static', 'dockercompose']);
test('deploy key application accepts a base directory without a leading slash', function (string $typed) {
actAsDeployKeyUser($this->admin, $this->team);
deployKeyComponent()
->call('setPrivateKey', $this->privateKey->id)
->set('repository_url', 'git@example.com:owner/monorepo.git')
->set('branch', 'main')
->set('build_pack', 'dockerfile')
->set('base_directory', $typed)
->call('submit')
->assertHasNoErrors();
expect(Application::query()->sole()->base_directory)->toBe('/apps/api');
})->with(['apps/api', 'apps/api/', ' /apps/api/ ']);
test('deploy key application uses the repository root when the base directory is empty', function () {
actAsDeployKeyUser($this->admin, $this->team);