Merge branch 'feature/note-validator' into 'master'

Improve note validation

This MR improves note validation. Originates from #15577.

Closes #17260

See merge request !4024
This commit is contained in:
Robert Speicher 2016-05-30 04:07:19 +00:00
commit 43c35b0f20
22 changed files with 298 additions and 155 deletions

View File

@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.9.0 (unreleased) v 8.9.0 (unreleased)
- Allow forking projects with restricted visibility level - Allow forking projects with restricted visibility level
- Improve note validation to prevent errors when creating invalid note via API
- Redesign navigation for project pages - Redesign navigation for project pages
- Fix groups API to list only user's accessible projects - Fix groups API to list only user's accessible projects
- Redesign account and email confirmation emails - Redesign account and email confirmation emails

View File

@ -29,10 +29,17 @@ class Note < ActiveRecord::Base
# Attachments are deprecated and are handled by Markdown uploader # Attachments are deprecated and are handled by Markdown uploader
validates :attachment, file_size: { maximum: :max_attachment_size } validates :attachment, file_size: { maximum: :max_attachment_size }
validates :noteable_id, presence: true, if: ->(n) { n.noteable_type.present? && n.noteable_type != 'Commit' } validates :noteable_type, presence: true
validates :commit_id, presence: true, if: ->(n) { n.noteable_type == 'Commit' } validates :noteable_id, presence: true, unless: :for_commit?
validates :commit_id, presence: true, if: :for_commit?
validates :author, presence: true validates :author, presence: true
validate unless: :for_commit? do |note|
unless note.noteable.try(:project) == note.project
errors.add(:invalid_project, 'Note and noteable project mismatch')
end
end
mount_uploader :attachment, AttachmentUploader mount_uploader :attachment, AttachmentUploader
# Scopes # Scopes

View File

@ -5,8 +5,6 @@ module Notes
note.author = current_user note.author = current_user
note.system = false note.system = false
return unless valid_project?(note)
if note.save if note.save
# Finish the harder work in the background # Finish the harder work in the background
NewNoteWorker.perform_in(2.seconds, note.id, params) NewNoteWorker.perform_in(2.seconds, note.id, params)
@ -15,14 +13,5 @@ module Notes
note note
end end
private
def valid_project?(note)
return false unless project
return true if note.for_commit?
note.noteable.try(:project) == project
end
end end
end end

View File

@ -20,7 +20,7 @@ class Spinach::Features::DashboardTodos < Spinach::FeatureSteps
step 'I have todos' do step 'I have todos' do
create(:todo, user: current_user, project: project, author: mary_jane, target: issue, action: Todo::MENTIONED) create(:todo, user: current_user, project: project, author: mary_jane, target: issue, action: Todo::MENTIONED)
create(:todo, user: current_user, project: project, author: john_doe, target: issue, action: Todo::ASSIGNED) create(:todo, user: current_user, project: project, author: john_doe, target: issue, action: Todo::ASSIGNED)
note = create(:note, author: john_doe, noteable: issue, note: "#{current_user.to_reference} Wdyt?") note = create(:note, author: john_doe, noteable: issue, note: "#{current_user.to_reference} Wdyt?", project: project)
create(:todo, user: current_user, project: project, author: john_doe, target: issue, action: Todo::MENTIONED, note: note) create(:todo, user: current_user, project: project, author: john_doe, target: issue, action: Todo::MENTIONED, note: note)
create(:todo, user: current_user, project: project, author: john_doe, target: merge_request, action: Todo::ASSIGNED) create(:todo, user: current_user, project: project, author: john_doe, target: merge_request, action: Todo::ASSIGNED)
end end

View File

@ -348,7 +348,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
step 'another user adds a comment with text "Yay!" to issue "Release 0.4"' do step 'another user adds a comment with text "Yay!" to issue "Release 0.4"' do
issue = Issue.find_by!(title: 'Release 0.4') issue = Issue.find_by!(title: 'Release 0.4')
create(:note_on_issue, noteable: issue, note: 'Yay!') create(:note_on_issue, noteable: issue, project: project, note: 'Yay!')
end end
step 'I should see a new comment with text "Yay!"' do step 'I should see a new comment with text "Yay!"' do

View File

