Commit 63e0a423 authored by Mark Fletcher's avatar Mark Fletcher

Add an API endpoint to determine the forks of a project

parent 5f331ab7
---
title: Add an API endpoint to determine the forks of a project
merge_request:
author:
type: added
...@@ -635,6 +635,98 @@ POST /projects/:id/fork ...@@ -635,6 +635,98 @@ POST /projects/:id/fork
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `namespace` | integer/string | yes | The ID or path of the namespace that the project will be forked to | | `namespace` | integer/string | yes | The ID or path of the namespace that the project will be forked to |
## List Forks of a project
>**Note:** This feature was introduced in GitLab 10.1
List the projects accessible to the calling user that have an established, forked relationship with the specified project
```
GET /projects/:id/forks
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `archived` | boolean | no | Limit by archived status |
| `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
| `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
| `search` | string | no | Return list of projects matching the search criteria |
| `simple` | boolean | no | Return only the ID, URL, name, and path of each project |
| `owned` | boolean | no | Limit by projects owned by the current user |
| `membership` | boolean | no | Limit by projects that the current user is a member of |
| `starred` | boolean | no | Limit by projects starred by the current user |
| `statistics` | boolean | no | Include project statistics |
| `with_issues_enabled` | boolean | no | Limit by enabled issues feature |
| `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature |
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/forks"
```
Example responses:
```json
[
{
"id": 3,
"description": null,
"default_branch": "master",
"visibility": "internal",
"ssh_url_to_repo": "git@example.com:diaspora/diaspora-project-site.git",
"http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git",
"web_url": "http://example.com/diaspora/diaspora-project-site",
"tag_list": [
"example",
"disapora project"
],
"name": "Diaspora Project Site",
"name_with_namespace": "Diaspora / Diaspora Project Site",
"path": "diaspora-project-site",
"path_with_namespace": "diaspora/diaspora-project-site",
"issues_enabled": true,
"open_issues_count": 1,
"merge_requests_enabled": true,
"jobs_enabled": true,
"wiki_enabled": true,
"snippets_enabled": false,
"resolve_outdated_diff_discussions": false,
"container_registry_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
"creator_id": 3,
"namespace": {
"id": 3,
"name": "Diaspora",
"path": "diaspora",
"kind": "group",
"full_path": "diaspora"
},
"import_status": "none",
"archived": true,
"avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png",
"shared_runners_enabled": true,
"forks_count": 0,
"star_count": 1,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
"request_access_enabled": false,
"_links": {
"self": "http://example.com/api/v4/projects",
"issues": "http://example.com/api/v4/projects/1/issues",
"merge_requests": "http://example.com/api/v4/projects/1/merge_requests",
"repo_branches": "http://example.com/api/v4/projects/1/repository_branches",
"labels": "http://example.com/api/v4/projects/1/labels",
"events": "http://example.com/api/v4/projects/1/events",
"members": "http://example.com/api/v4/projects/1/members"
}
}
]
```
## Star a project ## Star a project
Stars a given project. Returns status code `304` if the project is already starred. Stars a given project. Returns status code `304` if the project is already starred.
......
...@@ -70,8 +70,11 @@ module API ...@@ -70,8 +70,11 @@ module API
optional :import_url, type: String, desc: 'URL from which the project is imported' optional :import_url, type: String, desc: 'URL from which the project is imported'
end end
def present_projects(options = {}) def load_projects
projects = ProjectsFinder.new(current_user: current_user, params: project_finder_params).execute ProjectsFinder.new(current_user: current_user, params: project_finder_params).execute
end
def present_projects(projects, options = {})
projects = reorder_projects(projects) projects = reorder_projects(projects)
projects = projects.with_statistics if params[:statistics] projects = projects.with_statistics if params[:statistics]
projects = projects.with_issues_enabled if params[:with_issues_enabled] projects = projects.with_issues_enabled if params[:with_issues_enabled]
...@@ -111,7 +114,7 @@ module API ...@@ -111,7 +114,7 @@ module API
params[:user] = user params[:user] = user
present_projects present_projects load_projects
end end
end end
...@@ -124,7 +127,7 @@ module API ...@@ -124,7 +127,7 @@ module API
use :statistics_params use :statistics_params
end end
get do get do
present_projects present_projects load_projects
end end
desc 'Create new project' do desc 'Create new project' do
...@@ -229,6 +232,18 @@ module API ...@@ -229,6 +232,18 @@ module API
end end
end end
desc 'List forks of this project' do
success Entities::Project
end
params do
use :collection_params
end
get ':id/forks' do
forks = ForkProjectsFinder.new(user_project, params: project_finder_params, current_user: current_user).execute
present_projects forks
end
desc 'Update an existing project' do desc 'Update an existing project' do
success Entities::Project success Entities::Project
end end
......
...@@ -1181,6 +1181,59 @@ describe API::Projects do ...@@ -1181,6 +1181,59 @@ describe API::Projects do
end end
end end
end end
describe 'GET /projects/:id/forks' do
let(:private_fork) { create(:project, :private, :empty_repo) }
let(:member) { create(:user) }
let(:non_member) { create(:user) }
before do
private_fork.add_developer(member)
end
context 'for a forked project' do
before do
post api("/projects/#{private_fork.id}/fork/#{project_fork_source.id}", admin)
private_fork.reload
expect(private_fork.forked_from_project).not_to be_nil
expect(private_fork.forked?).to be_truthy
project_fork_source.reload
expect(project_fork_source.forks.length).to eq(1)
expect(project_fork_source.forks).to include(private_fork)
end
context 'for a user that can access the forks' do
it 'returns the forks' do
get api("/projects/#{project_fork_source.id}/forks", member)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(1)
expect(json_response[0]['name']).to eq(private_fork.name)
end
end
context 'for a user that cannot access the forks' do
it 'returns an empty array' do
get api("/projects/#{project_fork_source.id}/forks", non_member)
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(0)
end
end
end
context 'for a non-forked project' do
it 'returns an empty array' do
get api("/projects/#{project_fork_source.id}/forks")
expect(response).to have_http_status(200)
expect(response).to include_pagination_headers
expect(json_response.length).to eq(0)
end
end
end
end end
describe "POST /projects/:id/share" do describe "POST /projects/:id/share" do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment