From 0530ec5e6ec324c5b1dd6e450a534b204cae2118 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 8 Jul 2016 09:34:36 +0200 Subject: Expose shared groups for projects --- CHANGELOG | 1 + doc/api/groups.md | 72 ++++++++++++++++++++------------------ doc/api/projects.md | 37 ++++++++++++++++---- lib/api/entities.rb | 11 ++++++ spec/requests/api/projects_spec.rb | 40 +++++++++++++++++++-- 5 files changed, 118 insertions(+), 43 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 491692204a6..88ae6ed37a6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,7 @@ v 8.10.0 (unreleased) - Add notification settings dropdown for groups - Allow importing from Github using Personal Access Tokens. (Eric K Idema) - API: Todos !3188 (Robert Schilling) + - API: Expose shared groups for projects !5148 (Robert Schilling) - Add "Enabled Git access protocols" to Application Settings - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - PipelinesFinder uses git cache data diff --git a/doc/api/groups.md b/doc/api/groups.md index 1ccb9715e96..eaff3fa044e 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -42,46 +42,49 @@ Parameters: ```json [ { - "id": 4, - "description": null, + "id": 9, + "description": "foo", "default_branch": "master", + "tag_list": [], "public": false, - "visibility_level": 0, - "ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git", - "http_url_to_repo": "http://example.com/diaspora/diaspora-client.git", - "web_url": "http://example.com/diaspora/diaspora-client", - "tag_list": [ - "example", - "disapora client" - ], - "owner": { - "id": 3, - "name": "Diaspora", - "created_at": "2013-09-30T13: 46: 02Z" - }, - "name": "Diaspora Client", - "name_with_namespace": "Diaspora / Diaspora Client", - "path": "diaspora-client", - "path_with_namespace": "diaspora/diaspora-client", + "archived": false, + "visibility_level": 10, + "ssh_url_to_repo": "git@gitlab.example.com/html5-boilerplate.git", + "http_url_to_repo": "http://gitlab.example.com/h5bp/html5-boilerplate.git", + "web_url": "http://gitlab.example.com/h5bp/html5-boilerplate", + "name": "Html5 Boilerplate", + "name_with_namespace": "Experimental / Html5 Boilerplate", + "path": "html5-boilerplate", + "path_with_namespace": "h5bp/html5-boilerplate", "issues_enabled": true, "merge_requests_enabled": true, - "builds_enabled": true, "wiki_enabled": true, - "snippets_enabled": false, - "created_at": "2013-09-30T13: 46: 02Z", - "last_activity_at": "2013-09-30T13: 46: 02Z", - "creator_id": 3, + "builds_enabled": true, + "snippets_enabled": true, + "created_at": "2016-04-05T21:40:50.169Z", + "last_activity_at": "2016-04-06T16:52:08.432Z", + "shared_runners_enabled": true, + "creator_id": 1, "namespace": { - "created_at": "2013-09-30T13: 46: 02Z", - "description": "", - "id": 3, - "name": "Diaspora", - "owner_id": 1, - "path": "diaspora", - "updated_at": "2013-09-30T13: 46: 02Z" + "id": 5, + "name": "Experimental", + "path": "h5bp", + "owner_id": null, + "created_at": "2016-04-05T21:40:49.152Z", + "updated_at": "2016-04-07T08:07:48.466Z", + "description": "foo", + "avatar": { + "url": null + }, + "share_with_group_lock": false, + "visibility_level": 10 }, - "archived": false, - "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png" + "avatar_url": null, + "star_count": 1, + "forks_count": 0, + "open_issues_count": 3, + "public_builds": true, + "shared_with_groups": [] } ] ``` @@ -201,7 +204,8 @@ Example response: "star_count": 1, "forks_count": 0, "open_issues_count": 3, - "public_builds": true + "public_builds": true, + "shared_with_groups": [] } ] } diff --git a/doc/api/projects.md b/doc/api/projects.md index f5f195b97df..bf30aa28a14 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -82,7 +82,8 @@ Parameters: "forks_count": 0, "star_count": 0, "runners_token": "b8547b1dc37721d05889db52fa2f02", - "public_builds": true + "public_builds": true, + "shared_with_groups": [] }, { "id": 6, @@ -140,7 +141,8 @@ Parameters: "forks_count": 0, "star_count": 0, "runners_token": "b8547b1dc37721d05889db52fa2f02", - "public_builds": true + "public_builds": true, + "shared_with_groups": [] } ] ``` @@ -262,7 +264,20 @@ Parameters: "shared_runners_enabled": true, "forks_count": 0, "star_count": 0, - "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b" + "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b", + "public_builds": true, + "shared_with_groups": [ + { + "group_id": 4, + "group_name": "Twitter", + "group_access_level": 30 + }, + { + "group_id": 3, + "group_name": "Gitlab Org", + "group_access_level": 10 + } + ] } ``` @@ -553,7 +568,9 @@ Example response: "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", "shared_runners_enabled": true, "forks_count": 0, - "star_count": 1 + "star_count": 1, + "public_builds": true, + "shared_with_groups": [] } ``` @@ -616,7 +633,9 @@ Example response: "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", "shared_runners_enabled": true, "forks_count": 0, - "star_count": 0 + "star_count": 0, + "public_builds": true, + "shared_with_groups": [] } ``` @@ -699,7 +718,9 @@ Example response: "shared_runners_enabled": true, "forks_count": 0, "star_count": 0, - "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b" + "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b", + "public_builds": true, + "shared_with_groups": [] } ``` @@ -782,7 +803,9 @@ Example response: "shared_runners_enabled": true, "forks_count": 0, "star_count": 0, - "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b" + "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b", + "public_builds": true, + "shared_with_groups": [] } ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index db877d2eeb0..90e51c29339 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -58,6 +58,14 @@ module API expose :path, :path_with_namespace end + class SharedGroup < Grape::Entity + expose :group_id + expose :group_name do |group_link, options| + group_link.group.name + end + expose :group_access, as: :group_access_level + end + class Project < Grape::Entity expose :id, :description, :default_branch, :tag_list expose :public?, as: :public @@ -77,6 +85,9 @@ module API expose :open_issues_count, if: lambda { |project, options| project.issues_enabled? && project.default_issues_tracker? } expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] } expose :public_builds + expose :shared_with_groups do |project, options| + SharedGroup.represent(project.project_group_links.all, options) + end end class ProjectMember < UserBasic diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 611dd2a2a88..8a52725a893 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -392,11 +392,47 @@ describe API::API, api: true do before { project } before { project_member } - it 'should return a project by id' do + it 'returns a project by id' do + group = create(:group) + link = create(:project_group_link, project: project, group: group) + get api("/projects/#{project.id}", user) + expect(response).to have_http_status(200) + expect(json_response['id']).to eq(project.id) + expect(json_response['description']).to eq(project.description) + expect(json_response['default_branch']).to eq(project.default_branch) + expect(json_response['tag_list']).to be_an Array + expect(json_response['public']).to be_falsey + expect(json_response['archived']).to be_falsey + expect(json_response['visibility_level']).to be_present + expect(json_response['ssh_url_to_repo']).to be_present + expect(json_response['http_url_to_repo']).to be_present + expect(json_response['web_url']).to be_present + expect(json_response['owner']).to be_a Hash + expect(json_response['owner']).to be_a Hash expect(json_response['name']).to eq(project.name) - expect(json_response['owner']['username']).to eq(user.username) + expect(json_response['path']).to be_present + expect(json_response['issues_enabled']).to be_present + expect(json_response['merge_requests_enabled']).to be_present + expect(json_response['wiki_enabled']).to be_present + expect(json_response['builds_enabled']).to be_present + expect(json_response['snippets_enabled']).to be_present + expect(json_response['container_registry_enabled']).to be_present + expect(json_response['created_at']).to be_present + expect(json_response['last_activity_at']).to be_present + expect(json_response['shared_runners_enabled']).to be_present + expect(json_response['creator_id']).to be_present + expect(json_response['namespace']).to be_present + expect(json_response['avatar_url']).to be_nil + expect(json_response['star_count']).to be_present + expect(json_response['forks_count']).to be_present + expect(json_response['public_builds']).to be_present + expect(json_response['shared_with_groups']).to be_an Array + expect(json_response['shared_with_groups'].length).to eq(1) + expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id) + expect(json_response['shared_with_groups'][0]['group_name']).to eq(group.name) + expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access) end it 'should return a project by path name' do -- cgit v1.2.1 From 33124b4b500df904b91c74f3fdf4123fb27631a6 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 8 Jul 2016 10:59:52 +0200 Subject: API: Expose shared projects in a group --- CHANGELOG | 2 +- doc/api/groups.md | 175 ++++++++++++++++++++++++++++++++++++++- lib/api/entities.rb | 1 + spec/requests/api/groups_spec.rb | 19 ++++- 4 files changed, 193 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 88ae6ed37a6..c044246eeeb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,7 +27,7 @@ v 8.10.0 (unreleased) - Add notification settings dropdown for groups - Allow importing from Github using Personal Access Tokens. (Eric K Idema) - API: Todos !3188 (Robert Schilling) - - API: Expose shared groups for projects !5148 (Robert Schilling) + - API: Expose shared groups for projects and shared projects for groups !5050 (Robert Schilling) - Add "Enabled Git access protocols" to Application Settings - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - PipelinesFinder uses git cache data diff --git a/doc/api/groups.md b/doc/api/groups.md index eaff3fa044e..87480bebfc4 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -99,7 +99,180 @@ GET /groups/:id Parameters: -- `id` (required) - The ID or path of a group +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer/string | yes | The ID or path of a group | + +```bash +curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/groups/4 +``` + +Example response: + +```json +{ + "id": 4, + "name": "Twitter", + "path": "twitter", + "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.", + "visibility_level": 20, + "avatar_url": null, + "web_url": "https://gitlab.example.com/groups/twitter", + "projects": [ + { + "id": 7, + "description": "Voluptas veniam qui et beatae voluptas doloremque explicabo facilis.", + "default_branch": "master", + "tag_list": [], + "public": true, + "archived": false, + "visibility_level": 20, + "ssh_url_to_repo": "git@gitlab.example.com:twitter/typeahead-js.git", + "http_url_to_repo": "https://gitlab.example.com/twitter/typeahead-js.git", + "web_url": "https://gitlab.example.com/twitter/typeahead-js", + "name": "Typeahead.Js", + "name_with_namespace": "Twitter / Typeahead.Js", + "path": "typeahead-js", + "path_with_namespace": "twitter/typeahead-js", + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "builds_enabled": true, + "snippets_enabled": false, + "container_registry_enabled": true, + "created_at": "2016-06-17T07:47:25.578Z", + "last_activity_at": "2016-06-17T07:47:25.881Z", + "shared_runners_enabled": true, + "creator_id": 1, + "namespace": { + "id": 4, + "name": "Twitter", + "path": "twitter", + "owner_id": null, + "created_at": "2016-06-17T07:47:24.216Z", + "updated_at": "2016-06-17T07:47:24.216Z", + "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.", + "avatar": { + "url": null + }, + "share_with_group_lock": false, + "visibility_level": 20 + }, + "avatar_url": null, + "star_count": 0, + "forks_count": 0, + "open_issues_count": 3, + "public_builds": true, + "shared_with_groups": [] + }, + { + "id": 6, + "description": "Aspernatur omnis repudiandae qui voluptatibus eaque.", + "default_branch": "master", + "tag_list": [], + "public": false, + "archived": false, + "visibility_level": 10, + "ssh_url_to_repo": "git@gitlab.example.com:twitter/flight.git", + "http_url_to_repo": "https://gitlab.example.com/twitter/flight.git", + "web_url": "https://gitlab.example.com/twitter/flight", + "name": "Flight", + "name_with_namespace": "Twitter / Flight", + "path": "flight", + "path_with_namespace": "twitter/flight", + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "builds_enabled": true, + "snippets_enabled": false, + "container_registry_enabled": true, + "created_at": "2016-06-17T07:47:24.661Z", + "last_activity_at": "2016-06-17T07:47:24.838Z", + "shared_runners_enabled": true, + "creator_id": 1, + "namespace": { + "id": 4, + "name": "Twitter", + "path": "twitter", + "owner_id": null, + "created_at": "2016-06-17T07:47:24.216Z", + "updated_at": "2016-06-17T07:47:24.216Z", + "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.", + "avatar": { + "url": null + }, + "share_with_group_lock": false, + "visibility_level": 20 + }, + "avatar_url": null, + "star_count": 0, + "forks_count": 0, + "open_issues_count": 8, + "public_builds": true, + "shared_with_groups": [] + } + ], + "shared_projects": [ + { + "id": 8, + "description": "Velit eveniet provident fugiat saepe eligendi autem.", + "default_branch": "master", + "tag_list": [], + "public": false, + "archived": false, + "visibility_level": 0, + "ssh_url_to_repo": "git@gitlab.example.com:h5bp/html5-boilerplate.git", + "http_url_to_repo": "https://gitlab.example.com/h5bp/html5-boilerplate.git", + "web_url": "https://gitlab.example.com/h5bp/html5-boilerplate", + "name": "Html5 Boilerplate", + "name_with_namespace": "H5bp / Html5 Boilerplate", + "path": "html5-boilerplate", + "path_with_namespace": "h5bp/html5-boilerplate", + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "builds_enabled": true, + "snippets_enabled": false, + "container_registry_enabled": true, + "created_at": "2016-06-17T07:47:27.089Z", + "last_activity_at": "2016-06-17T07:47:27.310Z", + "shared_runners_enabled": true, + "creator_id": 1, + "namespace": { + "id": 5, + "name": "H5bp", + "path": "h5bp", + "owner_id": null, + "created_at": "2016-06-17T07:47:26.621Z", + "updated_at": "2016-06-17T07:47:26.621Z", + "description": "Id consequatur rem vel qui doloremque saepe.", + "avatar": { + "url": null + }, + "share_with_group_lock": false, + "visibility_level": 20 + }, + "avatar_url": null, + "star_count": 0, + "forks_count": 0, + "open_issues_count": 4, + "public_builds": true, + "shared_with_groups": [ + { + "group_id": 4, + "group_name": "Twitter", + "group_access_level": 30 + }, + { + "group_id": 3, + "group_name": "Gitlab Org", + "group_access_level": 10 + } + ] + } + ] +} +``` ## New group diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 90e51c29339..9076a0c3831 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -104,6 +104,7 @@ module API class GroupDetail < Group expose :projects, using: Entities::Project + expose :shared_projects, using: Entities::Project end class GroupMember < UserBasic diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 04141a45031..c2c94040ece 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -49,10 +49,25 @@ describe API::API, api: true do describe "GET /groups/:id" do context "when authenticated as user" do - it "should return one of user1's groups" do + it "returns one of user1's groups" do + project = create(:project, namespace: group2, path: 'Foo') + create(:project_group_link, project: project, group: group1) + get api("/groups/#{group1.id}", user1) + expect(response).to have_http_status(200) - json_response['name'] == group1.name + expect(json_response['id']).to eq(group1.id) + expect(json_response['name']).to eq(group1.name) + expect(json_response['path']).to eq(group1.path) + expect(json_response['description']).to eq(group1.description) + expect(json_response['visibility_level']).to eq(group1.visibility_level) + expect(json_response['avatar_url']).to eq(group1.avatar_url) + expect(json_response['web_url']).to eq(group1.web_url) + expect(json_response['projects']).to be_an Array + expect(json_response['projects'].length).to eq(2) + expect(json_response['shared_projects']).to be_an Array + expect(json_response['shared_projects'].length).to eq(1) + expect(json_response['shared_projects'][0]['id']).to eq(project.id) end it "should not return a non existing group" do -- cgit v1.2.1