@ -273,7 +273,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
step 'user "John Doe" leaves a comment like "Line is wrong" on diff' do step 'user "John Doe" leaves a comment like "Line is wrong" on diff' do
mr = MergeRequest.find_by(title: "Bug NS-05") mr = MergeRequest.find_by(title: "Bug NS-05")
create(:note_on_merge_request_diff, project: project, create(:note_on_merge_request_diff, project: project,
noteable_id: mr.id, noteable: mr,
author: user_exists("John Doe"), author: user_exists("John Doe"),
line_code: sample_commit.line_code, line_code: sample_commit.line_code,
note: 'Line is wrong') note: 'Line is wrong')

View File

@ -7,6 +7,7 @@ FactoryGirl.define do
project project
note "Note" note "Note"
author author
on_issue
factory :note_on_commit, traits: [:on_commit] factory :note_on_commit, traits: [:on_commit]
factory :note_on_commit_diff, traits: [:on_commit, :on_diff], class: LegacyDiffNote factory :note_on_commit_diff, traits: [:on_commit, :on_diff], class: LegacyDiffNote
@ -19,29 +20,26 @@ FactoryGirl.define do
factory :upvote_note, traits: [:award, :upvote] factory :upvote_note, traits: [:award, :upvote]
trait :on_commit do trait :on_commit do
project noteable nil
noteable_id nil
noteable_type 'Commit'
commit_id RepoHelpers.sample_commit.id commit_id RepoHelpers.sample_commit.id
noteable_type "Commit"
end end
trait :on_diff do trait :on_diff do
line_code "0_184_184" line_code "0_184_184"
end end
trait :on_merge_request do trait :on_issue do
project noteable { create(:issue, project: project) }
noteable_id 1
noteable_type "MergeRequest"
end end
trait :on_issue do trait :on_merge_request do
noteable_id 1 noteable { create(:merge_request, source_project: project) }
noteable_type "Issue"
end end
trait :on_project_snippet do trait :on_project_snippet do
noteable_id 1 noteable { create(:snippet, project: project) }
noteable_type "Snippet"
end end
trait :system do trait :system do

View File

@ -9,8 +9,11 @@ feature 'Issue notes polling' do
end end
scenario 'Another user adds a comment to an issue', js: true do scenario 'Another user adds a comment to an issue', js: true do
note = create(:note_on_issue, noteable: issue, note: 'Looks good!') note = create(:note, noteable: issue, project: project,
note: 'Looks good!')
page.execute_script('notes.refresh();') page.execute_script('notes.refresh();')
expect(page).to have_selector("#note_#{note.id}", text: 'Looks good!') expect(page).to have_selector("#note_#{note.id}", text: 'Looks good!')
end end
end end

View File

@ -125,7 +125,7 @@ describe 'Issues', feature: true do
describe 'Issue info' do describe 'Issue info' do
it 'excludes award_emoji from comment count' do it 'excludes award_emoji from comment count' do
issue = create(:issue, author: @user, assignee: @user, project: project, title: 'foobar') issue = create(:issue, author: @user, assignee: @user, project: project, title: 'foobar')
create(:upvote_note, noteable: issue) create(:upvote_note, noteable: issue, project: project)
visit namespace_project_issues_path(project.namespace, project, assignee_id: @user.id) visit namespace_project_issues_path(project.namespace, project, assignee_id: @user.id)

View File

@ -19,10 +19,14 @@ describe 'Comments', feature: true do
end end
describe 'On a merge request', js: true, feature: true do describe 'On a merge request', js: true, feature: true do
let!(:merge_request) { create(:merge_request) } let!(:project) { create(:project) }
let!(:project) { merge_request.source_project } let!(:merge_request) do
create(:merge_request, source_project: project, target_project: project)
end
let!(:note) do let!(:note) do
create(:note_on_merge_request, :with_attachment, project: project) create(:note_on_merge_request, :with_attachment, noteable: merge_request,
project: project)
end end
before do before do

View File

@ -32,7 +32,8 @@ feature 'Member autocomplete', feature: true do
context 'adding a new note on a Issue', js: true do context 'adding a new note on a Issue', js: true do
before do before do
issue = create(:issue, author: author, project: project) issue = create(:issue, author: author, project: project)
create(:note, note: 'Ultralight Beam', noteable: issue, author: participant) create(:note, note: 'Ultralight Beam', noteable: issue,
project: project, author: participant)
visit_issue(project, issue) visit_issue(project, issue)
end end
@ -47,7 +48,8 @@ feature 'Member autocomplete', feature: true do
context 'adding a new note on a Merge Request ', js: true do context 'adding a new note on a Merge Request ', js: true do
before do before do
merge = create(:merge_request, source_project: project, target_project: project, author: author) merge = create(:merge_request, source_project: project, target_project: project, author: author)
create(:note, note: 'Ultralight Beam', noteable: merge, author: participant) create(:note, note: 'Ultralight Beam', noteable: merge,
project: project, author: participant)
visit_merge_request(project, merge) visit_merge_request(project, merge)
end end

View File

@ -75,7 +75,10 @@ feature 'Task Lists', feature: true do
describe 'for Notes' do describe 'for Notes' do
let!(:issue) { create(:issue, author: user, project: project) } let!(:issue) { create(:issue, author: user, project: project) }
let!(:note) { create(:note, note: markdown, noteable: issue, author: user) } let!(:note) do
create(:note, note: markdown, noteable: issue,
project: project, author: user)
end
it 'renders for note body' do it 'renders for note body' do
visit_issue(project, issue) visit_issue(project, issue)

View File

@ -9,7 +9,8 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
before(:each) do before(:each) do
expect(data).to have_key(:object_attributes) expect(data).to have_key(:object_attributes)
expect(data[:object_attributes]).to have_key(:url) expect(data[:object_attributes]).to have_key(:url)
expect(data[:object_attributes][:url]).to eq(Gitlab::UrlBuilder.build(note)) expect(data[:object_attributes][:url])
.to eq(Gitlab::UrlBuilder.build(note))
expect(data[:object_kind]).to eq('note') expect(data[:object_kind]).to eq('note')
expect(data[:user]).to eq(user.hook_attrs) expect(data[:user]).to eq(user.hook_attrs)
end end
@ -37,13 +38,21 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
end end
describe 'When asking for a note on issue' do describe 'When asking for a note on issue' do
let(:issue) { create(:issue, created_at: fixed_time, updated_at: fixed_time) } let(:issue) do
let(:note) { create(:note_on_issue, noteable_id: issue.id, project: project) } create(:issue, created_at: fixed_time, updated_at: fixed_time,
project: project)
end
let(:note) do
create(:note_on_issue, noteable: issue, project: project)
end
it 'returns the note and issue-specific data' do it 'returns the note and issue-specific data' do
expect(data).to have_key(:issue) expect(data).to have_key(:issue)
expect(data[:issue].except('updated_at')).to eq(issue.hook_attrs.except('updated_at')) expect(data[:issue].except('updated_at'))
expect(data[:issue]['updated_at']).to be > issue.hook_attrs['updated_at'] .to eq(issue.reload.hook_attrs.except('updated_at'))
expect(data[:issue]['updated_at'])
.to be > issue.hook_attrs['updated_at']
end end
include_examples 'project hook data' include_examples 'project hook data'
@ -51,13 +60,23 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
end end
describe 'When asking for a note on merge request' do describe 'When asking for a note on merge request' do
let(:merge_request) { create(:merge_request, created_at: fixed_time, updated_at: fixed_time) } let(:merge_request) do
let(:note) { create(:note_on_merge_request, noteable_id: merge_request.id, project: project) } create(:merge_request, created_at: fixed_time,
updated_at: fixed_time,
source_project: project)
end
let(:note) do
create(:note_on_merge_request, noteable: merge_request,
project: project)
end
it 'returns the note and merge request data' do it 'returns the note and merge request data' do
expect(data).to have_key(:merge_request) expect(data).to have_key(:merge_request)
expect(data[:merge_request].except('updated_at')).to eq(merge_request.hook_attrs.except('updated_at')) expect(data[:merge_request].except('updated_at'))
expect(data[:merge_request]['updated_at']).to be > merge_request.hook_attrs['updated_at'] .to eq(merge_request.reload.hook_attrs.except('updated_at'))
expect(data[:merge_request]['updated_at'])
.to be > merge_request.hook_attrs['updated_at']
end end
include_examples 'project hook data' include_examples 'project hook data'
@ -65,13 +84,22 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
end end
describe 'When asking for a note on merge request diff' do describe 'When asking for a note on merge request diff' do
let(:merge_request) { create(:merge_request, created_at: fixed_time, updated_at: fixed_time) } let(:merge_request) do
let(:note) { create(:note_on_merge_request_diff, noteable_id: merge_request.id, project: project) } create(:merge_request, created_at: fixed_time, updated_at: fixed_time,
source_project: project)
end
let(:note) do
create(:note_on_merge_request_diff, noteable: merge_request,
project: project)
end
it 'returns the note and merge request diff data' do it 'returns the note and merge request diff data' do
expect(data).to have_key(:merge_request) expect(data).to have_key(:merge_request)
expect(data[:merge_request].except('updated_at')).to eq(merge_request.hook_attrs.except('updated_at')) expect(data[:merge_request].except('updated_at'))
expect(data[:merge_request]['updated_at']).to be > merge_request.hook_attrs['updated_at'] .to eq(merge_request.reload.hook_attrs.except('updated_at'))
expect(data[:merge_request]['updated_at'])
.to be > merge_request.hook_attrs['updated_at']
end end
include_examples 'project hook data' include_examples 'project hook data'
@ -79,13 +107,22 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
end end
describe 'When asking for a note on project snippet' do describe 'When asking for a note on project snippet' do
let!(:snippet) { create(:project_snippet, created_at: fixed_time, updated_at: fixed_time) } let!(:snippet) do
let!(:note) { create(:note_on_project_snippet, noteable_id: snippet.id, project: project) } create(:project_snippet, created_at: fixed_time, updated_at: fixed_time,
project: project)
end
let!(:note) do
create(:note_on_project_snippet, noteable: snippet,
project: project)
end
it 'returns the note and project snippet data' do it 'returns the note and project snippet data' do
expect(data).to have_key(:snippet) expect(data).to have_key(:snippet)
expect(data[:snippet].except('updated_at')).to eq(snippet.hook_attrs.except('updated_at')) expect(data[:snippet].except('updated_at'))
expect(data[:snippet]['updated_at']).to be > snippet.hook_attrs['updated_at'] .to eq(snippet.reload.hook_attrs.except('updated_at'))
expect(data[:snippet]['updated_at'])
.to be > snippet.hook_attrs['updated_at']
end end
include_examples 'project hook data' include_examples 'project hook data'

