Add project repository connection settings
This commit is contained in:
@@ -7,6 +7,7 @@ use App\Models\Project;
|
||||
use Database\Seeders\BoardColumnSeeder;
|
||||
use Database\Seeders\ProjectSeeder;
|
||||
use Database\Seeders\ProjectTicketMetadataSeeder;
|
||||
use Database\Seeders\RepositoryConnectionSeeder;
|
||||
use Database\Seeders\TicketSeeder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
@@ -141,4 +142,56 @@ class ProjectTest extends TestCase
|
||||
$coreProject->tickets->pluck('ticket_key')->all(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure projects expose linked repository connections in a stable order.
|
||||
*/
|
||||
public function test_projects_expose_repository_connections_in_name_order(): void
|
||||
{
|
||||
$project = Project::factory()->create();
|
||||
|
||||
$project->repositoryConnections()->create([
|
||||
'base_url' => 'https://git.example.test',
|
||||
'owner_name' => 'core-team',
|
||||
'provider' => 'gitea',
|
||||
'provider_repository_id' => '502',
|
||||
'repository_full_name' => 'core-team/platform',
|
||||
'repository_name' => 'platform',
|
||||
'repository_url' => 'https://git.example.test/core-team/platform',
|
||||
]);
|
||||
$project->repositoryConnections()->create([
|
||||
'base_url' => 'https://git.example.test',
|
||||
'owner_name' => 'core-team',
|
||||
'provider' => 'gitea',
|
||||
'provider_repository_id' => '501',
|
||||
'repository_full_name' => 'core-team/kanbangit',
|
||||
'repository_name' => 'kanbangit',
|
||||
'repository_url' => 'https://git.example.test/core-team/kanbangit',
|
||||
]);
|
||||
|
||||
$this->assertSame(
|
||||
['core-team/kanbangit', 'core-team/platform'],
|
||||
$project->fresh()->repositoryConnections->pluck('repository_full_name')->all(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure repository connection seeding adds starter repositories to seeded projects.
|
||||
*/
|
||||
public function test_repository_connection_seeder_adds_repositories_to_seeded_projects(): void
|
||||
{
|
||||
$this->seed([
|
||||
ProjectSeeder::class,
|
||||
RepositoryConnectionSeeder::class,
|
||||
]);
|
||||
|
||||
$coreProject = Project::query()->where('key', 'CORE')->firstOrFail();
|
||||
|
||||
$this->assertDatabaseHas('repository_connections', [
|
||||
'project_id' => $coreProject->id,
|
||||
'provider' => 'gitea',
|
||||
'provider_repository_id' => '501',
|
||||
'repository_full_name' => 'core-team/kanbangit',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Models;
|
||||
|
||||
use App\Actions\Git\GitProviderKey;
|
||||
use App\Models\RepositoryConnection;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class RepositoryConnectionTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
/**
|
||||
* Ensure the repository connection factory creates a project-scoped Gitea link.
|
||||
*/
|
||||
public function test_factory_creates_a_project_repository_connection(): void
|
||||
{
|
||||
$repositoryConnection = RepositoryConnection::factory()->create();
|
||||
|
||||
$this->assertSame(GitProviderKey::Gitea, $repositoryConnection->fresh()->provider);
|
||||
$this->assertNotNull($repositoryConnection->project_id);
|
||||
$this->assertNotSame('', $repositoryConnection->repository_full_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure repository connections belong to a project.
|
||||
*/
|
||||
public function test_repository_connections_belong_to_a_project(): void
|
||||
{
|
||||
$repositoryConnection = RepositoryConnection::factory()->create();
|
||||
|
||||
$this->assertTrue($repositoryConnection->project()->exists());
|
||||
$this->assertTrue($repositoryConnection->project->is($repositoryConnection->fresh()->project));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Projects;
|
||||
|
||||
use App\Actions\Git\GitProviderKey;
|
||||
use App\Actions\ProjectPermissions\ProjectPermissionService;
|
||||
use App\Models\Project;
|
||||
use App\Models\RepositoryConnection;
|
||||
use App\Models\User;
|
||||
use App\Models\UserGitConnection;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ProjectRepositorySettingsControllerTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
/**
|
||||
* Ensure users with edit permission can view repository settings.
|
||||
*/
|
||||
public function test_users_with_edit_permission_can_view_repository_settings(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$project = Project::factory()->create([
|
||||
'key' => 'CORE',
|
||||
]);
|
||||
|
||||
RepositoryConnection::factory()->for($project)->create([
|
||||
'base_url' => 'https://git.example.test',
|
||||
'owner_name' => 'core-team',
|
||||
'provider' => GitProviderKey::Gitea,
|
||||
'provider_repository_id' => '501',
|
||||
'repository_full_name' => 'core-team/kanbangit',
|
||||
'repository_name' => 'kanbangit',
|
||||
'repository_url' => 'https://git.example.test/core-team/kanbangit',
|
||||
]);
|
||||
|
||||
app(ProjectPermissionService::class)->syncUserPermissions($project, $user, ['edit']);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('projects.settings.repositories', $project))
|
||||
->assertOk()
|
||||
->assertInertia(fn (Assert $page) => $page
|
||||
->component('projects/settings/Repositories')
|
||||
->where('project.id', $project->id)
|
||||
->where('repositoryConnections.0.repository_full_name', 'core-team/kanbangit')
|
||||
->where('repositoryConnections.0.has_personal_access', false)
|
||||
->where('availableRepositorySources', []),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure users without edit permission cannot manage repository settings.
|
||||
*/
|
||||
public function test_users_without_edit_permission_cannot_view_repository_settings(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$project = Project::factory()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('projects.settings.repositories', $project))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure authorized users can link a repository through their own Git connection.
|
||||
*/
|
||||
public function test_users_with_edit_permission_can_link_project_repositories(): void
|
||||
{
|
||||
Http::preventStrayRequests();
|
||||
Http::fake([
|
||||
'https://git.example.test/api/v1/user/repos*' => Http::response([
|
||||
[
|
||||
'id' => 501,
|
||||
'name' => 'kanbangit',
|
||||
'full_name' => 'core-team/kanbangit',
|
||||
'html_url' => 'https://git.example.test/core-team/kanbangit',
|
||||
'owner' => [
|
||||
'login' => 'core-team',
|
||||
],
|
||||
'private' => true,
|
||||
],
|
||||
]),
|
||||
]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
$project = Project::factory()->create();
|
||||
$userGitConnection = UserGitConnection::factory()->for($user)->create([
|
||||
'base_url' => 'https://git.example.test',
|
||||
'provider' => GitProviderKey::Gitea,
|
||||
]);
|
||||
|
||||
app(ProjectPermissionService::class)->syncUserPermissions($project, $user, ['edit']);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post(route('projects.settings.repositories.store', $project), [
|
||||
'provider_repository_id' => '501',
|
||||
'user_git_connection_id' => $userGitConnection->id,
|
||||
])
|
||||
->assertRedirect(route('projects.settings.repositories', $project))
|
||||
->assertSessionHas('status', 'core-team/kanbangit was linked to '.$project->name.'.');
|
||||
|
||||
$this->assertDatabaseHas('repository_connections', [
|
||||
'project_id' => $project->id,
|
||||
'provider' => GitProviderKey::Gitea->value,
|
||||
'base_url' => 'https://git.example.test',
|
||||
'provider_repository_id' => '501',
|
||||
'owner_name' => 'core-team',
|
||||
'repository_name' => 'kanbangit',
|
||||
'repository_full_name' => 'core-team/kanbangit',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure users cannot link repositories through another user's Git connection.
|
||||
*/
|
||||
public function test_users_cannot_link_repositories_through_foreign_git_connections(): void
|
||||
{
|
||||
Http::preventStrayRequests();
|
||||
Http::fake();
|
||||
|
||||
$user = User::factory()->create();
|
||||
$otherUser = User::factory()->create();
|
||||
$project = Project::factory()->create();
|
||||
$foreignGitConnection = UserGitConnection::factory()->for($otherUser)->create();
|
||||
|
||||
app(ProjectPermissionService::class)->syncUserPermissions($project, $user, ['edit']);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post(route('projects.settings.repositories.store', $project), [
|
||||
'provider_repository_id' => '501',
|
||||
'user_git_connection_id' => $foreignGitConnection->id,
|
||||
])
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure authorized users can relink an existing project repository.
|
||||
*/
|
||||
public function test_users_with_edit_permission_can_update_repository_connections(): void
|
||||
{
|
||||
Http::preventStrayRequests();
|
||||
Http::fake([
|
||||
'https://git.internal.test/api/v1/user/repos*' => Http::response([
|
||||
[
|
||||
'id' => 902,
|
||||
'name' => 'platform',
|
||||
'full_name' => 'infra/platform',
|
||||
'html_url' => 'https://git.internal.test/infra/platform',
|
||||
'owner' => [
|
||||
'login' => 'infra',
|
||||
],
|
||||
'private' => false,
|
||||
],
|
||||
]),
|
||||
]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
$project = Project::factory()->create();
|
||||
$repositoryConnection = RepositoryConnection::factory()->for($project)->create([
|
||||
'base_url' => 'https://git.example.test',
|
||||
'owner_name' => 'core-team',
|
||||
'provider' => GitProviderKey::Gitea,
|
||||
'provider_repository_id' => '501',
|
||||
'repository_full_name' => 'core-team/kanbangit',
|
||||
'repository_name' => 'kanbangit',
|
||||
'repository_url' => 'https://git.example.test/core-team/kanbangit',
|
||||
]);
|
||||
$userGitConnection = UserGitConnection::factory()->for($user)->create([
|
||||
'base_url' => 'https://git.internal.test',
|
||||
'provider' => GitProviderKey::Gitea,
|
||||
]);
|
||||
|
||||
app(ProjectPermissionService::class)->syncUserPermissions($project, $user, ['edit']);
|
||||
|
||||
$this->actingAs($user)
|
||||
->patch(route('projects.settings.repositories.update', [$project, $repositoryConnection]), [
|
||||
'provider_repository_id' => '902',
|
||||
'user_git_connection_id' => $userGitConnection->id,
|
||||
])
|
||||
->assertRedirect(route('projects.settings.repositories', $project))
|
||||
->assertSessionHas('status', 'infra/platform connection was updated.');
|
||||
|
||||
$this->assertDatabaseHas('repository_connections', [
|
||||
'id' => $repositoryConnection->id,
|
||||
'base_url' => 'https://git.internal.test',
|
||||
'provider_repository_id' => '902',
|
||||
'owner_name' => 'infra',
|
||||
'repository_name' => 'platform',
|
||||
'repository_full_name' => 'infra/platform',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure authorized users can remove project repository links.
|
||||
*/
|
||||
public function test_users_with_edit_permission_can_delete_repository_connections(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$project = Project::factory()->create();
|
||||
$repositoryConnection = RepositoryConnection::factory()->for($project)->create([
|
||||
'repository_full_name' => 'core-team/kanbangit',
|
||||
]);
|
||||
|
||||
app(ProjectPermissionService::class)->syncUserPermissions($project, $user, ['edit']);
|
||||
|
||||
$this->actingAs($user)
|
||||
->delete(route('projects.settings.repositories.destroy', [$project, $repositoryConnection]))
|
||||
->assertRedirect(route('projects.settings.repositories', $project))
|
||||
->assertSessionHas('status', 'core-team/kanbangit was removed from the project.');
|
||||
|
||||
$this->assertDatabaseMissing('repository_connections', [
|
||||
'id' => $repositoryConnection->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user