From 23288f62da73fb0e30d8e7ce306665e8fda1b932 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 29 Jan 2020 15:08:59 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../projects/merge_requests_controller_spec.rb | 15 ++ .../projects/repositories_controller_spec.rb | 12 +- spec/factories/merge_request_context_commit.rb | 12 ++ .../merge_request_context_commit_diff_file.rb | 20 +++ spec/features/groups/navbar_spec.rb | 51 ++++++ .../projects/files/user_browses_files_spec.rb | 25 +++ spec/features/projects/navbar_spec.rb | 104 ++++++++++++ spec/finders/context_commits_finder_spec.rb | 28 ++++ .../clusters/components/applications_spec.js | 3 - .../attr_encrypted_thread_safe_spec.rb | 28 ++++ spec/lib/gitlab/database/sha_attribute_spec.rb | 2 +- spec/lib/gitlab/import_export/all_models.yml | 5 + .../gitlab/import_export/safe_model_attributes.yml | 25 +++ .../merge_request_context_commit_diff_file_spec.rb | 9 ++ spec/models/merge_request_context_commit_spec.rb | 33 ++++ spec/models/merge_request_diff_commit_spec.rb | 7 +- spec/requests/api/internal/base_spec.rb | 6 +- spec/requests/api/merge_requests_spec.rb | 177 ++++++++++++++++++++- spec/serializers/diffs_metadata_entity_spec.rb | 1 + .../merge_requests/add_context_service_spec.rb | 44 +++++ .../features/navbar_shared_examples.rb | 20 +++ 21 files changed, 614 insertions(+), 13 deletions(-) create mode 100644 spec/factories/merge_request_context_commit.rb create mode 100644 spec/factories/merge_request_context_commit_diff_file.rb create mode 100644 spec/features/groups/navbar_spec.rb create mode 100644 spec/features/projects/navbar_spec.rb create mode 100644 spec/finders/context_commits_finder_spec.rb create mode 100644 spec/initializers/attr_encrypted_thread_safe_spec.rb create mode 100644 spec/models/merge_request_context_commit_diff_file_spec.rb create mode 100644 spec/models/merge_request_context_commit_spec.rb create mode 100644 spec/services/merge_requests/add_context_service_spec.rb create mode 100644 spec/support/shared_examples/features/navbar_shared_examples.rb (limited to 'spec') diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 826c69ee5f0..da26eb94fb0 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -791,6 +791,21 @@ describe Projects::MergeRequestsController do end end + describe 'GET context commits' do + it 'returns the commits for context commits' do + get :context_commits, + params: { + namespace_id: project.namespace.to_param, + project_id: project, + id: merge_request.iid + }, + format: 'json' + + expect(response).to have_gitlab_http_status(:success) + expect(json_response).to be_an Array + end + end + describe 'GET exposed_artifacts' do let(:merge_request) do create(:merge_request, diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb index aeb053fe9f6..42dfdd3115c 100644 --- a/spec/controllers/projects/repositories_controller_spec.rb +++ b/spec/controllers/projects/repositories_controller_spec.rb @@ -17,6 +17,7 @@ describe Projects::RepositoriesController do context 'as a user' do let(:user) { create(:user) } + let(:archive_name) { "#{project.path}-master" } before do project.add_developer(user) @@ -30,9 +31,18 @@ describe Projects::RepositoriesController do end it 'responds with redirect to the short name archive if fully qualified' do - get :archive, params: { namespace_id: project.namespace, project_id: project, id: "master/#{project.path}-master" }, format: "zip" + get :archive, params: { namespace_id: project.namespace, project_id: project, id: "master/#{archive_name}" }, format: "zip" expect(assigns(:ref)).to eq("master") + expect(assigns(:filename)).to eq(archive_name) + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-archive:") + end + + it 'responds with redirect for a path with multiple slashes' do + get :archive, params: { namespace_id: project.namespace, project_id: project, id: "improve/awesome/#{archive_name}" }, format: "zip" + + expect(assigns(:ref)).to eq("improve/awesome") + expect(assigns(:filename)).to eq(archive_name) expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-archive:") end diff --git a/spec/factories/merge_request_context_commit.rb b/spec/factories/merge_request_context_commit.rb new file mode 100644 index 00000000000..f9bfc9af02e --- /dev/null +++ b/spec/factories/merge_request_context_commit.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :merge_request_context_commit do + association :merge_request, factory: :merge_request + author_name { 'test' } + author_email { 'test@test.com' } + message { '' } + relative_order { 0 } + sha { Digest::SHA1.hexdigest(SecureRandom.hex) } + end +end diff --git a/spec/factories/merge_request_context_commit_diff_file.rb b/spec/factories/merge_request_context_commit_diff_file.rb new file mode 100644 index 00000000000..eb497166d05 --- /dev/null +++ b/spec/factories/merge_request_context_commit_diff_file.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :merge_request_context_commit_diff_file do + association :merge_request_context_commit + + sha { Digest::SHA1.hexdigest(SecureRandom.hex) } + relative_order { 0 } + new_file { true } + renamed_file { false } + deleted_file { false } + too_large { false } + a_mode { 0 } + b_mode { 100644 } + new_path { 'foo' } + old_path { 'foo' } + diff { '' } + binary { false } + end +end diff --git a/spec/features/groups/navbar_spec.rb b/spec/features/groups/navbar_spec.rb new file mode 100644 index 00000000000..e348eb80b1a --- /dev/null +++ b/spec/features/groups/navbar_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Group navbar' do + it_behaves_like 'verified navigation bar' do + let(:user) { create(:user) } + let(:group) { create(:group) } + + let(:structure) do + [ + { + nav_item: _('Group overview'), + nav_sub_items: [ + _('Details'), + _('Activity'), + (_('Contribution Analytics') if Gitlab.ee?) + ] + }, + { + nav_item: _('Issues'), + nav_sub_items: [ + _('List'), + _('Board'), + _('Labels'), + _('Milestones') + ] + }, + { + nav_item: _('Merge Requests'), + nav_sub_items: [] + }, + { + nav_item: _('Kubernetes'), + nav_sub_items: [] + }, + { + nav_item: _('Members'), + nav_sub_items: [] + } + ] + end + + before do + group.add_maintainer(user) + sign_in(user) + + visit group_path(group) + end + end +end diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb index b8efabb0cab..5364bc10b2f 100644 --- a/spec/features/projects/files/user_browses_files_spec.rb +++ b/spec/features/projects/files/user_browses_files_spec.rb @@ -171,6 +171,31 @@ describe "User browses files" do end end + context "when browsing a `improve/awesome` branch", :js do + before do + visit(project_tree_path(project, "improve/awesome")) + end + + it "shows files from a repository" do + expect(page).to have_content("VERSION") + .and have_content(".gitignore") + .and have_content("LICENSE") + end + end + + context "when browsing a `test-#` branch", :js do + before do + project.repository.create_branch('test-#', project.repository.root_ref) + visit(project_tree_path(project, "test-#")) + end + + it "shows files from a repository" do + expect(page).to have_content("VERSION") + .and have_content(".gitignore") + .and have_content("LICENSE") + end + end + context "when browsing a specific ref", :js do let(:ref) { project_tree_path(project, "6d39438") } diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb new file mode 100644 index 00000000000..f87bd5ca529 --- /dev/null +++ b/spec/features/projects/navbar_spec.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Project navbar' do + it_behaves_like 'verified navigation bar' do + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } + + let(:structure) do + [ + { + nav_item: _('Project overview'), + nav_sub_items: [ + _('Details'), + _('Activity'), + _('Releases') + ] + }, + { + nav_item: _('Repository'), + nav_sub_items: [ + _('Files'), + _('Commits'), + _('Branches'), + _('Tags'), + _('Contributors'), + _('Graph'), + _('Compare'), + (_('Locked Files') if Gitlab.ee?) + ] + }, + { + nav_item: _('Issues'), + nav_sub_items: [ + _('List'), + _('Boards'), + _('Labels'), + _('Milestones') + ] + }, + { + nav_item: _('Merge Requests'), + nav_sub_items: [] + }, + { + nav_item: _('CI / CD'), + nav_sub_items: [ + _('Pipelines'), + _('Jobs'), + _('Artifacts'), + _('Schedules') + ] + }, + { + nav_item: _('Operations'), + nav_sub_items: [ + _('Metrics'), + _('Environments'), + _('Error Tracking'), + _('Serverless'), + _('Kubernetes'), + _('Auto DevOps') + ] + }, + { + nav_item: _('Analytics'), + nav_sub_items: [ + (_('Code Review') if Gitlab.ee?), + _('Cycle Analytics'), + _('Repository Analytics') + ] + }, + { + nav_item: _('Wiki'), + nav_sub_items: [] + }, + { + nav_item: _('Snippets'), + nav_sub_items: [] + }, + { + nav_item: _('Settings'), + nav_sub_items: [ + _('General'), + _('Members'), + _('Integrations'), + _('Repository'), + _('CI / CD'), + _('Operations'), + (_('Audit Events') if Gitlab.ee?) + ].compact + } + ] + end + + before do + project.add_maintainer(user) + sign_in(user) + + visit project_path(project) + end + end +end diff --git a/spec/finders/context_commits_finder_spec.rb b/spec/finders/context_commits_finder_spec.rb new file mode 100644 index 00000000000..13cfa32ecfc --- /dev/null +++ b/spec/finders/context_commits_finder_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ContextCommitsFinder do + describe "#execute" do + let(:project) { create(:project, :repository) } + let(:merge_request) { create(:merge_request) } + let(:commit) { create(:commit, id: '6d394385cf567f80a8fd85055db1ab4c5295806f') } + + it 'filters commits by valid sha/commit message' do + params = { search: commit.id } + + commits = described_class.new(project, merge_request, params).execute + + expect(commits.length).to eq(1) + expect(commits[0].id).to eq(commit.id) + end + + it 'returns nothing when searched by invalid sha/commit message' do + params = { search: 'zzz' } + + commits = described_class.new(project, merge_request, params).execute + + expect(commits).to be_empty + end + end +end diff --git a/spec/frontend/clusters/components/applications_spec.js b/spec/frontend/clusters/components/applications_spec.js index 01e9b04dcd7..c3336edfe59 100644 --- a/spec/frontend/clusters/components/applications_spec.js +++ b/spec/frontend/clusters/components/applications_spec.js @@ -14,9 +14,6 @@ describe('Applications', () => { beforeEach(() => { Applications = Vue.extend(applications); - - gon.features = gon.features || {}; - gon.features.enableClusterApplicationElasticStack = true; }); afterEach(() => { diff --git a/spec/initializers/attr_encrypted_thread_safe_spec.rb b/spec/initializers/attr_encrypted_thread_safe_spec.rb new file mode 100644 index 00000000000..096b8b196b4 --- /dev/null +++ b/spec/initializers/attr_encrypted_thread_safe_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe AttrEncrypted do + describe '#encrypted_attributes' do + subject do + Class.new(ActiveRecord::Base) do + self.table_name = 'projects' + + attr_accessor :encrypted_foo + attr_accessor :encrypted_foo_iv + + attr_encrypted :foo, key: 'This is a key that is 256 bits!!' + end + end + + it 'does not share state with other instances' do + instance = subject.new + instance.foo = 'bar' + + another_instance = subject.new + + expect(instance.encrypted_attributes[:foo][:operation]).to eq(:encrypting) + expect(another_instance.encrypted_attributes[:foo][:operation]).to be_nil + end + end +end diff --git a/spec/lib/gitlab/database/sha_attribute_spec.rb b/spec/lib/gitlab/database/sha_attribute_spec.rb index c6fc55291f5..15695bc8069 100644 --- a/spec/lib/gitlab/database/sha_attribute_spec.rb +++ b/spec/lib/gitlab/database/sha_attribute_spec.rb @@ -25,7 +25,7 @@ describe Gitlab::Database::ShaAttribute do describe '#serialize' do it 'converts a SHA String to binary data' do - expect(attribute.serialize(sha).to_s).to eq(binary_sha) + expect(described_class.serialize(sha).to_s).to eq(binary_sha) end end end diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 08e57e541a4..22c2fc5545e 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -125,6 +125,8 @@ merge_requests: - merge_user - merge_request_diffs - merge_request_diff +- merge_request_context_commits +- merge_request_context_commit_diff_files - events - merge_requests_closing_issues - cached_closes_issues @@ -170,6 +172,9 @@ merge_request_diff_commits: - merge_request_diff merge_request_diff_files: - merge_request_diff +merge_request_context_commits: +- merge_request +- diff_files ci_pipelines: - project - user diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index ad363233bfe..9c4854a30ad 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -225,6 +225,31 @@ MergeRequestDiffFile: - b_mode - too_large - binary +MergeRequestContextCommit: +- id +- authored_date +- committed_date +- relative_order +- sha +- author_name +- author_email +- committer_name +- committer_email +- message +- merge_request_id +MergeRequestContextCommitDiffFile: +- sha +- relative_order +- new_file +- renamed_file +- deleted_file +- new_path +- old_path +- a_mode +- b_mode +- too_large +- binary +- text MergeRequest::Metrics: - id - created_at diff --git a/spec/models/merge_request_context_commit_diff_file_spec.rb b/spec/models/merge_request_context_commit_diff_file_spec.rb new file mode 100644 index 00000000000..37d44662326 --- /dev/null +++ b/spec/models/merge_request_context_commit_diff_file_spec.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe MergeRequestContextCommitDiffFile do + describe 'associations' do + it { is_expected.to belong_to(:merge_request_context_commit) } + end +end diff --git a/spec/models/merge_request_context_commit_spec.rb b/spec/models/merge_request_context_commit_spec.rb new file mode 100644 index 00000000000..5a1bf9874ac --- /dev/null +++ b/spec/models/merge_request_context_commit_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe MergeRequestContextCommit do + let(:merge_request) { create(:merge_request) } + let(:project) { merge_request.project } + let(:raw_repository) { project.repository.raw_repository } + let(:commits) do + [ + project.commit('5937ac0a7beb003549fc5fd26fc247adbce4a52e'), + project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') + ] + end + + describe 'associations' do + it { is_expected.to belong_to(:merge_request) } + it { is_expected.to have_many(:diff_files).class_name("MergeRequestContextCommitDiffFile") } + end + + describe '.delete_bulk' do + let(:context_commit1) { create(:merge_request_context_commit, merge_request: merge_request, sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') } + let(:context_commit2) { create(:merge_request_context_commit, merge_request: merge_request, sha: '570e7b2abdd848b95f2f578043fc23bd6f6fd24d') } + + it 'deletes context commits for given commit sha\'s and returns the commit' do + expect(described_class.delete_bulk(merge_request, [context_commit1, context_commit2])).to eq(2) + end + + it 'doesn\'t delete context commits when commit sha\'s are not passed' do + expect(described_class.delete_bulk(merge_request, [])).to eq(0) + end + end +end diff --git a/spec/models/merge_request_diff_commit_spec.rb b/spec/models/merge_request_diff_commit_spec.rb index c0a09dab0b0..a74c0b20642 100644 --- a/spec/models/merge_request_diff_commit_spec.rb +++ b/spec/models/merge_request_diff_commit_spec.rb @@ -18,7 +18,6 @@ describe MergeRequestDiffCommit do end describe '.create_bulk' do - let(:sha_attribute) { Gitlab::Database::ShaAttribute.new } let(:merge_request_diff_id) { merge_request.merge_request_diff.id } let(:commits) do [ @@ -38,7 +37,7 @@ describe MergeRequestDiffCommit do "committer_email": "dmitriy.zaporozhets@gmail.com", "merge_request_diff_id": merge_request_diff_id, "relative_order": 0, - "sha": sha_attribute.serialize("5937ac0a7beb003549fc5fd26fc247adbce4a52e") + "sha": Gitlab::Database::ShaAttribute.serialize("5937ac0a7beb003549fc5fd26fc247adbce4a52e") }, { "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", @@ -50,7 +49,7 @@ describe MergeRequestDiffCommit do "committer_email": "dmitriy.zaporozhets@gmail.com", "merge_request_diff_id": merge_request_diff_id, "relative_order": 1, - "sha": sha_attribute.serialize("570e7b2abdd848b95f2f578043fc23bd6f6fd24d") + "sha": Gitlab::Database::ShaAttribute.serialize("570e7b2abdd848b95f2f578043fc23bd6f6fd24d") } ] end @@ -81,7 +80,7 @@ describe MergeRequestDiffCommit do "committer_email": "alejorro70@gmail.com", "merge_request_diff_id": merge_request_diff_id, "relative_order": 0, - "sha": sha_attribute.serialize("ba3343bc4fa403a8dfbfcab7fc1a8c29ee34bd69") + "sha": Gitlab::Database::ShaAttribute.serialize("ba3343bc4fa403a8dfbfcab7fc1a8c29ee34bd69") }] end diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb index 93feef83067..cb10bebfd98 100644 --- a/spec/requests/api/internal/base_spec.rb +++ b/spec/requests/api/internal/base_spec.rb @@ -326,7 +326,7 @@ describe API::Internal::Base do expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path) expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage)) expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage)) - expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-cache-invalidator' => 'true', 'gitaly-feature-commit-without-batch-check' => 'true') + expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-cache-invalidator' => 'true', 'gitaly-feature-commit-without-batch-check' => 'true', 'gitaly-feature-use-core-delta-islands' => 'true') expect(user.reload.last_activity_on).to eql(Date.today) end end @@ -346,7 +346,7 @@ describe API::Internal::Base do expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path) expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage)) expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage)) - expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-cache-invalidator' => 'true', 'gitaly-feature-commit-without-batch-check' => 'true') + expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-cache-invalidator' => 'true', 'gitaly-feature-commit-without-batch-check' => 'true', 'gitaly-feature-use-core-delta-islands' => 'true') expect(user.reload.last_activity_on).to be_nil end end @@ -594,7 +594,7 @@ describe API::Internal::Base do expect(json_response["gitaly"]["repository"]["relative_path"]).to eq(project.repository.gitaly_repository.relative_path) expect(json_response["gitaly"]["address"]).to eq(Gitlab::GitalyClient.address(project.repository_storage)) expect(json_response["gitaly"]["token"]).to eq(Gitlab::GitalyClient.token(project.repository_storage)) - expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-cache-invalidator' => 'true', 'gitaly-feature-commit-without-batch-check' => 'true') + expect(json_response["gitaly"]["features"]).to eq('gitaly-feature-inforef-uploadpack-cache' => 'true', 'gitaly-feature-cache-invalidator' => 'true', 'gitaly-feature-commit-without-batch-check' => 'true', 'gitaly-feature-use-core-delta-islands' => 'true') end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index c3d92a90d11..58ae4565582 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -12,7 +12,8 @@ describe API::MergeRequests do let(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace, only_allow_merge_if_pipeline_succeeds: false) } let(:milestone) { create(:milestone, title: '1.0.0', project: project) } let(:milestone1) { create(:milestone, title: '0.9', project: project) } - let!(:merge_request) { create(:merge_request, :simple, milestone: milestone1, author: user, assignees: [user], source_project: project, target_project: project, source_branch: 'markdown', title: "Test", created_at: base_time) } + let(:merge_request_context_commit) {create(:merge_request_context_commit, message: 'test')} + let!(:merge_request) { create(:merge_request, :simple, milestone: milestone1, author: user, assignees: [user], merge_request_context_commits: [merge_request_context_commit], source_project: project, target_project: project, source_branch: 'markdown', title: "Test", created_at: base_time) } let!(:merge_request_closed) { create(:merge_request, state: "closed", milestone: milestone1, author: user, assignees: [user], source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) } let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignees: [user], source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') } let!(:merge_request_locked) { create(:merge_request, state: "locked", milestone: milestone1, author: user, assignees: [user], source_project: project, target_project: project, title: "Locked test", created_at: base_time + 1.second) } @@ -1066,6 +1067,20 @@ describe API::MergeRequests do end end + describe 'GET /projects/:id/merge_requests/:merge_request_iid/:context_commits' do + it 'returns a 200 when merge request is valid' do + get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/context_commits", user) + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(merge_request.context_commits.size) + end + + it 'returns a 404 when merge_request_iid not found' do + get api("/projects/#{project.id}/merge_requests/0/context_commits", user) + expect(response).to have_gitlab_http_status(404) + end + end + describe 'GET /projects/:id/merge_requests/:merge_request_iid/changes' do it 'returns the change information of the merge_request' do get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/changes", user) @@ -1540,6 +1555,93 @@ describe API::MergeRequests do end end + describe "POST /projects/:id/merge_requests/:merge_request_iid/context_commits" do + let(:merge_request_iid) { merge_request.iid } + let(:authenticated_user) { user } + let(:commit) { project.repository.commit } + + let(:params) do + { + commits: [commit.id] + } + end + + let(:params_empty_commits) do + { + commits: [] + } + end + + let(:params_invalid_shas) do + { + commits: ['invalid'] + } + end + + describe 'when authenticated' do + it 'creates and returns the new context commit' do + post api("/projects/#{project.id}/merge_requests/#{merge_request_iid}/context_commits", authenticated_user), params: params + expect(response).to have_gitlab_http_status(201) + expect(json_response).to be_an Array + expect(json_response.first['short_id']).to eq(commit.short_id) + expect(json_response.first['title']).to eq(commit.title) + expect(json_response.first['message']).to eq(commit.message) + expect(json_response.first['author_name']).to eq(commit.author_name) + expect(json_response.first['author_email']).to eq(commit.author_email) + expect(json_response.first['committer_name']).to eq(commit.committer_name) + expect(json_response.first['committer_email']).to eq(commit.committer_email) + end + + context 'doesnt create when its already created' do + before do + create(:merge_request_context_commit, merge_request: merge_request, sha: commit.id) + end + it 'returns 400 when the context commit is already created' do + post api("/projects/#{project.id}/merge_requests/#{merge_request_iid}/context_commits", authenticated_user), params: params + expect(response).to have_gitlab_http_status(400) + expect(json_response['message']).to eq("Context commits: [\"#{commit.id}\"] are already created") + end + end + + it 'returns 400 when one or more shas are invalid' do + post api("/projects/#{project.id}/merge_requests/#{merge_request_iid}/context_commits", authenticated_user), params: params_invalid_shas + expect(response).to have_gitlab_http_status(400) + expect(json_response['message']).to eq('One or more context commits\' sha is not valid.') + end + + it 'returns 400 when the commits are empty' do + post api("/projects/#{project.id}/merge_requests/#{merge_request_iid}/context_commits", authenticated_user), params: params_empty_commits + expect(response).to have_gitlab_http_status(400) + end + + it 'returns 400 when params is empty' do + post api("/projects/#{project.id}/merge_requests/#{merge_request_iid}/context_commits", authenticated_user) + expect(response).to have_gitlab_http_status(400) + end + + it 'returns 403 when creating new context commit for guest role' do + guest = create(:user) + project.add_guest(guest) + post api("/projects/#{project.id}/merge_requests/#{merge_request_iid}/context_commits", guest), params: params + expect(response).to have_gitlab_http_status(403) + end + + it 'returns 403 when creating new context commit for reporter role' do + reporter = create(:user) + project.add_reporter(reporter) + post api("/projects/#{project.id}/merge_requests/#{merge_request_iid}/context_commits", reporter), params: params + expect(response).to have_gitlab_http_status(403) + end + end + + context 'when unauthenticated' do + it 'returns 401 if user tries to create context commits' do + post api("/projects/#{project.id}/merge_requests/#{merge_request_iid}/context_commits"), params: params + expect(response).to have_gitlab_http_status(401) + end + end + end + describe "DELETE /projects/:id/merge_requests/:merge_request_iid" do context "when the user is developer" do let(:developer) { create(:user) } @@ -1579,6 +1681,79 @@ describe API::MergeRequests do end end + describe "DELETE /projects/:id/merge_requests/:merge_request_iid/context_commits" do + let(:merge_request_iid) { merge_request.iid } + let(:authenticated_user) { user } + let(:commit) { project.repository.commit } + + context "when authenticated" do + let(:params) do + { + commits: [commit.id] + } + end + + let(:params_invalid_shas) do + { + commits: ["invalid"] + } + end + + let(:params_empty_commits) do + { + commits: [] + } + end + + it "deletes context commit" do + delete api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/context_commits", authenticated_user), params: params + + expect(response).to have_gitlab_http_status(204) + end + + it "returns 400 when invalid commit sha is passed" do + delete api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/context_commits", authenticated_user), params: params_invalid_shas + + expect(response).to have_gitlab_http_status(400) + expect(json_response["message"]).to eq('One or more context commits\' sha is not valid.') + end + + it "returns 400 when commits is empty" do + delete api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/context_commits", authenticated_user), params: params_empty_commits + + expect(response).to have_gitlab_http_status(400) + end + + it "returns 400 when no params is passed" do + delete api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/context_commits", authenticated_user) + + expect(response).to have_gitlab_http_status(400) + end + + it 'returns 403 when deleting existing context commit for guest role' do + guest = create(:user) + project.add_guest(guest) + delete api("/projects/#{project.id}/merge_requests/#{merge_request_iid}/context_commits", guest), params: params + expect(response).to have_gitlab_http_status(403) + end + + it 'returns 403 when deleting existing context commit for reporter role' do + reporter = create(:user) + project.add_reporter(reporter) + delete api("/projects/#{project.id}/merge_requests/#{merge_request_iid}/context_commits", reporter), params: params + expect(response).to have_gitlab_http_status(403) + end + end + + context "when unauthenticated" do + it "returns 401, unauthorised error" do + delete api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/context_commits") + + expect(response).to have_gitlab_http_status(401) + end + end + end + describe "PUT /projects/:id/merge_requests/:merge_request_iid/merge", :clean_gitlab_redis_cache do let(:pipeline) { create(:ci_pipeline) } diff --git a/spec/serializers/diffs_metadata_entity_spec.rb b/spec/serializers/diffs_metadata_entity_spec.rb index 0fa643d37b3..86438bd59d7 100644 --- a/spec/serializers/diffs_metadata_entity_spec.rb +++ b/spec/serializers/diffs_metadata_entity_spec.rb @@ -29,6 +29,7 @@ describe DiffsMetadataEntity do :added_lines, :removed_lines, :render_overflow_warning, :email_patch_path, :plain_diff_path, :merge_request_diffs, + :context_commits, # Attributes :diff_files ) diff --git a/spec/services/merge_requests/add_context_service_spec.rb b/spec/services/merge_requests/add_context_service_spec.rb new file mode 100644 index 00000000000..d4e95c2f1ea --- /dev/null +++ b/spec/services/merge_requests/add_context_service_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe MergeRequests::AddContextService do + let(:project) { create(:project, :repository) } + let(:admin) { create(:admin) } + let(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: admin) } + let(:commits) { ["874797c3a73b60d2187ed6e2fcabd289ff75171e"] } + let(:raw_repository) { project.repository.raw } + + subject(:service) { described_class.new(project, admin, merge_request: merge_request, commits: commits) } + + describe "#execute" do + it "adds context commit" do + service.execute + + expect(merge_request.merge_request_context_commit_diff_files.length).to eq(2) + end + + context "when user doesn't have permission to update merge request" do + let(:user) { create(:user) } + let(:merge_request1) { create(:merge_request, source_project: project, author: user) } + + subject(:service) { described_class.new(project, user, merge_request: merge_request, commits: commits) } + + it "doesn't add context commit" do + subject.execute + + expect(merge_request.merge_request_context_commit_diff_files.length).to eq(0) + end + end + + context "when the commits array is empty" do + subject(:service) { described_class.new(project, admin, merge_request: merge_request, commits: []) } + + it "doesn't add context commit" do + subject.execute + + expect(merge_request.merge_request_context_commit_diff_files.length).to eq(0) + end + end + end +end diff --git a/spec/support/shared_examples/features/navbar_shared_examples.rb b/spec/support/shared_examples/features/navbar_shared_examples.rb new file mode 100644 index 00000000000..a963739878e --- /dev/null +++ b/spec/support/shared_examples/features/navbar_shared_examples.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'verified navigation bar' do + it 'renders correctly' do + current_structure = page.find_all('.sidebar-top-level-items > li', class: ['!hidden']).map do |item| + nav_item = item.find_all('a').first.text.gsub(/\s+\d+$/, '') # remove counts at the end + + nav_sub_items = item + .find_all('.sidebar-sub-level-items a') + .map(&:text) + .drop(1) # remove the first hidden item + + { nav_item: nav_item, nav_sub_items: nav_sub_items } + end + + structure.each { |s| s[:nav_sub_items].compact! } + + expect(current_structure).to eq(structure) + end +end -- cgit v1.2.3