View File

@ -189,7 +189,6 @@ describe Issue, "Issuable" do
let(:data) { issue.to_hook_data(user) } let(:data) { issue.to_hook_data(user) }
let(:project) { issue.project } let(:project) { issue.project }
it "returns correct hook data" do it "returns correct hook data" do
expect(data[:object_kind]).to eq("issue") expect(data[:object_kind]).to eq("issue")
expect(data[:user]).to eq(user.hook_attrs) expect(data[:user]).to eq(user.hook_attrs)
@ -229,11 +228,11 @@ describe Issue, "Issuable" do
end end
describe "votes" do describe "votes" do
let(:project) { issue.project }
before do before do
author = create :user issue.notes.awards.create!(note: "thumbsup", author: user, project: project)
project = create :empty_project issue.notes.awards.create!(note: "thumbsdown", author: user, project: project)
issue.notes.awards.create!(note: "thumbsup", author: author, project: project)
issue.notes.awards.create!(note: "thumbsdown", author: author, project: project)
end end
it "returns correct values" do it "returns correct values" do

View File

@ -63,7 +63,9 @@ describe LegacyDiffNote, models: true do
code = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos) code = Gitlab::Diff::LineCode.generate(diff.new_path, line.new_pos, line.old_pos)
# We're persisting in order to trigger the set_diff callback # We're persisting in order to trigger the set_diff callback
note = create(:note_on_merge_request_diff, noteable: merge, line_code: code) note = create(:note_on_merge_request_diff, noteable: merge,
line_code: code,
project: merge.source_project)
# Make sure we don't get a false positive from a guard clause # Make sure we don't get a false positive from a guard clause
expect(note).to receive(:find_noteable_diff).and_call_original expect(note).to receive(:find_noteable_diff).and_call_original

View File

