Skip to content
Snippets Groups Projects
Commit 3cb316b2 authored by charlie ablett's avatar charlie ablett :tools:
Browse files

Merge branch 'mmj-rest-api-for-project-transfer-locations' into 'master'

Introduce REST API for project transfer locations

See merge request gitlab-org/gitlab!95572
parents faa2811e ad8a8d09
No related branches found
No related tags found
2 merge requests!95848Draft: Add service to bulk process alerts,!95572Introduce REST API for project transfer locations
Pipeline #620379510 passed
...@@ -2596,6 +2596,50 @@ DELETE /projects/:id/push_rule ...@@ -2596,6 +2596,50 @@ DELETE /projects/:id/push_rule
|-----------|----------------|------------------------|-------------| |-----------|----------------|------------------------|-------------|
| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). | | `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
## Get groups to which a user can transfer a project
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/371006) in GitLab 15.4
Retrieve a list of groups to which the user can transfer a project.
```plaintext
GET /projects/:id/transfer_locations
```
| Attribute | Type | Required | Description |
|-------------|----------------|------------------------|-------------|
| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
| `search` | string | **{dotted-circle}** No | The group names to search for. |
Example request:
```shell
curl --request GET "https://gitlab.example.com/api/v4/projects/1/transfer_locations"
```
Example response:
```json
[
{
"id": 27,
"web_url": "https://gitlab.example.com/groups/gitlab",
"name": "GitLab",
"avatar_url": null,
"full_name": "GitLab",
"full_path": "GitLab"
},
{
"id": 31,
"web_url": "https://gitlab.example.com/groups/foobar",
"name": "FooBar",
"avatar_url": null,
"full_name": "FooBar",
"full_path": "FooBar"
}
]
```
## Transfer a project to a new namespace ## Transfer a project to a new namespace
> The `_links.cluster_agents` attribute in the response [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/347047) in GitLab 14.10. > The `_links.cluster_agents` attribute in the response [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/347047) in GitLab 14.10.
......
...@@ -743,6 +743,22 @@ def add_import_params(params) ...@@ -743,6 +743,22 @@ def add_import_params(params)
end end
end end
desc 'Get the namespaces to where the project can be transferred'
params do
optional :search, type: String, desc: 'Return list of namespaces matching the search criteria'
use :pagination
end
get ":id/transfer_locations", feature_category: :projects do
authorize! :change_namespace, user_project
args = declared_params(include_missing: false)
args[:permission_scope] = :transfer_projects
groups = ::Groups::UserGroupsFinder.new(current_user, current_user, args).execute
groups = groups.with_route
present_groups(groups)
end
desc 'Show the storage information' do desc 'Show the storage information' do
success Entities::ProjectRepositoryStorage success Entities::ProjectRepositoryStorage
end end
......
...@@ -4646,6 +4646,112 @@ def failure_message(diff) ...@@ -4646,6 +4646,112 @@ def failure_message(diff)
end end
end end
describe 'GET /projects/:id/transfer_locations' do
let_it_be(:user) { create(:user) }
let_it_be(:source_group) { create(:group) }
let_it_be(:project) { create(:project, group: source_group) }
let(:params) { {} }
subject(:request) do
get api("/projects/#{project.id}/transfer_locations", user), params: params
end
context 'when the user has rights to transfer the project' do
let_it_be(:guest_group) { create(:group) }
let_it_be(:maintainer_group) { create(:group, name: 'maintainer group', path: 'maintainer-group') }
let_it_be(:owner_group) { create(:group, name: 'owner group', path: 'owner-group') }
before do
source_group.add_owner(user)
guest_group.add_guest(user)
maintainer_group.add_maintainer(user)
owner_group.add_owner(user)
end
it 'returns 200' do
request
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
end
it 'includes groups where the user has permissions to transfer a project to' do
request
expect(project_ids_from_response).to include(maintainer_group.id, owner_group.id)
end
it 'does not include groups where the user doesn not have permissions to transfer a project' do
request
expect(project_ids_from_response).not_to include(guest_group.id)
end
context 'with search' do
let(:params) { { search: 'maintainer' } }
it 'includes groups where the user has permissions to transfer a project to' do
request
expect(project_ids_from_response).to contain_exactly(maintainer_group.id)
end
end
context 'group shares' do
let_it_be(:shared_to_owner_group) { create(:group) }
let_it_be(:shared_to_guest_group) { create(:group) }
before do
create(:group_group_link, :owner,
shared_with_group: owner_group,
shared_group: shared_to_owner_group
)
create(:group_group_link, :guest,
shared_with_group: guest_group,
shared_group: shared_to_guest_group
)
end
it 'only includes groups arising from group shares where the user has permission to transfer a project to' do
request
expect(project_ids_from_response).to include(shared_to_owner_group.id)
expect(project_ids_from_response).not_to include(shared_to_guest_group.id)
end
context 'when the feature flag `include_groups_from_group_shares_in_project_transfer_locations` is disabled' do
before do
stub_feature_flags(include_groups_from_group_shares_in_project_transfer_locations: false)
end
it 'does not include any groups arising from group shares' do
request
expect(project_ids_from_response).not_to include(shared_to_owner_group.id, shared_to_guest_group.id)
end
end
end
def project_ids_from_response
json_response.map { |project| project['id'] }
end
end
context 'when the user does not have permissions to transfer the project' do
before do
source_group.add_developer(user)
end
it 'returns 403' do
request
expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
describe 'GET /projects/:id/storage' do describe 'GET /projects/:id/storage' do
context 'when unauthenticated' do context 'when unauthenticated' do
it 'does not return project storage data' do it 'does not return project storage data' do
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment