diff --git a/app/Livewire/Source/Gitlab/Create.php b/app/Livewire/Source/Gitlab/Create.php index 7f37219ec..200bd6d40 100644 --- a/app/Livewire/Source/Gitlab/Create.php +++ b/app/Livewire/Source/Gitlab/Create.php @@ -6,6 +6,7 @@ use App\Models\GitlabApp; use App\Rules\SafeExternalUrl; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Str; +use Illuminate\Validation\ValidationException; use Livewire\Component; class Create extends Component @@ -16,34 +17,62 @@ class Create extends Component public string $html_url = 'https://gitlab.com'; + public string $api_url = 'https://gitlab.com/api/v4'; + + public string $custom_user = 'git'; + + public int $custom_port = 22; + public bool $is_system_wide = false; public ?string $group_name = null; + private bool $shouldDeriveApiUrlAfterHtmlUrlUpdate = false; + public function mount() { $this->name = substr(generate_random_name(), 0, 30); } + public function updatingHtmlUrl(): void + { + $this->shouldDeriveApiUrlAfterHtmlUrlUpdate = blank($this->api_url) + || $this->api_url === $this->gitlabApiUrlFromHtmlUrl($this->html_url); + } + + public function updatedHtmlUrl(): void + { + if ($this->shouldDeriveApiUrlAfterHtmlUrlUpdate) { + $this->api_url = $this->gitlabApiUrlFromHtmlUrl($this->html_url); + } + } + public function createGitLabApp() { try { $this->authorize('createAnyResource'); + $this->html_url = rtrim($this->html_url, '/'); + $this->api_url = filled($this->api_url) + ? rtrim($this->api_url, '/') + : $this->gitlabApiUrlFromHtmlUrl($this->html_url); + $this->validate([ 'name' => 'required|string', 'html_url' => ['required', 'string', 'url', new SafeExternalUrl], + 'api_url' => ['required', 'string', 'url', new SafeExternalUrl], + 'custom_user' => 'required|string', + 'custom_port' => 'required|int', 'is_system_wide' => 'required|bool', 'group_name' => 'nullable|string', ]); - $htmlUrl = rtrim($this->html_url, '/'); - $apiUrl = $htmlUrl.'/api/v4'; - $gitlab_app = GitlabApp::create([ 'name' => $this->name, - 'api_url' => $apiUrl, - 'html_url' => $htmlUrl, + 'api_url' => $this->api_url, + 'html_url' => $this->html_url, + 'custom_user' => $this->custom_user, + 'custom_port' => $this->custom_port, 'is_system_wide' => $this->is_system_wide, 'group_name' => $this->group_name, 'webhook_token' => Str::random(32), @@ -55,8 +84,15 @@ class Create extends Component } return redirectRoute($this, 'source.gitlab.show', ['gitlab_app_uuid' => $gitlab_app->uuid]); + } catch (ValidationException $e) { + throw $e; } catch (\Throwable $e) { return handleError($e, $this); } } + + private function gitlabApiUrlFromHtmlUrl(string $htmlUrl): string + { + return rtrim($htmlUrl, '/').'/api/v4'; + } } diff --git a/resources/views/livewire/source/gitlab/create.blade.php b/resources/views/livewire/source/gitlab/create.blade.php index 61e2bedeb..4b053edb7 100644 --- a/resources/views/livewire/source/gitlab/create.blade.php +++ b/resources/views/livewire/source/gitlab/create.blade.php @@ -1,18 +1,70 @@ -
-
+@can('createAnyResource') + +
This is required if you would like to get full integration (deployments from + private repositories, webhooks, etc) with GitLab.
-

New GitLab App

- Save + +
-
Add a self-hosted or GitLab.com instance as a source for your applications.
- - - @if (!isCloud()) - +
+
+ +
+
+ +
+ System-wide GitLab Apps are shared across all teams on this Coolify instance. This means any team + can use this GitLab App to deploy applications from your repositories. For better security and + isolation, it's recommended to create team-specific GitLab Apps instead. +
+
+
+
@endif +
+
+ +
+
+
+ + +
+
+ + +
+
+
+
+
+ + + Continue + -
+@else + + You don't have permission to create new GitLab Apps. Please contact your team administrator for access. + +@endcan diff --git a/tests/Feature/GitlabSourceCreateModalTest.php b/tests/Feature/GitlabSourceCreateModalTest.php new file mode 100644 index 000000000..073fc1b74 --- /dev/null +++ b/tests/Feature/GitlabSourceCreateModalTest.php @@ -0,0 +1,50 @@ +team = Team::factory()->create(); + $this->user = User::factory()->create(); + $this->team->members()->attach($this->user->id, ['role' => 'owner']); + + $this->actingAs($this->user); + session(['currentTeam' => $this->team]); +}); + +describe('GitLab source create modal', function () { + test('matches github create modal structure', function () { + Livewire::test(Create::class) + ->assertSee('This is required if you would like to get full integration') + ->assertSee('Self-hosted GitLab') + ->assertSee('Continue') + ->assertDontSee('>SaveassertDontSeeHtml('

New GitLab App

'); + }); + + test('creates a gitlab app with defaults for gitlab.com', function () { + Livewire::test(Create::class) + ->set('name', 'my-gitlab') + ->call('createGitLabApp') + ->assertRedirect(); + + $app = GitlabApp::where('name', 'my-gitlab')->first(); + expect($app)->not->toBeNull() + ->and($app->html_url)->toBe('https://gitlab.com') + ->and($app->api_url)->toBe('https://gitlab.com/api/v4') + ->and($app->custom_user)->toBe('git') + ->and($app->custom_port)->toBe(22); + }); + + test('derives api url when html url changes', function () { + Livewire::test(Create::class) + ->set('html_url', 'https://gitlab.example.com') + ->assertSet('api_url', 'https://gitlab.example.com/api/v4'); + }); +});