@ -119,7 +119,8 @@ describe MergeRequest, models: true do
before do before do
allow(merge_request).to receive(:commits) { [merge_request.source_project.repository.commit] } allow(merge_request).to receive(:commits) { [merge_request.source_project.repository.commit] }
create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit', project: merge_request.project) create(:note_on_commit, commit_id: merge_request.commits.first.id,
project: merge_request.project)
create(:note, noteable: merge_request, project: merge_request.project) create(:note, noteable: merge_request, project: merge_request.project)
end end
@ -129,7 +130,9 @@ describe MergeRequest, models: true do
end end
it "should include notes for commits from target project as well" do it "should include notes for commits from target project as well" do
create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit', project: merge_request.target_project) create(:note_on_commit, commit_id: merge_request.commits.first.id,
project: merge_request.target_project)
expect(merge_request.commits).not_to be_empty expect(merge_request.commits).not_to be_empty
expect(merge_request.mr_and_commit_notes.count).to eq(3) expect(merge_request.mr_and_commit_notes.count).to eq(3)
end end

View File

@ -12,6 +12,34 @@ describe Note, models: true do
describe 'validation' do describe 'validation' do
it { is_expected.to validate_presence_of(:note) } it { is_expected.to validate_presence_of(:note) }
it { is_expected.to validate_presence_of(:project) } it { is_expected.to validate_presence_of(:project) }
context 'when note is on commit' do
before { allow(subject).to receive(:for_commit?).and_return(true) }
it { is_expected.to validate_presence_of(:commit_id) }
it { is_expected.not_to validate_presence_of(:noteable_id) }
end
context 'when note is not on commit' do
before { allow(subject).to receive(:for_commit?).and_return(false) }
it { is_expected.not_to validate_presence_of(:commit_id) }
it { is_expected.to validate_presence_of(:noteable_id) }
end
context 'when noteable and note project differ' do
subject do
build(:note, noteable: build_stubbed(:issue),
project: build_stubbed(:project))
end
it { is_expected.to be_invalid }
end
context 'when noteable and note project are the same' do
subject { create(:note) }
it { is_expected.to be_valid }
end
end end
describe "Commit notes" do describe "Commit notes" do
@ -89,8 +117,8 @@ describe Note, models: true do
end end
describe "#all_references" do describe "#all_references" do
let!(:note1) { create(:note) } let!(:note1) { create(:note_on_issue) }
let!(:note2) { create(:note) } let!(:note2) { create(:note_on_issue) }
it "reads the rendered note body from the cache" do it "reads the rendered note body from the cache" do
expect(Banzai::Renderer).to receive(:render).with(note1.note, pipeline: :note, cache_key: [note1, "note"], project: note1.project) expect(Banzai::Renderer).to receive(:render).with(note1.note, pipeline: :note, cache_key: [note1, "note"], project: note1.project)
@ -102,7 +130,7 @@ describe Note, models: true do
end end
describe '.search' do describe '.search' do
let(:note) { create(:note, note: 'WoW') } let(:note) { create(:note_on_issue, note: 'WoW') }
it 'returns notes with matching content' do it 'returns notes with matching content' do
expect(described_class.search(note.note)).to eq([note]) expect(described_class.search(note.note)).to eq([note])
@ -175,12 +203,18 @@ describe Note, models: true do
let(:merge_request) { create :merge_request } let(:merge_request) { create :merge_request }
it "converts aliases to actual name" do it "converts aliases to actual name" do
note = create(:note, note: ":+1:", noteable: merge_request) note = create(:note, note: ":+1:",
noteable: merge_request,
project: merge_request.project)
expect(note.reload.note).to eq("thumbsup") expect(note.reload.note).to eq("thumbsup")
end end
it "is not an award emoji when comment is on a diff" do it "is not an award emoji when comment is on a diff" do
note = create(:note_on_merge_request_diff, note: ":blowfish:", noteable: merge_request, line_code: "11d5d2e667e9da4f7f610f81d86c974b146b13bd_0_2") note = create(:note_on_merge_request_diff, note: ":blowfish:",
noteable: merge_request,
project: merge_request.project,
line_code: "11d5d2e667e9da4f7f610f81d86c974b146b13bd_0_2")
note = note.reload note = note.reload
expect(note.note).to eq(":blowfish:") expect(note.note).to eq(":blowfish:")

View File

