diff options
author | Bob Van Landuyt <bob@vanlanduyt.co> | 2018-10-24 18:01:44 +0200 |
---|---|---|
committer | Bob Van Landuyt <bob@vanlanduyt.co> | 2018-11-07 16:27:55 +0100 |
commit | 6fbdc5ed5224154b89cf351e11a8f9db48e6d7f0 (patch) | |
tree | dd2ccecd4b1100d4b83f91292b96ec988eecde6d /spec/lib | |
parent | 6d8810a64f944ff96af54e5c759f866bb68a7453 (diff) | |
download | gitlab-ce-6fbdc5ed5224154b89cf351e11a8f9db48e6d7f0.tar.gz |
Apply patches when creating MR via email
This allows users to add patches as attachments to merge request
created via email.
When an email to create a merge request is sent, all the attachments
ending in `.patch` will be applied to the branch specified in the
subject of the email. If the branch did not exist, it will be created
from the HEAD of the repository.
When the patches could not be applied, the error message will be
replied to the user.
The patches can have a maximum combined size of 2MB for now.
Diffstat (limited to 'spec/lib')
5 files changed, 195 insertions, 0 deletions
diff --git a/spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb b/spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb index ace3104f36f..f276f1a8ddf 100644 --- a/spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb @@ -93,5 +93,74 @@ describe Gitlab::Email::Handler::CreateMergeRequestHandler do end end end + + context 'when the email contains patch attachments' do + let(:email_raw) { fixture_file("emails/valid_merge_request_with_patch.eml") } + + it 'creates the source branch and applies the patches' do + receiver.execute + + branch = project.repository.find_branch('new-branch-with-a-patch') + + expect(branch).not_to be_nil + expect(branch.dereferenced_target.message).to include('A commit from a patch') + end + + it 'creates the merge request' do + expect { receiver.execute } + .to change { project.merge_requests.where(source_branch: 'new-branch-with-a-patch').size }.by(1) + end + + it 'does not mention the patches in the created merge request' do + receiver.execute + + merge_request = project.merge_requests.find_by!(source_branch: 'new-branch-with-a-patch') + + expect(merge_request.description).not_to include('0001-A-commit-from-a-patch.patch') + end + + context 'when the patch could not be applied' do + let(:email_raw) { fixture_file("emails/merge_request_with_conflicting_patch.eml") } + + it 'raises an error' do + expect { receiver.execute }.to raise_error(Gitlab::Email::InvalidAttachment) + end + end + + context 'when specifying the target branch using quick actions' do + let(:email_raw) { fixture_file('emails/merge_request_with_patch_and_target_branch.eml') } + + it 'creates the merge request with the correct target branch' do + receiver.execute + + merge_request = project.merge_requests.find_by!(source_branch: 'new-branch-with-a-patch') + + expect(merge_request.target_branch).to eq('with-codeowners') + end + + it 'based the merge request of the target_branch' do + receiver.execute + + merge_request = project.merge_requests.find_by!(source_branch: 'new-branch-with-a-patch') + + expect(merge_request.diff_base_commit).to eq(project.repository.commit('with-codeowners')) + end + end + end + end + + describe '#patch_attachments' do + let(:email_raw) { fixture_file('emails/merge_request_multiple_patches.eml') } + let(:mail) { Mail::Message.new(email_raw) } + subject(:handler) { described_class.new(mail, mail_key) } + + it 'orders attachments ending in `.patch` by name' do + expected_filenames = ["0001-A-commit-from-a-patch.patch", + "0002-This-does-not-apply-to-the-feature-branch.patch"] + + attachments = handler.__send__(:patch_attachments).map(&:filename) + + expect(attachments).to eq(expected_filenames) + end end end diff --git a/spec/lib/gitlab/git/patches/collection_spec.rb b/spec/lib/gitlab/git/patches/collection_spec.rb new file mode 100644 index 00000000000..080be141c59 --- /dev/null +++ b/spec/lib/gitlab/git/patches/collection_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Gitlab::Git::Patches::Collection do + let(:patches_folder) { Rails.root.join('spec/fixtures/patchfiles') } + let(:patch_content1) do + File.read(File.join(patches_folder, "0001-This-does-not-apply-to-the-feature-branch.patch")) + end + let(:patch_content2) do + File.read(File.join(patches_folder, "0001-A-commit-from-a-patch.patch")) + end + + subject(:collection) { described_class.new([patch_content1, patch_content2]) } + + describe '#size' do + it 'combines the size of the patches' do + expect(collection.size).to eq(549.bytes + 424.bytes) + end + end + + describe '#valid_size?' do + it 'is not valid if the total size is bigger than 2MB' do + expect(collection).to receive(:size).and_return(2500.kilobytes) + + expect(collection).not_to be_valid_size + end + end +end diff --git a/spec/lib/gitlab/git/patches/commit_patches_spec.rb b/spec/lib/gitlab/git/patches/commit_patches_spec.rb new file mode 100644 index 00000000000..760112155ce --- /dev/null +++ b/spec/lib/gitlab/git/patches/commit_patches_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Gitlab::Git::Patches::CommitPatches do + describe '#commit' do + let(:patches) do + patches_folder = Rails.root.join('spec/fixtures/patchfiles') + content_1 = File.read(File.join(patches_folder, "0001-This-does-not-apply-to-the-feature-branch.patch")) + content_2 = File.read(File.join(patches_folder, "0001-A-commit-from-a-patch.patch")) + + Gitlab::Git::Patches::Collection.new([content_1, content_2]) + end + let(:user) { build(:user) } + let(:branch_name) { 'branch-with-patches' } + let(:repository) { create(:project, :repository).repository } + + subject(:commit_patches) do + described_class.new(user, repository, branch_name, patches) + end + + it 'applies the patches' do + new_rev = commit_patches.commit + + expect(repository.commit(new_rev)).not_to be_nil + end + + it 'updates the branch cache' do + expect(repository).to receive(:after_create_branch) + + commit_patches.commit + end + + context 'when the repository does not exist' do + let(:repository) { create(:project).repository } + + it 'raises the correct error' do + expect { commit_patches.commit }.to raise_error(Gitlab::Git::Repository::NoRepository) + end + end + + context 'when the patch does not apply' do + let(:branch_name) { 'feature' } + + it 'raises the correct error' do + expect { commit_patches.commit }.to raise_error(Gitlab::Git::CommandError) + end + end + end +end diff --git a/spec/lib/gitlab/git/patches/patch_spec.rb b/spec/lib/gitlab/git/patches/patch_spec.rb new file mode 100644 index 00000000000..7466e853b65 --- /dev/null +++ b/spec/lib/gitlab/git/patches/patch_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Gitlab::Git::Patches::Patch do + let(:patches_folder) { Rails.root.join('spec/fixtures/patchfiles') } + let(:patch_content) do + File.read(File.join(patches_folder, "0001-This-does-not-apply-to-the-feature-branch.patch")) + end + let(:patch) { described_class.new(patch_content) } + + describe '#size' do + it 'is correct' do + expect(patch.size).to eq(549.bytes) + end + end +end diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb index eaf64e3c9b4..b37fe2686b6 100644 --- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb @@ -335,4 +335,37 @@ describe Gitlab::GitalyClient::OperationService do end end end + + describe '#user_commit_patches' do + let(:patches_folder) { Rails.root.join('spec/fixtures/patchfiles') } + let(:patch_content) do + patch_names.map { |name| File.read(File.join(patches_folder, name)) }.join("\n") + end + let(:patch_names) { %w(0001-This-does-not-apply-to-the-feature-branch.patch) } + let(:branch_name) { 'branch-with-patches' } + + subject(:commit_patches) do + client.user_commit_patches(user, branch_name, patch_content) + end + + it 'applies the patch correctly' do + branch_update = commit_patches + + expect(branch_update).to be_branch_created + + commit = repository.commit(branch_update.newrev) + expect(commit.author_email).to eq('patchuser@gitlab.org') + expect(commit.committer_email).to eq(user.email) + expect(commit.message.chomp).to eq('This does not apply to the `feature` branch') + end + + context 'when the patch could not be applied' do + let(:patch_names) { %w(0001-This-does-not-apply-to-the-feature-branch.patch) } + let(:branch_name) { 'feature' } + + it 'raises the correct error' do + expect { commit_patches }.to raise_error(GRPC::FailedPrecondition) + end + end + end end |