diff options
Diffstat (limited to 'spec/requests/api/projects_spec.rb')
-rw-r--r-- | spec/requests/api/projects_spec.rb | 1461 |
1 files changed, 730 insertions, 731 deletions
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 856fe1bbe89..3be8b890780 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1,19 +1,18 @@ -# -*- coding: utf-8 -*- -require 'spec_helper' +require "spec_helper" -shared_examples 'languages and percentages JSON response' do +shared_examples "languages and percentages JSON response" do let(:expected_languages) { project.repository.languages.map { |language| language.values_at(:label, :value)}.to_h } before do allow(project.repository).to receive(:languages).and_return( - [{ value: 66.69, label: "Ruby", color: "#701516", highlight: "#701516" }, - { value: 22.98, label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" }, - { value: 7.91, label: "HTML", color: "#e34c26", highlight: "#e34c26" }, - { value: 2.42, label: "CoffeeScript", color: "#244776", highlight: "#244776" }] + [{value: 66.69, label: "Ruby", color: "#701516", highlight: "#701516"}, + {value: 22.98, label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a"}, + {value: 7.91, label: "HTML", color: "#e34c26", highlight: "#e34c26"}, + {value: 2.42, label: "CoffeeScript", color: "#244776", highlight: "#244776"},] ) end - it 'returns expected language values' do + it "returns expected language values" do get api("/projects/#{project.id}/languages", user) expect(response).to have_gitlab_http_status(:ok) @@ -21,12 +20,12 @@ shared_examples 'languages and percentages JSON response' do expect(json_response.count).to be > 1 end - context 'when the languages were detected before' do + context "when the languages were detected before" do before do Projects::DetectRepositoryLanguagesService.new(project, project.owner).execute end - it 'returns the detection from the database' do + it "returns the detection from the database" do # Allow this to happen once, so the expected languages can be determined expect(project.repository).to receive(:languages).once @@ -47,43 +46,43 @@ describe API::Projects do let(:project) { create(:project, :repository, namespace: user.namespace) } let(:project2) { create(:project, namespace: user.namespace) } let(:project_member) { create(:project_member, :developer, user: user3, project: project) } - let(:user4) { create(:user, username: 'user.with.dot') } + let(:user4) { create(:user, username: "user.with.dot") } let(:project3) do create(:project, - :private, - :repository, - name: 'second_project', - path: 'second_project', - creator_id: user.id, - namespace: user.namespace, - merge_requests_enabled: false, - issues_enabled: false, wiki_enabled: false, - builds_enabled: false, - snippets_enabled: false) + :private, + :repository, + name: "second_project", + path: "second_project", + creator_id: user.id, + namespace: user.namespace, + merge_requests_enabled: false, + issues_enabled: false, wiki_enabled: false, + builds_enabled: false, + snippets_enabled: false) end let(:project_member2) do create(:project_member, - user: user4, - project: project3, - access_level: ProjectMember::MAINTAINER) + user: user4, + project: project3, + access_level: ProjectMember::MAINTAINER) end let(:project4) do create(:project, - name: 'third_project', - path: 'third_project', - creator_id: user4.id, - namespace: user4.namespace) + name: "third_project", + path: "third_project", + creator_id: user4.id, + namespace: user4.namespace) end - shared_context 'with language detection' do - let(:ruby) { create(:programming_language, name: 'Ruby') } - let(:javascript) { create(:programming_language, name: 'JavaScript') } - let(:html) { create(:programming_language, name: 'HTML') } + shared_context "with language detection" do + let(:ruby) { create(:programming_language, name: "Ruby") } + let(:javascript) { create(:programming_language, name: "JavaScript") } + let(:html) { create(:programming_language, name: "HTML") } let(:mock_repo_languages) do { - project => { ruby => 0.5, html => 0.5 }, - project3 => { html => 0.7, javascript => 0.3 } + project => {ruby => 0.5, html => 0.5}, + project3 => {html => 0.7, javascript => 0.3}, } end @@ -96,29 +95,29 @@ describe API::Projects do end end - describe 'GET /projects' do - shared_examples_for 'projects response' do - it 'returns an array of projects' do - get api('/projects', current_user), params: filter + describe "GET /projects" do + shared_examples_for "projects response" do + it "returns an array of projects" do + get api("/projects", current_user), params: filter expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |p| p['id'] }).to contain_exactly(*projects.map(&:id)) + expect(json_response.map { |p| p["id"] }).to contain_exactly(*projects.map(&:id)) end - it 'returns the proper security headers' do - get api('/projects', current_user), params: filter + it "returns the proper security headers" do + get api("/projects", current_user), params: filter expect(response).to include_security_headers end end - shared_examples_for 'projects response without N + 1 queries' do - it 'avoids N + 1 queries' do - control = ActiveRecord::QueryRecorder.new do - get api('/projects', current_user) - end + shared_examples_for "projects response without N + 1 queries" do + it "avoids N + 1 queries" do + control = ActiveRecord::QueryRecorder.new { + get api("/projects", current_user) + } if defined?(additional_project) additional_project @@ -129,13 +128,13 @@ describe API::Projects do # TODO: We're currently querying to detect if a project is a fork # in 2 ways. Lower this back to 8 when `ForkedProjectLink` relation is # removed - expect do - get api('/projects', current_user) - end.not_to exceed_query_limit(control).with_threshold(9) + expect { + get api("/projects", current_user) + }.not_to exceed_query_limit(control).with_threshold(9) end end - let!(:public_project) { create(:project, :public, name: 'public_project') } + let!(:public_project) { create(:project, :public, name: "public_project") } before do project project2 @@ -143,156 +142,156 @@ describe API::Projects do project4 end - context 'when unauthenticated' do - it_behaves_like 'projects response' do - let(:filter) { { search: project.name } } + context "when unauthenticated" do + it_behaves_like "projects response" do + let(:filter) { {search: project.name} } let(:current_user) { user } let(:projects) { [project] } end - it_behaves_like 'projects response without N + 1 queries' do + it_behaves_like "projects response without N + 1 queries" do let(:current_user) { nil } end end - context 'when authenticated as regular user' do - it_behaves_like 'projects response' do + context "when authenticated as regular user" do + it_behaves_like "projects response" do let(:filter) { {} } let(:current_user) { user } let(:projects) { [public_project, project, project2, project3] } end - it_behaves_like 'projects response without N + 1 queries' do + it_behaves_like "projects response without N + 1 queries" do let(:current_user) { user } end - context 'when some projects are in a group' do + context "when some projects are in a group" do before do create(:project, :public, group: create(:group)) end - it_behaves_like 'projects response without N + 1 queries' do + it_behaves_like "projects response without N + 1 queries" do let(:current_user) { user } let(:additional_project) { create(:project, :public, group: create(:group)) } end end - it 'includes the project labels as the tag_list' do - get api('/projects', user) + it "includes the project labels as the tag_list" do + get api("/projects", user) expect(response.status).to eq 200 expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.first.keys).to include('tag_list') + expect(json_response.first.keys).to include("tag_list") end - it 'includes open_issues_count' do - get api('/projects', user) + it "includes open_issues_count" do + get api("/projects", user) expect(response.status).to eq 200 expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.first.keys).to include('open_issues_count') + expect(json_response.first.keys).to include("open_issues_count") end - it 'does not include projects marked for deletion' do + it "does not include projects marked for deletion" do project.update(pending_delete: true) - get api('/projects', user) + get api("/projects", user) expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array - expect(json_response.map { |p| p['id'] }).not_to include(project.id) + expect(json_response.map { |p| p["id"] }).not_to include(project.id) end - it 'does not include open_issues_count if issues are disabled' do + it "does not include open_issues_count if issues are disabled" do project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) - get api('/projects', user) + get api("/projects", user) expect(response.status).to eq 200 expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.find { |hash| hash['id'] == project.id }.keys).not_to include('open_issues_count') + expect(json_response.find { |hash| hash["id"] == project.id }.keys).not_to include("open_issues_count") end - context 'and with_issues_enabled=true' do - it 'only returns projects with issues enabled' do + context "and with_issues_enabled=true" do + it "only returns projects with issues enabled" do project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) - get api('/projects?with_issues_enabled=true', user) + get api("/projects?with_issues_enabled=true", user) expect(response.status).to eq 200 expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |p| p['id'] }).not_to include(project.id) + expect(json_response.map { |p| p["id"] }).not_to include(project.id) end end it "does not include statistics by default" do - get api('/projects', user) + get api("/projects", user) expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.first).not_to include('statistics') + expect(json_response.first).not_to include("statistics") end it "includes statistics if requested" do - get api('/projects', user), params: { statistics: true } + get api("/projects", user), params: {statistics: true} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.first).to include 'statistics' + expect(json_response.first).to include "statistics" end it "does not include license by default" do - get api('/projects', user) + get api("/projects", user) expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.first).not_to include('license', 'license_url') + expect(json_response.first).not_to include("license", "license_url") end it "does not include license if requested" do - get api('/projects', user), params: { license: true } + get api("/projects", user), params: {license: true} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.first).not_to include('license', 'license_url') + expect(json_response.first).not_to include("license", "license_url") end - context 'when external issue tracker is enabled' do + context "when external issue tracker is enabled" do let!(:jira_service) { create(:jira_service, project: project) } - it 'includes open_issues_count' do - get api('/projects', user) + it "includes open_issues_count" do + get api("/projects", user) expect(response.status).to eq 200 expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.first.keys).to include('open_issues_count') - expect(json_response.find { |hash| hash['id'] == project.id }.keys).to include('open_issues_count') + expect(json_response.first.keys).to include("open_issues_count") + expect(json_response.find { |hash| hash["id"] == project.id }.keys).to include("open_issues_count") end - it 'does not include open_issues_count if issues are disabled' do + it "does not include open_issues_count if issues are disabled" do project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) - get api('/projects', user) + get api("/projects", user) expect(response.status).to eq 200 expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.find { |hash| hash['id'] == project.id }.keys).not_to include('open_issues_count') + expect(json_response.find { |hash| hash["id"] == project.id }.keys).not_to include("open_issues_count") end end - context 'and with simple=true' do - it 'returns a simplified version of all the projects' do - expected_keys = %w( + context "and with simple=true" do + it "returns a simplified version of all the projects" do + expected_keys = %w[ id description default_branch tag_list ssh_url_to_repo http_url_to_repo web_url readme_url name name_with_namespace @@ -300,9 +299,9 @@ describe API::Projects do star_count forks_count created_at last_activity_at avatar_url namespace - ) + ] - get api('/projects?simple=true', user) + get api("/projects?simple=true", user) expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers @@ -311,123 +310,123 @@ describe API::Projects do end end - context 'and using archived' do + context "and using archived" do let!(:archived_project) { create(:project, creator_id: user.id, namespace: user.namespace, archived: true) } - it 'returns archived projects' do - get api('/projects?archived=true', user) + it "returns archived projects" do + get api("/projects?archived=true", user) expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(Project.public_or_visible_to_user(user).where(archived: true).size) - expect(json_response.map { |project| project['id'] }).to include(archived_project.id) + expect(json_response.map { |project| project["id"] }).to include(archived_project.id) end - it 'returns non-archived projects' do - get api('/projects?archived=false', user) + it "returns non-archived projects" do + get api("/projects?archived=false", user) expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(Project.public_or_visible_to_user(user).where(archived: false).size) - expect(json_response.map { |project| project['id'] }).not_to include(archived_project.id) + expect(json_response.map { |project| project["id"] }).not_to include(archived_project.id) end - it 'returns every project' do - get api('/projects', user) + it "returns every project" do + get api("/projects", user) expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |project| project['id'] }).to contain_exactly(*Project.public_or_visible_to_user(user).pluck(:id)) + expect(json_response.map { |project| project["id"] }).to contain_exactly(*Project.public_or_visible_to_user(user).pluck(:id)) end end - context 'and using search' do - it_behaves_like 'projects response' do - let(:filter) { { search: project.name } } + context "and using search" do + it_behaves_like "projects response" do + let(:filter) { {search: project.name} } let(:current_user) { user } let(:projects) { [project] } end end - context 'and membership=true' do - it_behaves_like 'projects response' do - let(:filter) { { membership: true } } + context "and membership=true" do + it_behaves_like "projects response" do + let(:filter) { {membership: true} } let(:current_user) { user } let(:projects) { [project, project2, project3] } end end - context 'and using the visibility filter' do - it 'filters based on private visibility param' do - get api('/projects', user), params: { visibility: 'private' } + context "and using the visibility filter" do + it "filters based on private visibility param" do + get api("/projects", user), params: {visibility: "private"} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |p| p['id'] }).to contain_exactly(project.id, project2.id, project3.id) + expect(json_response.map { |p| p["id"] }).to contain_exactly(project.id, project2.id, project3.id) end - it 'filters based on internal visibility param' do + it "filters based on internal visibility param" do project2.update_attribute(:visibility_level, Gitlab::VisibilityLevel::INTERNAL) - get api('/projects', user), params: { visibility: 'internal' } + get api("/projects", user), params: {visibility: "internal"} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |p| p['id'] }).to contain_exactly(project2.id) + expect(json_response.map { |p| p["id"] }).to contain_exactly(project2.id) end - it 'filters based on public visibility param' do - get api('/projects', user), params: { visibility: 'public' } + it "filters based on public visibility param" do + get api("/projects", user), params: {visibility: "public"} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |p| p['id'] }).to contain_exactly(public_project.id) + expect(json_response.map { |p| p["id"] }).to contain_exactly(public_project.id) end end - context 'and using the programming language filter' do - include_context 'with language detection' + context "and using the programming language filter" do + include_context "with language detection" - it 'filters case-insensitively by programming language' do - get api('/projects', user), params: { with_programming_language: 'javascript' } + it "filters case-insensitively by programming language" do + get api("/projects", user), params: {with_programming_language: "javascript"} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |p| p['id'] }).to contain_exactly(project3.id) + expect(json_response.map { |p| p["id"] }).to contain_exactly(project3.id) end end - context 'and using sorting' do - it 'returns the correct order when sorted by id' do - get api('/projects', user), params: { order_by: 'id', sort: 'desc' } + context "and using sorting" do + it "returns the correct order when sorted by id" do + get api("/projects", user), params: {order_by: "id", sort: "desc"} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.first['id']).to eq(project3.id) + expect(json_response.first["id"]).to eq(project3.id) end end - context 'and with owned=true' do - it 'returns an array of projects the user owns' do - get api('/projects', user4), params: { owned: true } + context "and with owned=true" do + it "returns an array of projects the user owns" do + get api("/projects", user4), params: {owned: true} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.first['name']).to eq(project4.name) - expect(json_response.first['owner']['username']).to eq(user4.username) + expect(json_response.first["name"]).to eq(project4.name) + expect(json_response.first["owner"]["username"]).to eq(user4.username) end end - context 'and with starred=true' do + context "and with starred=true" do let(:public_project) { create(:project, :public) } before do @@ -435,99 +434,99 @@ describe API::Projects do user3.update(starred_projects: [project, project2, project3, public_project]) end - it 'returns the starred projects viewable by the user' do - get api('/projects', user3), params: { starred: true } + it "returns the starred projects viewable by the user" do + get api("/projects", user3), params: {starred: true} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |project| project['id'] }).to contain_exactly(project.id, public_project.id) + expect(json_response.map { |project| project["id"] }).to contain_exactly(project.id, public_project.id) end end - context 'and with all query parameters' do - let!(:project5) { create(:project, :public, path: 'gitlab5', namespace: create(:namespace)) } + context "and with all query parameters" do + let!(:project5) { create(:project, :public, path: "gitlab5", namespace: create(:namespace)) } let!(:project6) { create(:project, :public, namespace: user.namespace) } - let!(:project7) { create(:project, :public, path: 'gitlab7', namespace: user.namespace) } - let!(:project8) { create(:project, path: 'gitlab8', namespace: user.namespace) } - let!(:project9) { create(:project, :public, path: 'gitlab9') } + let!(:project7) { create(:project, :public, path: "gitlab7", namespace: user.namespace) } + let!(:project8) { create(:project, path: "gitlab8", namespace: user.namespace) } + let!(:project9) { create(:project, :public, path: "gitlab9") } before do user.update(starred_projects: [project5, project7, project8, project9]) end - context 'including owned filter' do - it 'returns only projects that satisfy all query parameters' do - get api('/projects', user), params: { visibility: 'public', owned: true, starred: true, search: 'gitlab' } + context "including owned filter" do + it "returns only projects that satisfy all query parameters" do + get api("/projects", user), params: {visibility: "public", owned: true, starred: true, search: "gitlab"} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.size).to eq(1) - expect(json_response.first['id']).to eq(project7.id) + expect(json_response.first["id"]).to eq(project7.id) end end - context 'including membership filter' do + context "including membership filter" do before do create(:project_member, - user: user, - project: project5, - access_level: ProjectMember::MAINTAINER) + user: user, + project: project5, + access_level: ProjectMember::MAINTAINER) end - it 'returns only projects that satisfy all query parameters' do - get api('/projects', user), params: { visibility: 'public', membership: true, starred: true, search: 'gitlab' } + it "returns only projects that satisfy all query parameters" do + get api("/projects", user), params: {visibility: "public", membership: true, starred: true, search: "gitlab"} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.size).to eq(2) - expect(json_response.map { |project| project['id'] }).to contain_exactly(project5.id, project7.id) + expect(json_response.map { |project| project["id"] }).to contain_exactly(project5.id, project7.id) end end end - context 'and with min_access_level' do + context "and with min_access_level" do before do project2.add_maintainer(user2) project3.add_developer(user2) project4.add_reporter(user2) end - it 'returns an array of groups the user has at least developer access' do - get api('/projects', user2), params: { min_access_level: 30 } + it "returns an array of groups the user has at least developer access" do + get api("/projects", user2), params: {min_access_level: 30} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |project| project['id'] }).to contain_exactly(project2.id, project3.id) + expect(json_response.map { |project| project["id"] }).to contain_exactly(project2.id, project3.id) end end end - context 'when authenticated as a different user' do - it_behaves_like 'projects response' do + context "when authenticated as a different user" do + it_behaves_like "projects response" do let(:filter) { {} } let(:current_user) { user2 } let(:projects) { [public_project] } end - context 'and with_issues_enabled=true' do - it 'does not return private issue projects' do + context "and with_issues_enabled=true" do + it "does not return private issue projects" do project.project_feature.update_attribute(:issues_access_level, ProjectFeature::PRIVATE) - get api('/projects?with_issues_enabled=true', user2) + get api("/projects?with_issues_enabled=true", user2) expect(response.status).to eq 200 expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |p| p['id'] }).not_to include(project.id) + expect(json_response.map { |p| p["id"] }).not_to include(project.id) end end end - context 'when authenticated as admin' do - it_behaves_like 'projects response' do + context "when authenticated as admin" do + it_behaves_like "projects response" do let(:filter) { {} } let(:current_user) { admin } let(:projects) { Project.all } @@ -535,63 +534,63 @@ describe API::Projects do end end - describe 'POST /projects' do - context 'maximum number of projects reached' do - it 'does not create new project and respond with 403' do + describe "POST /projects" do + context "maximum number of projects reached" do + it "does not create new project and respond with 403" do allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0) - expect { post api('/projects', user2), params: { name: 'foo' } } + expect { post api("/projects", user2), params: {name: "foo"} } .to change {Project.count}.by(0) expect(response).to have_gitlab_http_status(403) end end - it 'creates new project without path but with name and returns 201' do - expect { post api('/projects', user), params: { name: 'Foo Project' } } + it "creates new project without path but with name and returns 201" do + expect { post api("/projects", user), params: {name: "Foo Project"} } .to change { Project.count }.by(1) expect(response).to have_gitlab_http_status(201) project = Project.first - expect(project.name).to eq('Foo Project') - expect(project.path).to eq('foo-project') + expect(project.name).to eq("Foo Project") + expect(project.path).to eq("foo-project") end - it 'creates new project without name but with path and returns 201' do - expect { post api('/projects', user), params: { path: 'foo_project' } } + it "creates new project without name but with path and returns 201" do + expect { post api("/projects", user), params: {path: "foo_project"} } .to change { Project.count }.by(1) expect(response).to have_gitlab_http_status(201) project = Project.first - expect(project.name).to eq('foo_project') - expect(project.path).to eq('foo_project') + expect(project.name).to eq("foo_project") + expect(project.path).to eq("foo_project") end - it 'creates new project with name and path and returns 201' do - expect { post api('/projects', user), params: { path: 'path-project-Foo', name: 'Foo Project' } } + it "creates new project with name and path and returns 201" do + expect { post api("/projects", user), params: {path: "path-project-Foo", name: "Foo Project"} } .to change { Project.count }.by(1) expect(response).to have_gitlab_http_status(201) project = Project.first - expect(project.name).to eq('Foo Project') - expect(project.path).to eq('path-project-Foo') + expect(project.name).to eq("Foo Project") + expect(project.path).to eq("path-project-Foo") end - it 'creates last project before reaching project limit' do + it "creates last project before reaching project limit" do allow_any_instance_of(User).to receive(:projects_limit_left).and_return(1) - post api('/projects', user2), params: { name: 'foo' } + post api("/projects", user2), params: {name: "foo"} expect(response).to have_gitlab_http_status(201) end - it 'does not create new project without name or path and returns 400' do - expect { post api('/projects', user) }.not_to change { Project.count } + it "does not create new project without name or path and returns 400" do + expect { post api("/projects", user) }.not_to change { Project.count } expect(response).to have_gitlab_http_status(400) end it "assigns attributes to project" do project = attributes_for(:project, { - path: 'camelCasePath', + path: "camelCasePath", issues_enabled: false, jobs_enabled: false, merge_requests_enabled: false, @@ -600,11 +599,11 @@ describe API::Projects do only_allow_merge_if_pipeline_succeeds: false, request_access_enabled: true, only_allow_merge_if_all_discussions_are_resolved: false, - ci_config_path: 'a/custom/path', - merge_method: 'ff' + ci_config_path: "a/custom/path", + merge_method: "ff", }) - post api('/projects', user), params: project + post api("/projects", user), params: project expect(response).to have_gitlab_http_status(201) @@ -621,252 +620,252 @@ describe API::Projects do expect(project.project_feature.wiki_access_level).to eq(ProjectFeature::DISABLED) end - it 'sets a project as public' do - project = attributes_for(:project, visibility: 'public') + it "sets a project as public" do + project = attributes_for(:project, visibility: "public") - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['visibility']).to eq('public') + expect(json_response["visibility"]).to eq("public") end - it 'sets a project as internal' do - project = attributes_for(:project, visibility: 'internal') + it "sets a project as internal" do + project = attributes_for(:project, visibility: "internal") - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['visibility']).to eq('internal') + expect(json_response["visibility"]).to eq("internal") end - it 'sets a project as private' do - project = attributes_for(:project, visibility: 'private') + it "sets a project as private" do + project = attributes_for(:project, visibility: "private") - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['visibility']).to eq('private') + expect(json_response["visibility"]).to eq("private") end - it 'creates a new project initialized with a README.md' do - project = attributes_for(:project, initialize_with_readme: 1, name: 'somewhere') + it "creates a new project initialized with a README.md" do + project = attributes_for(:project, initialize_with_readme: 1, name: "somewhere") - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['readme_url']).to eql("#{Gitlab.config.gitlab.url}/#{json_response['namespace']['full_path']}/somewhere/blob/master/README.md") + expect(json_response["readme_url"]).to eql("#{Gitlab.config.gitlab.url}/#{json_response["namespace"]["full_path"]}/somewhere/blob/master/README.md") end - it 'sets tag list to a project' do + it "sets tag list to a project" do project = attributes_for(:project, tag_list: %w[tagFirst tagSecond]) - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['tag_list']).to eq(%w[tagFirst tagSecond]) + expect(json_response["tag_list"]).to eq(%w[tagFirst tagSecond]) end - it 'uploads avatar for project a project' do - project = attributes_for(:project, avatar: fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif')) + it "uploads avatar for project a project" do + project = attributes_for(:project, avatar: fixture_file_upload("spec/fixtures/banana_sample.gif", "image/gif")) - post api('/projects', user), params: project + post api("/projects", user), params: project - project_id = json_response['id'] - expect(json_response['avatar_url']).to eq("http://localhost/uploads/-/system/project/avatar/#{project_id}/banana_sample.gif") + project_id = json_response["id"] + expect(json_response["avatar_url"]).to eq("http://localhost/uploads/-/system/project/avatar/#{project_id}/banana_sample.gif") end - it 'sets a project as not allowing outdated diff discussions to automatically resolve' do + it "sets a project as not allowing outdated diff discussions to automatically resolve" do project = attributes_for(:project, resolve_outdated_diff_discussions: false) - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['resolve_outdated_diff_discussions']).to be_falsey + expect(json_response["resolve_outdated_diff_discussions"]).to be_falsey end - it 'sets a project as allowing outdated diff discussions to automatically resolve' do + it "sets a project as allowing outdated diff discussions to automatically resolve" do project = attributes_for(:project, resolve_outdated_diff_discussions: true) - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['resolve_outdated_diff_discussions']).to be_truthy + expect(json_response["resolve_outdated_diff_discussions"]).to be_truthy end - it 'sets a project as allowing merge even if build fails' do + it "sets a project as allowing merge even if build fails" do project = attributes_for(:project, only_allow_merge_if_pipeline_succeeds: false) - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_falsey + expect(json_response["only_allow_merge_if_pipeline_succeeds"]).to be_falsey end - it 'sets a project as allowing merge only if merge_when_pipeline_succeeds' do + it "sets a project as allowing merge only if merge_when_pipeline_succeeds" do project = attributes_for(:project, only_allow_merge_if_pipeline_succeeds: true) - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_truthy + expect(json_response["only_allow_merge_if_pipeline_succeeds"]).to be_truthy end - it 'sets a project as allowing merge even if discussions are unresolved' do + it "sets a project as allowing merge even if discussions are unresolved" do project = attributes_for(:project, only_allow_merge_if_all_discussions_are_resolved: false) - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_falsey + expect(json_response["only_allow_merge_if_all_discussions_are_resolved"]).to be_falsey end - it 'sets a project as allowing merge if only_allow_merge_if_all_discussions_are_resolved is nil' do + it "sets a project as allowing merge if only_allow_merge_if_all_discussions_are_resolved is nil" do project = attributes_for(:project, only_allow_merge_if_all_discussions_are_resolved: nil) - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_falsey + expect(json_response["only_allow_merge_if_all_discussions_are_resolved"]).to be_falsey end - it 'sets a project as allowing merge only if all discussions are resolved' do + it "sets a project as allowing merge only if all discussions are resolved" do project = attributes_for(:project, only_allow_merge_if_all_discussions_are_resolved: true) - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_truthy + expect(json_response["only_allow_merge_if_all_discussions_are_resolved"]).to be_truthy end - it 'sets the merge method of a project to rebase merge' do - project = attributes_for(:project, merge_method: 'rebase_merge') + it "sets the merge method of a project to rebase merge" do + project = attributes_for(:project, merge_method: "rebase_merge") - post api('/projects', user), params: project + post api("/projects", user), params: project - expect(json_response['merge_method']).to eq('rebase_merge') + expect(json_response["merge_method"]).to eq("rebase_merge") end - it 'rejects invalid values for merge_method' do - project = attributes_for(:project, merge_method: 'totally_not_valid_method') + it "rejects invalid values for merge_method" do + project = attributes_for(:project, merge_method: "totally_not_valid_method") - post api('/projects', user), params: project + post api("/projects", user), params: project expect(response).to have_gitlab_http_status(400) end - it 'ignores import_url when it is nil' do + it "ignores import_url when it is nil" do project = attributes_for(:project, import_url: nil) - post api('/projects', user), params: project + post api("/projects", user), params: project expect(response).to have_gitlab_http_status(201) end - context 'when a visibility level is restricted' do - let(:project_param) { attributes_for(:project, visibility: 'public') } + context "when a visibility level is restricted" do + let(:project_param) { attributes_for(:project, visibility: "public") } before do stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) end - it 'does not allow a non-admin to use a restricted visibility level' do - post api('/projects', user), params: project_param + it "does not allow a non-admin to use a restricted visibility level" do + post api("/projects", user), params: project_param expect(response).to have_gitlab_http_status(400) - expect(json_response['message']['visibility_level'].first).to( - match('restricted by your GitLab administrator') + expect(json_response["message"]["visibility_level"].first).to( + match("restricted by your GitLab administrator") ) end - it 'allows an admin to override restricted visibility settings' do - post api('/projects', admin), params: project_param + it "allows an admin to override restricted visibility settings" do + post api("/projects", admin), params: project_param - expect(json_response['visibility']).to eq('public') + expect(json_response["visibility"]).to eq("public") end end end - describe 'GET /users/:user_id/projects/' do - let!(:public_project) { create(:project, :public, name: 'public_project', creator_id: user4.id, namespace: user4.namespace) } + describe "GET /users/:user_id/projects/" do + let!(:public_project) { create(:project, :public, name: "public_project", creator_id: user4.id, namespace: user4.namespace) } - it 'returns error when user not found' do - get api('/users/0/projects/') + it "returns error when user not found" do + get api("/users/0/projects/") expect(response).to have_gitlab_http_status(404) - expect(json_response['message']).to eq('404 User Not Found') + expect(json_response["message"]).to eq("404 User Not Found") end - it 'returns projects filtered by user id' do + it "returns projects filtered by user id" do get api("/users/#{user4.id}/projects/", user) expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |project| project['id'] }).to contain_exactly(public_project.id) + expect(json_response.map { |project| project["id"] }).to contain_exactly(public_project.id) end - it 'returns projects filtered by username' do + it "returns projects filtered by username" do get api("/users/#{user4.username}/projects/", user) expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |project| project['id'] }).to contain_exactly(public_project.id) + expect(json_response.map { |project| project["id"] }).to contain_exactly(public_project.id) end - it 'returns projects filtered by minimal access level' do - private_project1 = create(:project, :private, name: 'private_project1', creator_id: user4.id, namespace: user4.namespace) - private_project2 = create(:project, :private, name: 'private_project2', creator_id: user4.id, namespace: user4.namespace) + it "returns projects filtered by minimal access level" do + private_project1 = create(:project, :private, name: "private_project1", creator_id: user4.id, namespace: user4.namespace) + private_project2 = create(:project, :private, name: "private_project2", creator_id: user4.id, namespace: user4.namespace) private_project1.add_developer(user2) private_project2.add_reporter(user2) - get api("/users/#{user4.id}/projects/", user2), params: { min_access_level: 30 } + get api("/users/#{user4.id}/projects/", user2), params: {min_access_level: 30} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |project| project['id'] }).to contain_exactly(private_project1.id) + expect(json_response.map { |project| project["id"] }).to contain_exactly(private_project1.id) end - context 'and using the programming language filter' do - include_context 'with language detection' + context "and using the programming language filter" do + include_context "with language detection" - it 'filters case-insensitively by programming language' do - get api('/projects', user), params: { with_programming_language: 'ruby' } + it "filters case-insensitively by programming language" do + get api("/projects", user), params: {with_programming_language: "ruby"} expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.map { |p| p['id'] }).to contain_exactly(project.id) + expect(json_response.map { |p| p["id"] }).to contain_exactly(project.id) end end end - describe 'POST /projects/user/:id' do - it 'creates new project without path but with name and return 201' do - expect { post api("/projects/user/#{user.id}", admin), params: { name: 'Foo Project' } }.to change { Project.count }.by(1) + describe "POST /projects/user/:id" do + it "creates new project without path but with name and return 201" do + expect { post api("/projects/user/#{user.id}", admin), params: {name: "Foo Project"} }.to change { Project.count }.by(1) expect(response).to have_gitlab_http_status(201) project = Project.last - expect(project.name).to eq('Foo Project') - expect(project.path).to eq('foo-project') + expect(project.name).to eq("Foo Project") + expect(project.path).to eq("foo-project") end - it 'creates new project with name and path and returns 201' do - expect { post api("/projects/user/#{user.id}", admin), params: { path: 'path-project-Foo', name: 'Foo Project' } } + it "creates new project with name and path and returns 201" do + expect { post api("/projects/user/#{user.id}", admin), params: {path: "path-project-Foo", name: "Foo Project"} } .to change { Project.count }.by(1) expect(response).to have_gitlab_http_status(201) project = Project.last - expect(project.name).to eq('Foo Project') - expect(project.path).to eq('path-project-Foo') + expect(project.name).to eq("Foo Project") + expect(project.path).to eq("path-project-Foo") end - it 'responds with 400 on failure and not project' do + it "responds with 400 on failure and not project" do expect { post api("/projects/user/#{user.id}", admin) } .not_to change { Project.count } expect(response).to have_gitlab_http_status(400) - expect(json_response['error']).to eq('name is missing') + expect(json_response["error"]).to eq("name is missing") end - it 'assigns attributes to project' do + it "assigns attributes to project" do project = attributes_for(:project, { issues_enabled: false, merge_requests_enabled: false, wiki_enabled: false, request_access_enabled: true, - jobs_enabled: true + jobs_enabled: true, }) post api("/projects/user/#{user.id}", admin), params: project @@ -880,74 +879,74 @@ describe API::Projects do end end - it 'sets a project as public' do - project = attributes_for(:project, visibility: 'public') + it "sets a project as public" do + project = attributes_for(:project, visibility: "public") post api("/projects/user/#{user.id}", admin), params: project expect(response).to have_gitlab_http_status(201) - expect(json_response['visibility']).to eq('public') + expect(json_response["visibility"]).to eq("public") end - it 'sets a project as internal' do - project = attributes_for(:project, visibility: 'internal') + it "sets a project as internal" do + project = attributes_for(:project, visibility: "internal") post api("/projects/user/#{user.id}", admin), params: project expect(response).to have_gitlab_http_status(201) - expect(json_response['visibility']).to eq('internal') + expect(json_response["visibility"]).to eq("internal") end - it 'sets a project as private' do - project = attributes_for(:project, visibility: 'private') + it "sets a project as private" do + project = attributes_for(:project, visibility: "private") post api("/projects/user/#{user.id}", admin), params: project - expect(json_response['visibility']).to eq('private') + expect(json_response["visibility"]).to eq("private") end - it 'sets a project as not allowing outdated diff discussions to automatically resolve' do + it "sets a project as not allowing outdated diff discussions to automatically resolve" do project = attributes_for(:project, resolve_outdated_diff_discussions: false) post api("/projects/user/#{user.id}", admin), params: project - expect(json_response['resolve_outdated_diff_discussions']).to be_falsey + expect(json_response["resolve_outdated_diff_discussions"]).to be_falsey end - it 'sets a project as allowing outdated diff discussions to automatically resolve' do + it "sets a project as allowing outdated diff discussions to automatically resolve" do project = attributes_for(:project, resolve_outdated_diff_discussions: true) post api("/projects/user/#{user.id}", admin), params: project - expect(json_response['resolve_outdated_diff_discussions']).to be_truthy + expect(json_response["resolve_outdated_diff_discussions"]).to be_truthy end - it 'sets a project as allowing merge even if build fails' do + it "sets a project as allowing merge even if build fails" do project = attributes_for(:project, only_allow_merge_if_pipeline_succeeds: false) post api("/projects/user/#{user.id}", admin), params: project - expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_falsey + expect(json_response["only_allow_merge_if_pipeline_succeeds"]).to be_falsey end - it 'sets a project as allowing merge only if pipeline succeeds' do + it "sets a project as allowing merge only if pipeline succeeds" do project = attributes_for(:project, only_allow_merge_if_pipeline_succeeds: true) post api("/projects/user/#{user.id}", admin), params: project - expect(json_response['only_allow_merge_if_pipeline_succeeds']).to be_truthy + expect(json_response["only_allow_merge_if_pipeline_succeeds"]).to be_truthy end - it 'sets a project as allowing merge even if discussions are unresolved' do + it "sets a project as allowing merge even if discussions are unresolved" do project = attributes_for(:project, only_allow_merge_if_all_discussions_are_resolved: false) post api("/projects/user/#{user.id}", admin), params: project - expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_falsey + expect(json_response["only_allow_merge_if_all_discussions_are_resolved"]).to be_falsey end - it 'sets a project as allowing merge only if all discussions are resolved' do + it "sets a project as allowing merge only if all discussions are resolved" do project = attributes_for(:project, only_allow_merge_if_all_discussions_are_resolved: true) post api("/projects/user/#{user.id}", admin), params: project - expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_truthy + expect(json_response["only_allow_merge_if_all_discussions_are_resolved"]).to be_truthy end end @@ -957,142 +956,142 @@ describe API::Projects do end it "uploads the file and returns its info" do - post api("/projects/#{project.id}/uploads", user), params: { file: fixture_file_upload("spec/fixtures/dk.png", "image/png") } + post api("/projects/#{project.id}/uploads", user), params: {file: fixture_file_upload("spec/fixtures/dk.png", "image/png")} expect(response).to have_gitlab_http_status(201) - expect(json_response['alt']).to eq("dk") - expect(json_response['url']).to start_with("/uploads/") - expect(json_response['url']).to end_with("/dk.png") + expect(json_response["alt"]).to eq("dk") + expect(json_response["url"]).to start_with("/uploads/") + expect(json_response["url"]).to end_with("/dk.png") end end - describe 'GET /projects/:id' do - context 'when unauthenticated' do - it 'returns the public projects' do + describe "GET /projects/:id" do + context "when unauthenticated" do + it "returns the public projects" do public_project = create(:project, :public) get api("/projects/#{public_project.id}") expect(response).to have_gitlab_http_status(200) - expect(json_response['id']).to eq(public_project.id) - expect(json_response['description']).to eq(public_project.description) - expect(json_response['default_branch']).to eq(public_project.default_branch) - expect(json_response.keys).not_to include('permissions') + expect(json_response["id"]).to eq(public_project.id) + expect(json_response["description"]).to eq(public_project.description) + expect(json_response["default_branch"]).to eq(public_project.default_branch) + expect(json_response.keys).not_to include("permissions") end end - context 'when authenticated' do + context "when authenticated" do before do project project_member end - it 'returns 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_gitlab_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['archived']).to be_falsey - expect(json_response['visibility']).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['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['jobs_enabled']).to be_present - expect(json_response['snippets_enabled']).to be_present - expect(json_response['resolve_outdated_diff_discussions']).to eq(project.resolve_outdated_diff_discussions) - 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['import_status']).to be_present + 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["archived"]).to be_falsey + expect(json_response["visibility"]).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["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["jobs_enabled"]).to be_present + expect(json_response["snippets_enabled"]).to be_present + expect(json_response["resolve_outdated_diff_discussions"]).to eq(project.resolve_outdated_diff_discussions) + 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["import_status"]).to be_present expect(json_response).to include("import_error") - 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_jobs']).to be_present - expect(json_response['ci_config_path']).to be_nil - 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_full_path']).to eq(group.full_path) - expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access) - expect(json_response['shared_with_groups'][0]['expires_at']).to be_nil - expect(json_response['only_allow_merge_if_pipeline_succeeds']).to eq(project.only_allow_merge_if_pipeline_succeeds) - expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to eq(project.only_allow_merge_if_all_discussions_are_resolved) - expect(json_response['merge_method']).to eq(project.merge_method.to_s) - expect(json_response['readme_url']).to eq(project.readme_url) - end - - it 'returns a group link with expiration date' do + 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_jobs"]).to be_present + expect(json_response["ci_config_path"]).to be_nil + 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_full_path"]).to eq(group.full_path) + expect(json_response["shared_with_groups"][0]["group_access_level"]).to eq(link.group_access) + expect(json_response["shared_with_groups"][0]["expires_at"]).to be_nil + expect(json_response["only_allow_merge_if_pipeline_succeeds"]).to eq(project.only_allow_merge_if_pipeline_succeeds) + expect(json_response["only_allow_merge_if_all_discussions_are_resolved"]).to eq(project.only_allow_merge_if_all_discussions_are_resolved) + expect(json_response["merge_method"]).to eq(project.merge_method.to_s) + expect(json_response["readme_url"]).to eq(project.readme_url) + end + + it "returns a group link with expiration date" do group = create(:group) expires_at = 5.days.from_now.to_date link = create(:project_group_link, project: project, group: group, expires_at: expires_at) get api("/projects/#{project.id}", user) - 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_full_path']).to eq(group.full_path) - expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access) - expect(json_response['shared_with_groups'][0]['expires_at']).to eq(expires_at.to_s) + 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_full_path"]).to eq(group.full_path) + expect(json_response["shared_with_groups"][0]["group_access_level"]).to eq(link.group_access) + expect(json_response["shared_with_groups"][0]["expires_at"]).to eq(expires_at.to_s) end - it 'returns a project by path name' do + it "returns a project by path name" do get api("/projects/#{project.id}", user) expect(response).to have_gitlab_http_status(200) - expect(json_response['name']).to eq(project.name) + expect(json_response["name"]).to eq(project.name) end - it 'returns a 404 error if not found' do - get api('/projects/42', user) + it "returns a 404 error if not found" do + get api("/projects/42", user) expect(response).to have_gitlab_http_status(404) - expect(json_response['message']).to eq('404 Project Not Found') + expect(json_response["message"]).to eq("404 Project Not Found") end - it 'returns a 404 error if user is not a member' do + it "returns a 404 error if user is not a member" do other_user = create(:user) get api("/projects/#{project.id}", other_user) expect(response).to have_gitlab_http_status(404) end - it 'handles users with dots' do - dot_user = create(:user, username: 'dot.user') + it "handles users with dots" do + dot_user = create(:user, username: "dot.user") project = create(:project, creator_id: dot_user.id, namespace: dot_user.namespace) get api("/projects/#{CGI.escape(project.full_path)}", dot_user) expect(response).to have_gitlab_http_status(200) - expect(json_response['name']).to eq(project.name) + expect(json_response["name"]).to eq(project.name) end - it 'exposes namespace fields' do + it "exposes namespace fields" do get api("/projects/#{project.id}", user) expect(response).to have_gitlab_http_status(200) - expect(json_response['namespace']).to eq({ - 'id' => user.namespace.id, - 'name' => user.namespace.name, - 'path' => user.namespace.path, - 'kind' => user.namespace.kind, - 'full_path' => user.namespace.full_path, - 'parent_id' => nil + expect(json_response["namespace"]).to eq({ + "id" => user.namespace.id, + "name" => user.namespace.name, + "path" => user.namespace.path, + "kind" => user.namespace.kind, + "full_path" => user.namespace.full_path, + "parent_id" => nil, }) end @@ -1100,19 +1099,19 @@ describe API::Projects do get api("/projects/#{project.id}", user) expect(response).to have_gitlab_http_status(200) - expect(json_response).not_to include('license', 'license_url') + expect(json_response).not_to include("license", "license_url") end - it 'includes license fields when requested' do - get api("/projects/#{project.id}", user), params: { license: true } + it "includes license fields when requested" do + get api("/projects/#{project.id}", user), params: {license: true} expect(response).to have_gitlab_http_status(200) - expect(json_response['license']).to eq({ - 'key' => project.repository.license.key, - 'name' => project.repository.license.name, - 'nickname' => project.repository.license.nickname, - 'html_url' => project.repository.license.url, - 'source_url' => project.repository.license.meta['source'] + expect(json_response["license"]).to eq({ + "key" => project.repository.license.key, + "name" => project.repository.license.name, + "nickname" => project.repository.license.nickname, + "html_url" => project.repository.license.url, + "source_url" => project.repository.license.meta["source"], }) end @@ -1120,14 +1119,14 @@ describe API::Projects do get api("/projects/#{project.id}", user) expect(response).to have_gitlab_http_status(200) - expect(json_response).not_to include 'statistics' + expect(json_response).not_to include "statistics" end it "includes statistics if requested" do - get api("/projects/#{project.id}", user), params: { statistics: true } + get api("/projects/#{project.id}", user), params: {statistics: true} expect(response).to have_gitlab_http_status(200) - expect(json_response).to include 'statistics' + expect(json_response).to include "statistics" end it "includes import_error if user can admin project" do @@ -1144,93 +1143,93 @@ describe API::Projects do expect(json_response).not_to include("import_error") end - it 'returns 404 when project is marked for deletion' do + it "returns 404 when project is marked for deletion" do project.update(pending_delete: true) get api("/projects/#{project.id}", user) expect(response).to have_gitlab_http_status(404) - expect(json_response['message']).to eq('404 Project Not Found') + expect(json_response["message"]).to eq("404 Project Not Found") end - context 'links exposure' do - it 'exposes related resources full URIs' do + context "links exposure" do + it "exposes related resources full URIs" do get api("/projects/#{project.id}", user) - links = json_response['_links'] + links = json_response["_links"] - expect(links['self']).to end_with("/api/v4/projects/#{project.id}") - expect(links['issues']).to end_with("/api/v4/projects/#{project.id}/issues") - expect(links['merge_requests']).to end_with("/api/v4/projects/#{project.id}/merge_requests") - expect(links['repo_branches']).to end_with("/api/v4/projects/#{project.id}/repository/branches") - expect(links['labels']).to end_with("/api/v4/projects/#{project.id}/labels") - expect(links['events']).to end_with("/api/v4/projects/#{project.id}/events") - expect(links['members']).to end_with("/api/v4/projects/#{project.id}/members") + expect(links["self"]).to end_with("/api/v4/projects/#{project.id}") + expect(links["issues"]).to end_with("/api/v4/projects/#{project.id}/issues") + expect(links["merge_requests"]).to end_with("/api/v4/projects/#{project.id}/merge_requests") + expect(links["repo_branches"]).to end_with("/api/v4/projects/#{project.id}/repository/branches") + expect(links["labels"]).to end_with("/api/v4/projects/#{project.id}/labels") + expect(links["events"]).to end_with("/api/v4/projects/#{project.id}/events") + expect(links["members"]).to end_with("/api/v4/projects/#{project.id}/members") end - it 'filters related URIs when their feature is not enabled' do + it "filters related URIs when their feature is not enabled" do project = create(:project, :public, - :merge_requests_disabled, - :issues_disabled, - creator_id: user.id, - namespace: user.namespace) + :merge_requests_disabled, + :issues_disabled, + creator_id: user.id, + namespace: user.namespace) get api("/projects/#{project.id}", user) - links = json_response['_links'] + links = json_response["_links"] - expect(links.has_key?('merge_requests')).to be_falsy - expect(links.has_key?('issues')).to be_falsy - expect(links['self']).to end_with("/api/v4/projects/#{project.id}") + expect(links.key?("merge_requests")).to be_falsy + expect(links.key?("issues")).to be_falsy + expect(links["self"]).to end_with("/api/v4/projects/#{project.id}") end end - describe 'permissions' do - context 'all projects' do + describe "permissions" do + context "all projects" do before do project.add_maintainer(user) end - it 'contains permission information' do + it "contains permission information" do get api("/projects", user) expect(response).to have_gitlab_http_status(200) - expect(json_response.first['permissions']['project_access']['access_level']) - .to eq(Gitlab::Access::MAINTAINER) - expect(json_response.first['permissions']['group_access']).to be_nil + expect(json_response.first["permissions"]["project_access"]["access_level"]) + .to eq(Gitlab::Access::MAINTAINER) + expect(json_response.first["permissions"]["group_access"]).to be_nil end end - context 'personal project' do - it 'sets project access and returns 200' do + context "personal project" do + it "sets project access and returns 200" do project.add_maintainer(user) get api("/projects/#{project.id}", user) expect(response).to have_gitlab_http_status(200) - expect(json_response['permissions']['project_access']['access_level']) - .to eq(Gitlab::Access::MAINTAINER) - expect(json_response['permissions']['group_access']).to be_nil + expect(json_response["permissions"]["project_access"]["access_level"]) + .to eq(Gitlab::Access::MAINTAINER) + expect(json_response["permissions"]["group_access"]).to be_nil end end - context 'group project' do + context "group project" do let(:project2) { create(:project, group: create(:group)) } before do project2.group.add_owner(user) end - it 'sets the owner and return 200' do + it "sets the owner and return 200" do get api("/projects/#{project2.id}", user) expect(response).to have_gitlab_http_status(200) - expect(json_response['permissions']['project_access']).to be_nil - expect(json_response['permissions']['group_access']['access_level']) - .to eq(Gitlab::Access::OWNER) + expect(json_response["permissions"]["project_access"]).to be_nil + expect(json_response["permissions"]["group_access"]["access_level"]) + .to eq(Gitlab::Access::OWNER) end end - context 'nested group project', :nested_groups do + context "nested group project", :nested_groups do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } let(:project2) { create(:project, group: nested_group) } @@ -1239,27 +1238,27 @@ describe API::Projects do project2.group.parent.add_owner(user) end - it 'sets group access and return 200' do + it "sets group access and return 200" do get api("/projects/#{project2.id}", user) expect(response).to have_gitlab_http_status(200) - expect(json_response['permissions']['project_access']).to be_nil - expect(json_response['permissions']['group_access']['access_level']) - .to eq(Gitlab::Access::OWNER) + expect(json_response["permissions"]["project_access"]).to be_nil + expect(json_response["permissions"]["group_access"]["access_level"]) + .to eq(Gitlab::Access::OWNER) end - context 'with various access levels across nested groups' do + context "with various access levels across nested groups" do before do project2.group.add_maintainer(user) end - it 'sets the maximum group access and return 200' do + it "sets the maximum group access and return 200" do get api("/projects/#{project2.id}", user) expect(response).to have_gitlab_http_status(200) - expect(json_response['permissions']['project_access']).to be_nil - expect(json_response['permissions']['group_access']['access_level']) - .to eq(Gitlab::Access::OWNER) + expect(json_response["permissions"]["project_access"]).to be_nil + expect(json_response["permissions"]["group_access"]["access_level"]) + .to eq(Gitlab::Access::OWNER) end end end @@ -1267,9 +1266,9 @@ describe API::Projects do end end - describe 'GET /projects/:id/users' do - shared_examples_for 'project users response' do - it 'returns the project users' do + describe "GET /projects/:id/users" do + shared_examples_for "project users response" do + it "returns the project users" do get api("/projects/#{project.id}/users", current_user) user = project.namespace.owner @@ -1280,34 +1279,34 @@ describe API::Projects do expect(json_response.size).to eq(1) first_user = json_response.first - expect(first_user['username']).to eq(user.username) - expect(first_user['name']).to eq(user.name) - expect(first_user.keys).to contain_exactly(*%w[name username id state avatar_url web_url]) + expect(first_user["username"]).to eq(user.username) + expect(first_user["name"]).to eq(user.name) + expect(first_user.keys).to contain_exactly("name", "username", "id", "state", "avatar_url", "web_url") end end - context 'when unauthenticated' do - it_behaves_like 'project users response' do + context "when unauthenticated" do + it_behaves_like "project users response" do let(:project) { create(:project, :public) } let(:current_user) { nil } end end - context 'when authenticated' do - context 'valid request' do - it_behaves_like 'project users response' do + context "when authenticated" do + context "valid request" do + it_behaves_like "project users response" do let(:current_user) { user } end end - it 'returns a 404 error if not found' do - get api('/projects/42/users', user) + it "returns a 404 error if not found" do + get api("/projects/42/users", user) expect(response).to have_gitlab_http_status(404) - expect(json_response['message']).to eq('404 Project Not Found') + expect(json_response["message"]).to eq("404 Project Not Found") end - it 'returns a 404 error if user is not a member' do + it "returns a 404 error if user is not a member" do other_user = create(:user) get api("/projects/#{project.id}/users", other_user) @@ -1317,34 +1316,34 @@ describe API::Projects do end end - describe 'fork management' do + describe "fork management" do let(:project_fork_target) { create(:project) } let(:project_fork_source) { create(:project, :public) } let(:private_project_fork_source) { create(:project, :private) } - describe 'POST /projects/:id/fork/:forked_from_id' do - context 'user is a developer' do + describe "POST /projects/:id/fork/:forked_from_id" do + context "user is a developer" do before do project_fork_target.add_developer(user) end - it 'denies project to be forked from an existing project' do + it "denies project to be forked from an existing project" do post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) expect(response).to have_gitlab_http_status(403) end end - it 'refreshes the forks count cache' do + it "refreshes the forks count cache" do expect(project_fork_source.forks_count).to be_zero end - context 'user is maintainer' do + context "user is maintainer" do before do project_fork_target.add_maintainer(user) end - it 'allows project to be forked from an existing project' do + it "allows project to be forked from an existing project" do expect(project_fork_target).not_to be_forked post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) @@ -1356,15 +1355,15 @@ describe API::Projects do expect(project_fork_target).to be_forked end - it 'denies project to be forked from a private project' do + it "denies project to be forked from a private project" do post api("/projects/#{project_fork_target.id}/fork/#{private_project_fork_source.id}", user) expect(response).to have_gitlab_http_status(404) end end - context 'user is admin' do - it 'allows project to be forked from an existing project' do + context "user is admin" do + it "allows project to be forked from an existing project" do expect(project_fork_target).not_to be_forked post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) @@ -1372,24 +1371,24 @@ describe API::Projects do expect(response).to have_gitlab_http_status(201) end - it 'allows project to be forked from a private project' do + it "allows project to be forked from a private project" do post api("/projects/#{project_fork_target.id}/fork/#{private_project_fork_source.id}", admin) expect(response).to have_gitlab_http_status(201) end - it 'refreshes the forks count cachce' do - expect do + it "refreshes the forks count cachce" do + expect { post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) - end.to change(project_fork_source, :forks_count).by(1) + }.to change(project_fork_source, :forks_count).by(1) end - it 'fails if forked_from project which does not exist' do + it "fails if forked_from project which does not exist" do post api("/projects/#{project_fork_target.id}/fork/0", admin) expect(response).to have_gitlab_http_status(404) end - it 'fails with 409 if already forked' do + it "fails with 409 if already forked" do other_project_fork_source = create(:project, :public) Projects::ForkService.new(project_fork_source, admin).execute(project_fork_target) @@ -1404,13 +1403,13 @@ describe API::Projects do end end - describe 'DELETE /projects/:id/fork' do + describe "DELETE /projects/:id/fork" do it "is not visible to users outside group" do delete api("/projects/#{project_fork_target.id}/fork", user) expect(response).to have_gitlab_http_status(404) end - context 'when users belong to project group' do + context "when users belong to project group" do let(:project_fork_target) { create(:project, group: create(:group)) } before do @@ -1418,7 +1417,7 @@ describe API::Projects do project_fork_target.group.add_developer user2 end - context 'for a forked project' do + context "for a forked project" do before do post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) project_fork_target.reload @@ -1426,7 +1425,7 @@ describe API::Projects do expect(project_fork_target).to be_forked end - it 'makes forked project unforked' do + it "makes forked project unforked" do delete api("/projects/#{project_fork_target.id}/fork", admin) expect(response).to have_gitlab_http_status(204) @@ -1435,17 +1434,17 @@ describe API::Projects do expect(project_fork_target).not_to be_forked end - it_behaves_like '412 response' do + it_behaves_like "412 response" do let(:request) { api("/projects/#{project_fork_target.id}/fork", admin) } end end - it 'is forbidden to non-owner users' do + it "is forbidden to non-owner users" do delete api("/projects/#{project_fork_target.id}/fork", user2) expect(response).to have_gitlab_http_status(403) end - it 'is idempotent if not forked' do + it "is idempotent if not forked" do expect(project_fork_target.forked_from_project).to be_nil delete api("/projects/#{project_fork_target.id}/fork", admin) expect(response).to have_gitlab_http_status(304) @@ -1454,7 +1453,7 @@ describe API::Projects do end end - describe 'GET /projects/:id/forks' do + describe "GET /projects/:id/forks" do let(:private_fork) { create(:project, :private, :empty_repo) } let(:member) { create(:user) } let(:non_member) { create(:user) } @@ -1463,7 +1462,7 @@ describe API::Projects do private_fork.add_developer(member) end - context 'for a forked project' do + context "for a forked project" do before do post api("/projects/#{private_fork.id}/fork/#{project_fork_source.id}", admin) private_fork.reload @@ -1474,19 +1473,19 @@ describe API::Projects do 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 + 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_gitlab_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) + 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 + 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_gitlab_http_status(200) @@ -1496,8 +1495,8 @@ describe API::Projects do end end - context 'for a non-forked project' do - it 'returns an empty array' do + 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_gitlab_http_status(200) @@ -1514,94 +1513,94 @@ describe API::Projects do it "shares project with group" do expires_at = 10.days.from_now.to_date - expect do - post api("/projects/#{project.id}/share", user), params: { group_id: group.id, group_access: Gitlab::Access::DEVELOPER, expires_at: expires_at } - end.to change { ProjectGroupLink.count }.by(1) + expect { + post api("/projects/#{project.id}/share", user), params: {group_id: group.id, group_access: Gitlab::Access::DEVELOPER, expires_at: expires_at} + }.to change { ProjectGroupLink.count }.by(1) expect(response).to have_gitlab_http_status(201) - expect(json_response['group_id']).to eq(group.id) - expect(json_response['group_access']).to eq(Gitlab::Access::DEVELOPER) - expect(json_response['expires_at']).to eq(expires_at.to_s) + expect(json_response["group_id"]).to eq(group.id) + expect(json_response["group_access"]).to eq(Gitlab::Access::DEVELOPER) + expect(json_response["expires_at"]).to eq(expires_at.to_s) end it "returns a 400 error when group id is not given" do - post api("/projects/#{project.id}/share", user), params: { group_access: Gitlab::Access::DEVELOPER } + post api("/projects/#{project.id}/share", user), params: {group_access: Gitlab::Access::DEVELOPER} expect(response).to have_gitlab_http_status(400) end it "returns a 400 error when access level is not given" do - post api("/projects/#{project.id}/share", user), params: { group_id: group.id } + post api("/projects/#{project.id}/share", user), params: {group_id: group.id} expect(response).to have_gitlab_http_status(400) end it "returns a 400 error when sharing is disabled" do project.namespace.update(share_with_group_lock: true) - post api("/projects/#{project.id}/share", user), params: { group_id: group.id, group_access: Gitlab::Access::DEVELOPER } + post api("/projects/#{project.id}/share", user), params: {group_id: group.id, group_access: Gitlab::Access::DEVELOPER} expect(response).to have_gitlab_http_status(400) end - it 'returns a 404 error when user cannot read group' do + it "returns a 404 error when user cannot read group" do private_group = create(:group, :private) - post api("/projects/#{project.id}/share", user), params: { group_id: private_group.id, group_access: Gitlab::Access::DEVELOPER } + post api("/projects/#{project.id}/share", user), params: {group_id: private_group.id, group_access: Gitlab::Access::DEVELOPER} expect(response).to have_gitlab_http_status(404) end - it 'returns a 404 error when group does not exist' do - post api("/projects/#{project.id}/share", user), params: { group_id: 1234, group_access: Gitlab::Access::DEVELOPER } + it "returns a 404 error when group does not exist" do + post api("/projects/#{project.id}/share", user), params: {group_id: 1234, group_access: Gitlab::Access::DEVELOPER} expect(response).to have_gitlab_http_status(404) end it "returns a 400 error when wrong params passed" do - post api("/projects/#{project.id}/share", user), params: { group_id: group.id, group_access: 1234 } + post api("/projects/#{project.id}/share", user), params: {group_id: group.id, group_access: 1234} expect(response).to have_gitlab_http_status(400) - expect(json_response['error']).to eq 'group_access does not have a valid value' + expect(json_response["error"]).to eq "group_access does not have a valid value" end end - describe 'DELETE /projects/:id/share/:group_id' do - context 'for a valid group' do + describe "DELETE /projects/:id/share/:group_id" do + context "for a valid group" do let(:group) { create(:group, :public) } before do create(:project_group_link, group: group, project: project) end - it 'returns 204 when deleting a group share' do + it "returns 204 when deleting a group share" do delete api("/projects/#{project.id}/share/#{group.id}", user) expect(response).to have_gitlab_http_status(204) expect(project.project_group_links).to be_empty end - it_behaves_like '412 response' do + it_behaves_like "412 response" do let(:request) { api("/projects/#{project.id}/share/#{group.id}", user) } end end - it 'returns a 400 when group id is not an integer' do + it "returns a 400 when group id is not an integer" do delete api("/projects/#{project.id}/share/foo", user) expect(response).to have_gitlab_http_status(400) end - it 'returns a 404 error when group link does not exist' do + it "returns a 404 error when group link does not exist" do delete api("/projects/#{project.id}/share/1234", user) expect(response).to have_gitlab_http_status(404) end - it 'returns a 404 error when project does not exist' do + it "returns a 404 error when project does not exist" do delete api("/projects/123/share/1234", user) expect(response).to have_gitlab_http_status(404) end end - describe 'PUT /projects/:id' do + describe "PUT /projects/:id" do before do expect(project).to be_persisted expect(user).to be_persisted @@ -1613,18 +1612,18 @@ describe API::Projects do expect(project_member).to be_persisted end - it 'returns 400 when nothing sent' do + it "returns 400 when nothing sent" do project_param = {} put api("/projects/#{project.id}", user), params: project_param expect(response).to have_gitlab_http_status(400) - expect(json_response['error']).to match('at least one parameter must be provided') + expect(json_response["error"]).to match("at least one parameter must be provided") end - context 'when unauthenticated' do - it 'returns authentication error' do - project_param = { name: 'bar' } + context "when unauthenticated" do + it "returns authentication error" do + project_param = {name: "bar"} put api("/projects/#{project.id}"), params: project_param @@ -1632,9 +1631,9 @@ describe API::Projects do end end - context 'when authenticated as project owner' do - it 'updates name' do - project_param = { name: 'bar' } + context "when authenticated as project owner" do + it "updates name" do + project_param = {name: "bar"} put api("/projects/#{project.id}", user), params: project_param @@ -1645,8 +1644,8 @@ describe API::Projects do end end - it 'updates visibility_level' do - project_param = { visibility: 'public' } + it "updates visibility_level" do + project_param = {visibility: "public"} put api("/projects/#{project3.id}", user), params: project_param @@ -1657,9 +1656,9 @@ describe API::Projects do end end - it 'updates visibility_level from public to private' do - project3.update({ visibility_level: Gitlab::VisibilityLevel::PUBLIC }) - project_param = { visibility: 'private' } + it "updates visibility_level from public to private" do + project3.update({visibility_level: Gitlab::VisibilityLevel::PUBLIC}) + project_param = {visibility: "private"} put api("/projects/#{project3.id}", user), params: project_param @@ -1669,29 +1668,29 @@ describe API::Projects do expect(json_response[k.to_s]).to eq(v) end - expect(json_response['visibility']).to eq('private') + expect(json_response["visibility"]).to eq("private") end - it 'does not update name to existing name' do - project_param = { name: project3.name } + it "does not update name to existing name" do + project_param = {name: project3.name} put api("/projects/#{project.id}", user), params: project_param expect(response).to have_gitlab_http_status(400) - expect(json_response['message']['name']).to eq(['has already been taken']) + expect(json_response["message"]["name"]).to eq(["has already been taken"]) end - it 'updates request_access_enabled' do - project_param = { request_access_enabled: false } + it "updates request_access_enabled" do + project_param = {request_access_enabled: false} put api("/projects/#{project.id}", user), params: project_param expect(response).to have_gitlab_http_status(200) - expect(json_response['request_access_enabled']).to eq(false) + expect(json_response["request_access_enabled"]).to eq(false) end - it 'updates path & name to existing path & name in different namespace' do - project_param = { path: project4.path, name: project4.name } + it "updates path & name to existing path & name in different namespace" do + project_param = {path: project4.path, name: project4.name} put api("/projects/#{project3.id}", user), params: project_param @@ -1702,8 +1701,8 @@ describe API::Projects do end end - it 'updates jobs_enabled' do - project_param = { jobs_enabled: true } + it "updates jobs_enabled" do + project_param = {jobs_enabled: true} put api("/projects/#{project3.id}", user), params: project_param @@ -1714,8 +1713,8 @@ describe API::Projects do end end - it 'updates merge_method' do - project_param = { merge_method: 'ff' } + it "updates merge_method" do + project_param = {merge_method: "ff"} put api("/projects/#{project3.id}", user), params: project_param @@ -1726,32 +1725,32 @@ describe API::Projects do end end - it 'rejects to update merge_method when merge_method is invalid' do - project_param = { merge_method: 'invalid' } + it "rejects to update merge_method when merge_method is invalid" do + project_param = {merge_method: "invalid"} put api("/projects/#{project3.id}", user), params: project_param expect(response).to have_gitlab_http_status(400) end - it 'updates avatar' do + it "updates avatar" do project_param = { - avatar: fixture_file_upload('spec/fixtures/banana_sample.gif', - 'image/gif') + avatar: fixture_file_upload("spec/fixtures/banana_sample.gif", + "image/gif"), } put api("/projects/#{project3.id}", user), params: project_param expect(response).to have_gitlab_http_status(200) - expect(json_response['avatar_url']).to eq('http://localhost/uploads/'\ - '-/system/project/avatar/'\ + expect(json_response["avatar_url"]).to eq("http://localhost/uploads/"\ + "-/system/project/avatar/"\ "#{project3.id}/banana_sample.gif") end end - context 'when authenticated as project maintainer' do - it 'updates path' do - project_param = { path: 'bar' } + context "when authenticated as project maintainer" do + it "updates path" do + project_param = {path: "bar"} put api("/projects/#{project3.id}", user4), params: project_param expect(response).to have_gitlab_http_status(200) project_param.each_pair do |k, v| @@ -1759,13 +1758,13 @@ describe API::Projects do end end - it 'updates other attributes' do - project_param = { issues_enabled: true, - wiki_enabled: true, - snippets_enabled: true, - merge_requests_enabled: true, - merge_method: 'ff', - description: 'new description' } + it "updates other attributes" do + project_param = {issues_enabled: true, + wiki_enabled: true, + snippets_enabled: true, + merge_requests_enabled: true, + merge_method: "ff", + description: "new description",} put api("/projects/#{project3.id}", user4), params: project_param expect(response).to have_gitlab_http_status(200) @@ -1774,70 +1773,70 @@ describe API::Projects do end end - it 'does not update path to existing path' do - project_param = { path: project.path } + it "does not update path to existing path" do + project_param = {path: project.path} put api("/projects/#{project3.id}", user4), params: project_param expect(response).to have_gitlab_http_status(400) - expect(json_response['message']['path']).to eq(['has already been taken']) + expect(json_response["message"]["path"]).to eq(["has already been taken"]) end - it 'does not update name' do - project_param = { name: 'bar' } + it "does not update name" do + project_param = {name: "bar"} put api("/projects/#{project3.id}", user4), params: project_param expect(response).to have_gitlab_http_status(403) end - it 'does not update visibility_level' do - project_param = { visibility: 'public' } + it "does not update visibility_level" do + project_param = {visibility: "public"} put api("/projects/#{project3.id}", user4), params: project_param expect(response).to have_gitlab_http_status(403) end end - context 'when authenticated as project developer' do - it 'does not update other attributes' do - project_param = { path: 'bar', - issues_enabled: true, - wiki_enabled: true, - snippets_enabled: true, - merge_requests_enabled: true, - description: 'new description', - request_access_enabled: true } + context "when authenticated as project developer" do + it "does not update other attributes" do + project_param = {path: "bar", + issues_enabled: true, + wiki_enabled: true, + snippets_enabled: true, + merge_requests_enabled: true, + description: "new description", + request_access_enabled: true,} put api("/projects/#{project.id}", user3), params: project_param expect(response).to have_gitlab_http_status(403) end end end - describe 'POST /projects/:id/archive' do - context 'on an unarchived project' do - it 'archives the project' do + describe "POST /projects/:id/archive" do + context "on an unarchived project" do + it "archives the project" do post api("/projects/#{project.id}/archive", user) expect(response).to have_gitlab_http_status(201) - expect(json_response['archived']).to be_truthy + expect(json_response["archived"]).to be_truthy end end - context 'on an archived project' do + context "on an archived project" do before do ::Projects::UpdateService.new(project, user, archived: true).execute end - it 'remains archived' do + it "remains archived" do post api("/projects/#{project.id}/archive", user) expect(response).to have_gitlab_http_status(201) - expect(json_response['archived']).to be_truthy + expect(json_response["archived"]).to be_truthy end end - context 'user without archiving rights to the project' do + context "user without archiving rights to the project" do before do project.add_developer(user3) end - it 'rejects the action' do + it "rejects the action" do post api("/projects/#{project.id}/archive", user3) expect(response).to have_gitlab_http_status(403) @@ -1845,35 +1844,35 @@ describe API::Projects do end end - describe 'POST /projects/:id/unarchive' do - context 'on an unarchived project' do - it 'remains unarchived' do + describe "POST /projects/:id/unarchive" do + context "on an unarchived project" do + it "remains unarchived" do post api("/projects/#{project.id}/unarchive", user) expect(response).to have_gitlab_http_status(201) - expect(json_response['archived']).to be_falsey + expect(json_response["archived"]).to be_falsey end end - context 'on an archived project' do + context "on an archived project" do before do ::Projects::UpdateService.new(project, user, archived: true).execute end - it 'unarchives the project' do + it "unarchives the project" do post api("/projects/#{project.id}/unarchive", user) expect(response).to have_gitlab_http_status(201) - expect(json_response['archived']).to be_falsey + expect(json_response["archived"]).to be_falsey end end - context 'user without archiving rights to the project' do + context "user without archiving rights to the project" do before do project.add_developer(user3) end - it 'rejects the action' do + it "rejects the action" do post api("/projects/#{project.id}/unarchive", user3) expect(response).to have_gitlab_http_status(403) @@ -1881,23 +1880,23 @@ describe API::Projects do end end - describe 'POST /projects/:id/star' do - context 'on an unstarred project' do - it 'stars the project' do + describe "POST /projects/:id/star" do + context "on an unstarred project" do + it "stars the project" do expect { post api("/projects/#{project.id}/star", user) }.to change { project.reload.star_count }.by(1) expect(response).to have_gitlab_http_status(201) - expect(json_response['star_count']).to eq(1) + expect(json_response["star_count"]).to eq(1) end end - context 'on a starred project' do + context "on a starred project" do before do user.toggle_star(project) project.reload end - it 'does not modify the star count' do + it "does not modify the star count" do expect { post api("/projects/#{project.id}/star", user) }.not_to change { project.reload.star_count } expect(response).to have_gitlab_http_status(304) @@ -1905,23 +1904,23 @@ describe API::Projects do end end - describe 'POST /projects/:id/unstar' do - context 'on a starred project' do + describe "POST /projects/:id/unstar" do + context "on a starred project" do before do user.toggle_star(project) project.reload end - it 'unstars the project' do + it "unstars the project" do expect { post api("/projects/#{project.id}/unstar", user) }.to change { project.reload.star_count }.by(-1) expect(response).to have_gitlab_http_status(201) - expect(json_response['star_count']).to eq(0) + expect(json_response["star_count"]).to eq(0) end end - context 'on an unstarred project' do - it 'does not modify the star count' do + context "on an unstarred project" do + it "does not modify the star count" do expect { post api("/projects/#{project.id}/unstar", user) }.not_to change { project.reload.star_count } expect(response).to have_gitlab_http_status(304) @@ -1929,35 +1928,35 @@ describe API::Projects do end end - describe 'GET /projects/:id/languages' do - context 'with an authorized user' do - it_behaves_like 'languages and percentages JSON response' do + describe "GET /projects/:id/languages" do + context "with an authorized user" do + it_behaves_like "languages and percentages JSON response" do let(:project) { project3 } end - it 'returns not_found(404) for not existing project' do + it "returns not_found(404) for not existing project" do get api("/projects/0/languages", user) expect(response).to have_gitlab_http_status(:not_found) end end - context 'with not authorized user' do - it 'returns not_found for existing but unauthorized project' do + context "with not authorized user" do + it "returns not_found for existing but unauthorized project" do get api("/projects/#{project3.id}/languages", user3) expect(response).to have_gitlab_http_status(:not_found) end end - context 'without user' do + context "without user" do let(:project_public) { create(:project, :public, :repository) } - it_behaves_like 'languages and percentages JSON response' do + it_behaves_like "languages and percentages JSON response" do let(:project) { project_public } end - it 'returns not_found for existing but unauthorized project' do + it "returns not_found for existing but unauthorized project" do get api("/projects/#{project3.id}/languages", nil) expect(response).to have_gitlab_http_status(:not_found) @@ -1965,59 +1964,59 @@ describe API::Projects do end end - describe 'DELETE /projects/:id' do - context 'when authenticated as user' do - it 'removes project' do + describe "DELETE /projects/:id" do + context "when authenticated as user" do + it "removes project" do delete api("/projects/#{project.id}", user) expect(response).to have_gitlab_http_status(202) - expect(json_response['message']).to eql('202 Accepted') + expect(json_response["message"]).to eql("202 Accepted") end - it_behaves_like '412 response' do + it_behaves_like "412 response" do let(:success_status) { 202 } let(:request) { api("/projects/#{project.id}", user) } end - it 'does not remove a project if not an owner' do + it "does not remove a project if not an owner" do user3 = create(:user) project.add_developer(user3) delete api("/projects/#{project.id}", user3) expect(response).to have_gitlab_http_status(403) end - it 'does not remove a non existing project' do - delete api('/projects/1328', user) + it "does not remove a non existing project" do + delete api("/projects/1328", user) expect(response).to have_gitlab_http_status(404) end - it 'does not remove a project not attached to user' do + it "does not remove a project not attached to user" do delete api("/projects/#{project.id}", user2) expect(response).to have_gitlab_http_status(404) end end - context 'when authenticated as admin' do - it 'removes any existing project' do + context "when authenticated as admin" do + it "removes any existing project" do delete api("/projects/#{project.id}", admin) expect(response).to have_gitlab_http_status(202) - expect(json_response['message']).to eql('202 Accepted') + expect(json_response["message"]).to eql("202 Accepted") end - it 'does not remove a non existing project' do - delete api('/projects/1328', admin) + it "does not remove a non existing project" do + delete api("/projects/1328", admin) expect(response).to have_gitlab_http_status(404) end - it_behaves_like '412 response' do + it_behaves_like "412 response" do let(:success_status) { 202 } let(:request) { api("/projects/#{project.id}", admin) } end end end - describe 'POST /projects/:id/fork' do + describe "POST /projects/:id/fork" do let(:project) do create(:project, :repository, creator: user, namespace: user.namespace) end @@ -2028,13 +2027,13 @@ describe API::Projects do let(:group) { create(:group) } let(:group2) do - group = create(:group, name: 'group2_name') + group = create(:group, name: "group2_name") group.add_maintainer(user2) group end let(:group3) do - group = create(:group, name: 'group3_name', parent: group2) + group = create(:group, name: "group3_name", parent: group2) group.add_owner(user2) group end @@ -2044,181 +2043,181 @@ describe API::Projects do project2.add_reporter(user2) end - context 'when authenticated' do - it 'forks if user has sufficient access to project' do + context "when authenticated" do + it "forks if user has sufficient access to project" do post api("/projects/#{project.id}/fork", user2) expect(response).to have_gitlab_http_status(201) - expect(json_response['name']).to eq(project.name) - expect(json_response['path']).to eq(project.path) - expect(json_response['owner']['id']).to eq(user2.id) - expect(json_response['namespace']['id']).to eq(user2.namespace.id) - expect(json_response['forked_from_project']['id']).to eq(project.id) - expect(json_response['import_status']).to eq('scheduled') + expect(json_response["name"]).to eq(project.name) + expect(json_response["path"]).to eq(project.path) + expect(json_response["owner"]["id"]).to eq(user2.id) + expect(json_response["namespace"]["id"]).to eq(user2.namespace.id) + expect(json_response["forked_from_project"]["id"]).to eq(project.id) + expect(json_response["import_status"]).to eq("scheduled") expect(json_response).to include("import_error") end - it 'forks if user is admin' do + it "forks if user is admin" do post api("/projects/#{project.id}/fork", admin) expect(response).to have_gitlab_http_status(201) - expect(json_response['name']).to eq(project.name) - expect(json_response['path']).to eq(project.path) - expect(json_response['owner']['id']).to eq(admin.id) - expect(json_response['namespace']['id']).to eq(admin.namespace.id) - expect(json_response['forked_from_project']['id']).to eq(project.id) - expect(json_response['import_status']).to eq('scheduled') + expect(json_response["name"]).to eq(project.name) + expect(json_response["path"]).to eq(project.path) + expect(json_response["owner"]["id"]).to eq(admin.id) + expect(json_response["namespace"]["id"]).to eq(admin.namespace.id) + expect(json_response["forked_from_project"]["id"]).to eq(project.id) + expect(json_response["import_status"]).to eq("scheduled") expect(json_response).to include("import_error") end - it 'fails on missing project access for the project to fork' do + it "fails on missing project access for the project to fork" do new_user = create(:user) post api("/projects/#{project.id}/fork", new_user) expect(response).to have_gitlab_http_status(404) - expect(json_response['message']).to eq('404 Project Not Found') + expect(json_response["message"]).to eq("404 Project Not Found") end - it 'fails if forked project exists in the user namespace' do + it "fails if forked project exists in the user namespace" do post api("/projects/#{project.id}/fork", user) expect(response).to have_gitlab_http_status(409) - expect(json_response['message']['name']).to eq(['has already been taken']) - expect(json_response['message']['path']).to eq(['has already been taken']) + expect(json_response["message"]["name"]).to eq(["has already been taken"]) + expect(json_response["message"]["path"]).to eq(["has already been taken"]) end - it 'fails if project to fork from does not exist' do - post api('/projects/424242/fork', user) + it "fails if project to fork from does not exist" do + post api("/projects/424242/fork", user) expect(response).to have_gitlab_http_status(404) - expect(json_response['message']).to eq('404 Project Not Found') + expect(json_response["message"]).to eq("404 Project Not Found") end - it 'forks with explicit own user namespace id' do - post api("/projects/#{project.id}/fork", user2), params: { namespace: user2.namespace.id } + it "forks with explicit own user namespace id" do + post api("/projects/#{project.id}/fork", user2), params: {namespace: user2.namespace.id} expect(response).to have_gitlab_http_status(201) - expect(json_response['owner']['id']).to eq(user2.id) + expect(json_response["owner"]["id"]).to eq(user2.id) end - it 'forks with explicit own user name as namespace' do - post api("/projects/#{project.id}/fork", user2), params: { namespace: user2.username } + it "forks with explicit own user name as namespace" do + post api("/projects/#{project.id}/fork", user2), params: {namespace: user2.username} expect(response).to have_gitlab_http_status(201) - expect(json_response['owner']['id']).to eq(user2.id) + expect(json_response["owner"]["id"]).to eq(user2.id) end - it 'forks to another user when admin' do - post api("/projects/#{project.id}/fork", admin), params: { namespace: user2.username } + it "forks to another user when admin" do + post api("/projects/#{project.id}/fork", admin), params: {namespace: user2.username} expect(response).to have_gitlab_http_status(201) - expect(json_response['owner']['id']).to eq(user2.id) + expect(json_response["owner"]["id"]).to eq(user2.id) end - it 'fails if trying to fork to another user when not admin' do - post api("/projects/#{project.id}/fork", user2), params: { namespace: admin.namespace.id } + it "fails if trying to fork to another user when not admin" do + post api("/projects/#{project.id}/fork", user2), params: {namespace: admin.namespace.id} expect(response).to have_gitlab_http_status(404) end - it 'fails if trying to fork to non-existent namespace' do - post api("/projects/#{project.id}/fork", user2), params: { namespace: 42424242 } + it "fails if trying to fork to non-existent namespace" do + post api("/projects/#{project.id}/fork", user2), params: {namespace: 42424242} expect(response).to have_gitlab_http_status(404) - expect(json_response['message']).to eq('404 Target Namespace Not Found') + expect(json_response["message"]).to eq("404 Target Namespace Not Found") end - it 'forks to owned group' do - post api("/projects/#{project.id}/fork", user2), params: { namespace: group2.name } + it "forks to owned group" do + post api("/projects/#{project.id}/fork", user2), params: {namespace: group2.name} expect(response).to have_gitlab_http_status(201) - expect(json_response['namespace']['name']).to eq(group2.name) + expect(json_response["namespace"]["name"]).to eq(group2.name) end - it 'forks to owned subgroup' do + it "forks to owned subgroup" do full_path = "#{group2.path}/#{group3.path}" - post api("/projects/#{project.id}/fork", user2), params: { namespace: full_path } + post api("/projects/#{project.id}/fork", user2), params: {namespace: full_path} expect(response).to have_gitlab_http_status(201) - expect(json_response['namespace']['name']).to eq(group3.name) - expect(json_response['namespace']['full_path']).to eq(full_path) + expect(json_response["namespace"]["name"]).to eq(group3.name) + expect(json_response["namespace"]["full_path"]).to eq(full_path) end - it 'fails to fork to not owned group' do - post api("/projects/#{project.id}/fork", user2), params: { namespace: group.name } + it "fails to fork to not owned group" do + post api("/projects/#{project.id}/fork", user2), params: {namespace: group.name} expect(response).to have_gitlab_http_status(404) end - it 'forks to not owned group when admin' do - post api("/projects/#{project.id}/fork", admin), params: { namespace: group.name } + it "forks to not owned group when admin" do + post api("/projects/#{project.id}/fork", admin), params: {namespace: group.name} expect(response).to have_gitlab_http_status(201) - expect(json_response['namespace']['name']).to eq(group.name) + expect(json_response["namespace"]["name"]).to eq(group.name) end - it 'accepts a path for the target project' do - post api("/projects/#{project.id}/fork", user2), params: { path: 'foobar' } + it "accepts a path for the target project" do + post api("/projects/#{project.id}/fork", user2), params: {path: "foobar"} expect(response).to have_gitlab_http_status(201) - expect(json_response['name']).to eq(project.name) - expect(json_response['path']).to eq('foobar') - expect(json_response['owner']['id']).to eq(user2.id) - expect(json_response['namespace']['id']).to eq(user2.namespace.id) - expect(json_response['forked_from_project']['id']).to eq(project.id) - expect(json_response['import_status']).to eq('scheduled') + expect(json_response["name"]).to eq(project.name) + expect(json_response["path"]).to eq("foobar") + expect(json_response["owner"]["id"]).to eq(user2.id) + expect(json_response["namespace"]["id"]).to eq(user2.namespace.id) + expect(json_response["forked_from_project"]["id"]).to eq(project.id) + expect(json_response["import_status"]).to eq("scheduled") expect(json_response).to include("import_error") end - it 'fails to fork if path is already taken' do - post api("/projects/#{project.id}/fork", user2), params: { path: 'foobar' } - post api("/projects/#{project2.id}/fork", user2), params: { path: 'foobar' } + it "fails to fork if path is already taken" do + post api("/projects/#{project.id}/fork", user2), params: {path: "foobar"} + post api("/projects/#{project2.id}/fork", user2), params: {path: "foobar"} expect(response).to have_gitlab_http_status(409) - expect(json_response['message']['path']).to eq(['has already been taken']) + expect(json_response["message"]["path"]).to eq(["has already been taken"]) end - it 'accepts a name for the target project' do - post api("/projects/#{project.id}/fork", user2), params: { name: 'My Random Project' } + it "accepts a name for the target project" do + post api("/projects/#{project.id}/fork", user2), params: {name: "My Random Project"} expect(response).to have_gitlab_http_status(201) - expect(json_response['name']).to eq('My Random Project') - expect(json_response['path']).to eq(project.path) - expect(json_response['owner']['id']).to eq(user2.id) - expect(json_response['namespace']['id']).to eq(user2.namespace.id) - expect(json_response['forked_from_project']['id']).to eq(project.id) - expect(json_response['import_status']).to eq('scheduled') + expect(json_response["name"]).to eq("My Random Project") + expect(json_response["path"]).to eq(project.path) + expect(json_response["owner"]["id"]).to eq(user2.id) + expect(json_response["namespace"]["id"]).to eq(user2.namespace.id) + expect(json_response["forked_from_project"]["id"]).to eq(project.id) + expect(json_response["import_status"]).to eq("scheduled") expect(json_response).to include("import_error") end - it 'fails to fork if name is already taken' do - post api("/projects/#{project.id}/fork", user2), params: { name: 'My Random Project' } - post api("/projects/#{project2.id}/fork", user2), params: { name: 'My Random Project' } + it "fails to fork if name is already taken" do + post api("/projects/#{project.id}/fork", user2), params: {name: "My Random Project"} + post api("/projects/#{project2.id}/fork", user2), params: {name: "My Random Project"} expect(response).to have_gitlab_http_status(409) - expect(json_response['message']['name']).to eq(['has already been taken']) + expect(json_response["message"]["name"]).to eq(["has already been taken"]) end end - context 'when unauthenticated' do - it 'returns authentication error' do + context "when unauthenticated" do + it "returns authentication error" do post api("/projects/#{project.id}/fork") expect(response).to have_gitlab_http_status(401) - expect(json_response['message']).to eq('401 Unauthorized') + expect(json_response["message"]).to eq("401 Unauthorized") end end end - describe 'POST /projects/:id/housekeeping' do + describe "POST /projects/:id/housekeeping" do let(:housekeeping) { Projects::HousekeepingService.new(project) } before do allow(Projects::HousekeepingService).to receive(:new).with(project).and_return(housekeeping) end - context 'when authenticated as owner' do - it 'starts the housekeeping process' do + context "when authenticated as owner" do + it "starts the housekeeping process" do expect(housekeeping).to receive(:execute).once post api("/projects/#{project.id}/housekeeping", user) @@ -2226,32 +2225,32 @@ describe API::Projects do expect(response).to have_gitlab_http_status(201) end - context 'when housekeeping lease is taken' do - it 'returns conflict' do + context "when housekeeping lease is taken" do + it "returns conflict" do expect(housekeeping).to receive(:execute).once.and_raise(Projects::HousekeepingService::LeaseTaken) post api("/projects/#{project.id}/housekeeping", user) expect(response).to have_gitlab_http_status(409) - expect(json_response['message']).to match(/Somebody already triggered housekeeping for this project/) + expect(json_response["message"]).to match(/Somebody already triggered housekeeping for this project/) end end end - context 'when authenticated as developer' do + context "when authenticated as developer" do before do project_member end - it 'returns forbidden error' do + it "returns forbidden error" do post api("/projects/#{project.id}/housekeeping", user3) expect(response).to have_gitlab_http_status(403) end end - context 'when unauthenticated' do - it 'returns authentication error' do + context "when unauthenticated" do + it "returns authentication error" do post api("/projects/#{project.id}/housekeeping") expect(response).to have_gitlab_http_status(401) @@ -2259,31 +2258,31 @@ describe API::Projects do end end - describe 'PUT /projects/:id/transfer' do - context 'when authenticated as owner' do + describe "PUT /projects/:id/transfer" do + context "when authenticated as owner" do let(:group) { create :group } - it 'transfers the project to the new namespace' do + it "transfers the project to the new namespace" do group.add_owner(user) - put api("/projects/#{project.id}/transfer", user), params: { namespace: group.id } + put api("/projects/#{project.id}/transfer", user), params: {namespace: group.id} expect(response).to have_gitlab_http_status(200) end - it 'fails when transferring to a non owned namespace' do - put api("/projects/#{project.id}/transfer", user), params: { namespace: group.id } + it "fails when transferring to a non owned namespace" do + put api("/projects/#{project.id}/transfer", user), params: {namespace: group.id} expect(response).to have_gitlab_http_status(404) end - it 'fails when transferring to an unknown namespace' do - put api("/projects/#{project.id}/transfer", user), params: { namespace: 'unknown' } + it "fails when transferring to an unknown namespace" do + put api("/projects/#{project.id}/transfer", user), params: {namespace: "unknown"} expect(response).to have_gitlab_http_status(404) end - it 'fails on missing namespace' do + it "fails on missing namespace" do put api("/projects/#{project.id}/transfer", user) expect(response).to have_gitlab_http_status(400) @@ -2291,7 +2290,7 @@ describe API::Projects do end end - it_behaves_like 'custom attributes endpoints', 'projects' do + it_behaves_like "custom attributes endpoints", "projects" do let(:attributable) { project } let(:other_attributable) { project2 } end |