@ -176,86 +176,117 @@ describe HipchatService, models: true do
context "Note events" do context "Note events" do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, creator_id: user.id) } let(:project) { create(:project, creator_id: user.id) }
let(:issue) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:snippet) { create(:project_snippet, project: project) }
let(:commit_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') }
let(:merge_request_note) { create(:note_on_merge_request, noteable_id: merge_request.id, note: "merge request note") }
let(:issue_note) { create(:note_on_issue, noteable_id: issue.id, note: "issue note")}
let(:snippet_note) { create(:note_on_project_snippet, noteable_id: snippet.id, note: "snippet note") }
it "should call Hipchat API for commit comment events" do context 'when commit comment event triggered' do
data = Gitlab::NoteDataBuilder.build(commit_note, user) let(:commit_note) do
hipchat.execute(data) create(:note_on_commit, author: user, project: project,
commit_id: project.repository.commit.id,
note: 'a comment on a commit')
end
expect(WebMock).to have_requested(:post, api_url).once it "should call Hipchat API for commit comment events" do
data = Gitlab::NoteDataBuilder.build(commit_note, user)
hipchat.execute(data)
message = hipchat.send(:create_message, data) expect(WebMock).to have_requested(:post, api_url).once
obj_attr = data[:object_attributes] message = hipchat.send(:create_message, data)
commit_id = Commit.truncate_sha(data[:commit][:id])
title = hipchat.send(:format_title, data[:commit][:message])
expect(message).to eq("#{user.name} commented on " \ obj_attr = data[:object_attributes]
"<a href=\"#{obj_attr[:url]}\">commit #{commit_id}</a> in " \ commit_id = Commit.truncate_sha(data[:commit][:id])
"<a href=\"#{project.web_url}\">#{project_name}</a>: " \ title = hipchat.send(:format_title, data[:commit][:message])
"#{title}" \
"<pre>a comment on a commit</pre>") expect(message).to eq("#{user.name} commented on " \
"<a href=\"#{obj_attr[:url]}\">commit #{commit_id}</a> in " \
"<a href=\"#{project.web_url}\">#{project_name}</a>: " \
"#{title}" \
"<pre>a comment on a commit</pre>")
end
end end
it "should call Hipchat API for merge request comment events" do context 'when merge request comment event triggered' do
data = Gitlab::NoteDataBuilder.build(merge_request_note, user) let(:merge_request) do
hipchat.execute(data) create(:merge_request, source_project: project,
target_project: project)
end
expect(WebMock).to have_requested(:post, api_url).once let(:merge_request_note) do
create(:note_on_merge_request, noteable: merge_request,
project: project,
note: "merge request note")
end
message = hipchat.send(:create_message, data) it "should call Hipchat API for merge request comment events" do
data = Gitlab::NoteDataBuilder.build(merge_request_note, user)
hipchat.execute(data)
obj_attr = data[:object_attributes] expect(WebMock).to have_requested(:post, api_url).once
merge_id = data[:merge_request]['iid']
title = data[:merge_request]['title']
expect(message).to eq("#{user.name} commented on " \ message = hipchat.send(:create_message, data)
"<a href=\"#{obj_attr[:url]}\">merge request !#{merge_id}</a> in " \
"<a href=\"#{project.web_url}\">#{project_name}</a>: " \ obj_attr = data[:object_attributes]
"<b>#{title}</b>" \ merge_id = data[:merge_request]['iid']
"<pre>merge request note</pre>") title = data[:merge_request]['title']
expect(message).to eq("#{user.name} commented on " \
"<a href=\"#{obj_attr[:url]}\">merge request !#{merge_id}</a> in " \
"<a href=\"#{project.web_url}\">#{project_name}</a>: " \
"<b>#{title}</b>" \
"<pre>merge request note</pre>")
end
end end
it "should call Hipchat API for issue comment events" do context 'when issue comment event triggered' do
data = Gitlab::NoteDataBuilder.build(issue_note, user) let(:issue) { create(:issue, project: project) }
hipchat.execute(data) let(:issue_note) do
create(:note_on_issue, noteable: issue, project: project,
note: "issue note")
end
message = hipchat.send(:create_message, data) it "should call Hipchat API for issue comment events" do
data = Gitlab::NoteDataBuilder.build(issue_note, user)
hipchat.execute(data)
obj_attr = data[:object_attributes] message = hipchat.send(:create_message, data)
issue_id = data[:issue]['iid']
title = data[:issue]['title']
expect(message).to eq("#{user.name} commented on " \ obj_attr = data[:object_attributes]
"<a href=\"#{obj_attr[:url]}\">issue ##{issue_id}</a> in " \ issue_id = data[:issue]['iid']
"<a href=\"#{project.web_url}\">#{project_name}</a>: " \ title = data[:issue]['title']
"<b>#{title}</b>" \
"<pre>issue note</pre>") expect(message).to eq("#{user.name} commented on " \
"<a href=\"#{obj_attr[:url]}\">issue ##{issue_id}</a> in " \
"<a href=\"#{project.web_url}\">#{project_name}</a>: " \
"<b>#{title}</b>" \
"<pre>issue note</pre>")
end
end end
it "should call Hipchat API for snippet comment events" do context 'when snippet comment event triggered' do
data = Gitlab::NoteDataBuilder.build(snippet_note, user) let(:snippet) { create(:project_snippet, project: project) }
hipchat.execute(data) let(:snippet_note) do
create(:note_on_project_snippet, noteable: snippet,
project: project,
note: "snippet note")
end
expect(WebMock).to have_requested(:post, api_url).once it "should call Hipchat API for snippet comment events" do
data = Gitlab::NoteDataBuilder.build(snippet_note, user)
hipchat.execute(data)
message = hipchat.send(:create_message, data) expect(WebMock).to have_requested(:post, api_url).once
obj_attr = data[:object_attributes] message = hipchat.send(:create_message, data)
snippet_id = data[:snippet]['id']
title = data[:snippet]['title']
expect(message).to eq("#{user.name} commented on " \ obj_attr = data[:object_attributes]
"<a href=\"#{obj_attr[:url]}\">snippet ##{snippet_id}</a> in " \ snippet_id = data[:snippet]['id']
"<a href=\"#{project.web_url}\">#{project_name}</a>: " \ title = data[:snippet]['title']
"<b>#{title}</b>" \
"<pre>snippet note</pre>") expect(message).to eq("#{user.name} commented on " \
"<a href=\"#{obj_attr[:url]}\">snippet ##{snippet_id}</a> in " \
"<a href=\"#{project.web_url}\">#{project_name}</a>: " \
"<b>#{title}</b>" \
"<pre>snippet note</pre>")
end
end end
end end

View File

@ -142,13 +142,6 @@ describe SlackService, models: true do
let(:slack) { SlackService.new } let(:slack) { SlackService.new }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, creator_id: user.id) } let(:project) { create(:project, creator_id: user.id) }
let(:issue) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:snippet) { create(:project_snippet, project: project) }
let(:commit_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') }
let(:merge_request_note) { create(:note_on_merge_request, noteable_id: merge_request.id, note: "merge request note") }
let(:issue_note) { create(:note_on_issue, noteable_id: issue.id, note: "issue note")}
let(:snippet_note) { create(:note_on_project_snippet, noteable_id: snippet.id, note: "snippet note") }
let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' } let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' }
before do before do
@ -162,32 +155,61 @@ describe SlackService, models: true do
WebMock.stub_request(:post, webhook_url) WebMock.stub_request(:post, webhook_url)
end end
it "should call Slack API for commit comment events" do context 'when commit comment event executed' do
data = Gitlab::NoteDataBuilder.build(commit_note, user) let(:commit_note) do
slack.execute(data) create(:note_on_commit, author: user,
project: project,
commit_id: project.repository.commit.id,
note: 'a comment on a commit')
end
expect(WebMock).to have_requested(:post, webhook_url).once it "should call Slack API for commit comment events" do
data = Gitlab::NoteDataBuilder.build(commit_note, user)
slack.execute(data)
expect(WebMock).to have_requested(:post, webhook_url).once
end
end end
it "should call Slack API for merge request comment events" do context 'when merge request comment event executed' do
data = Gitlab::NoteDataBuilder.build(merge_request_note, user) let(:merge_request_note) do
slack.execute(data) create(:note_on_merge_request, project: project,
note: "merge request note")
end
expect(WebMock).to have_requested(:post, webhook_url).once it "should call Slack API for merge request comment events" do
data = Gitlab::NoteDataBuilder.build(merge_request_note, user)
slack.execute(data)
expect(WebMock).to have_requested(:post, webhook_url).once
end
end end
it "should call Slack API for issue comment events" do context 'when issue comment event executed' do
data = Gitlab::NoteDataBuilder.build(issue_note, user) let(:issue_note) do
slack.execute(data) create(:note_on_issue, project: project, note: "issue note")
end
expect(WebMock).to have_requested(:post, webhook_url).once it "should call Slack API for issue comment events" do
data = Gitlab::NoteDataBuilder.build(issue_note, user)
slack.execute(data)
expect(WebMock).to have_requested(:post, webhook_url).once
end
end end
it "should call Slack API for snippet comment events" do context 'when snippet comment event executed' do
data = Gitlab::NoteDataBuilder.build(snippet_note, user) let(:snippet_note) do
slack.execute(data) create(:note_on_project_snippet, project: project,
note: "snippet note")
end
expect(WebMock).to have_requested(:post, webhook_url).once it "should call Slack API for snippet comment events" do
data = Gitlab::NoteDataBuilder.build(snippet_note, user)
slack.execute(data)
expect(WebMock).to have_requested(:post, webhook_url).once
end
end end
end end
end end

View File

@ -258,8 +258,8 @@ describe API::API, api: true do
body: 'Hi!' body: 'Hi!'
end end
it 'responds with 500' do it 'responds with resource not found error' do
expect(response.status).to eq 500 expect(response.status).to eq 404
end end
it 'does not create new note' do it 'does not create new note' do

View File

@ -1,8 +1,8 @@
require 'spec_helper' require 'spec_helper'
describe MergeRequests::MergeWhenBuildSucceedsService do describe MergeRequests::MergeWhenBuildSucceedsService do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) } let(:project) { create(:project) }
let(:mr_merge_if_green_enabled) do let(:mr_merge_if_green_enabled) do
create(:merge_request, merge_when_build_succeeds: true, merge_user: user, create(:merge_request, merge_when_build_succeeds: true, merge_user: user,
@ -10,11 +10,15 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
source_project: project, target_project: project, state: "opened") source_project: project, target_project: project, state: "opened")
end end
let(:project) { create(:project) }
let(:ci_commit) { create(:ci_commit_with_one_job, ref: mr_merge_if_green_enabled.source_branch, project: project) } let(:ci_commit) { create(:ci_commit_with_one_job, ref: mr_merge_if_green_enabled.source_branch, project: project) }
let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, commit_message: 'Awesome message') } let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, commit_message: 'Awesome message') }
describe "#execute" do describe "#execute" do
let(:merge_request) do
create(:merge_request, target_project: project, source_project: project,
source_branch: "feature", target_branch: 'master')
end
context 'first time enabling' do context 'first time enabling' do
before do before do
allow(merge_request).to receive(:ci_commit).and_return(ci_commit) allow(merge_request).to receive(:ci_commit).and_return(ci_commit)

View File

@ -208,8 +208,10 @@ describe SystemNoteService, services: true do
end end
describe '.merge_when_build_succeeds' do describe '.merge_when_build_succeeds' do
let(:ci_commit) { build :ci_commit_without_jobs } let(:ci_commit) { build(:ci_commit_without_jobs )}
let(:noteable) { create :merge_request } let(:noteable) do
create(:merge_request, source_project: project, target_project: project)
end
subject { described_class.merge_when_build_succeeds(noteable, project, author, noteable.last_commit) } subject { described_class.merge_when_build_succeeds(noteable, project, author, noteable.last_commit) }
@ -221,8 +223,10 @@ describe SystemNoteService, services: true do
end end
describe '.cancel_merge_when_build_succeeds' do describe '.cancel_merge_when_build_succeeds' do
let(:ci_commit) { build :ci_commit_without_jobs } let(:ci_commit) { build(:ci_commit_without_jobs) }
let(:noteable) { create :merge_request } let(:noteable) do
create(:merge_request, source_project: project, target_project: project)
end
subject { described_class.cancel_merge_when_build_succeeds(noteable, project, author) } subject { described_class.cancel_merge_when_build_succeeds(noteable, project, author) }