Commit 2a01b2c2 authored by Rémy Coutable's avatar Rémy Coutable Committed by Andy Soiron

Add labels to the 'Note on MR' webhook payload

Changelog: changed
Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent fe8946ee
...@@ -524,6 +524,10 @@ module Issuable ...@@ -524,6 +524,10 @@ module Issuable
labels.order('title ASC').pluck(:title) labels.order('title ASC').pluck(:title)
end end
def labels_hook_attrs
labels.map(&:hook_attrs)
end
# Convert this Issuable class name to a format usable by Ability definitions # Convert this Issuable class name to a format usable by Ability definitions
# #
# Examples: # Examples:
......
...@@ -386,10 +386,6 @@ class Issue < ApplicationRecord ...@@ -386,10 +386,6 @@ class Issue < ApplicationRecord
resource_parent.root_namespace&.issue_repositioning_disabled? resource_parent.root_namespace&.issue_repositioning_disabled?
end end
def hook_attrs
Gitlab::HookData::IssueBuilder.new(self).build
end
# `from` argument can be a Namespace or Project. # `from` argument can be a Namespace or Project.
def to_reference(from = nil, full: false) def to_reference(from = nil, full: false)
reference = "#{self.class.reference_prefix}#{iid}" reference = "#{self.class.reference_prefix}#{iid}"
...@@ -530,10 +526,6 @@ class Issue < ApplicationRecord ...@@ -530,10 +526,6 @@ class Issue < ApplicationRecord
::MergeRequestsClosingIssues.count_for_issue(self.id, user) ::MergeRequestsClosingIssues.count_for_issue(self.id, user)
end end
def labels_hook_attrs
labels.map(&:hook_attrs)
end
def previous_updated_at def previous_updated_at
previous_changes['updated_at']&.first || updated_at previous_changes['updated_at']&.first || updated_at
end end
......
...@@ -538,6 +538,32 @@ Payload example: ...@@ -538,6 +538,32 @@ Payload example:
"iid": 1, "iid": 1,
"description": "Et voluptas corrupti assumenda temporibus. Architecto cum animi eveniet amet asperiores. Vitae numquam voluptate est natus sit et ad id.", "description": "Et voluptas corrupti assumenda temporibus. Architecto cum animi eveniet amet asperiores. Vitae numquam voluptate est natus sit et ad id.",
"position": 0, "position": 0,
"labels": [
{
"id": 25,
"title": "Afterpod",
"color": "#3e8068",
"project_id": null,
"created_at": "2019-06-05T14:32:20.211Z",
"updated_at": "2019-06-05T14:32:20.211Z",
"template": false,
"description": null,
"type": "GroupLabel",
"group_id": 4
},
{
"id": 86,
"title": "Element",
"color": "#231afe",
"project_id": 4,
"created_at": "2019-06-05T14:32:20.637Z",
"updated_at": "2019-06-05T14:32:20.637Z",
"template": false,
"description": null,
"type": "ProjectLabel",
"group_id": null
}
],
"source":{ "source":{
"name":"Gitlab Test", "name":"Gitlab Test",
"description":"Aut reprehenderit ut est.", "description":"Aut reprehenderit ut est.",
......
...@@ -43,10 +43,9 @@ module Gitlab ...@@ -43,10 +43,9 @@ module Gitlab
if note.for_commit? if note.for_commit?
data[:commit] = build_data_for_commit(project, user, note) data[:commit] = build_data_for_commit(project, user, note)
elsif note.for_issue? elsif note.for_issue?
data[:issue] = note.noteable.hook_attrs data[:issue] = Gitlab::HookData::IssueBuilder.new(note.noteable).build
data[:issue][:labels] = note.noteable.labels_hook_attrs
elsif note.for_merge_request? elsif note.for_merge_request?
data[:merge_request] = note.noteable.hook_attrs data[:merge_request] = Gitlab::HookData::MergeRequestBuilder.new(note.noteable).build
elsif note.for_snippet? elsif note.for_snippet?
data[:snippet] = note.noteable.hook_attrs data[:snippet] = note.noteable.hook_attrs
end end
......
...@@ -13,7 +13,7 @@ module Gitlab ...@@ -13,7 +13,7 @@ module Gitlab
event_type: event_type, event_type: event_type,
user: user.hook_attrs, user: user.hook_attrs,
project: issuable.project.hook_attrs, project: issuable.project.hook_attrs,
object_attributes: issuable.hook_attrs, object_attributes: issuable_builder.new(issuable).build,
labels: issuable.labels.map(&:hook_attrs), labels: issuable.labels.map(&:hook_attrs),
changes: final_changes(changes.slice(*safe_keys)), changes: final_changes(changes.slice(*safe_keys)),
# DEPRECATED # DEPRECATED
......
...@@ -60,6 +60,7 @@ module Gitlab ...@@ -60,6 +60,7 @@ module Gitlab
human_time_estimate: merge_request.human_time_estimate, human_time_estimate: merge_request.human_time_estimate,
assignee_ids: merge_request.assignee_ids, assignee_ids: merge_request.assignee_ids,
assignee_id: merge_request.assignee_ids.first, # This key is deprecated assignee_id: merge_request.assignee_ids.first, # This key is deprecated
labels: merge_request.labels_hook_attrs,
state: merge_request.state, # This key is deprecated state: merge_request.state, # This key is deprecated
blocking_discussions_resolved: merge_request.mergeable_discussions_state? blocking_discussions_resolved: merge_request.mergeable_discussions_state?
} }
......
...@@ -8,18 +8,22 @@ RSpec.describe Gitlab::DataBuilder::Note do ...@@ -8,18 +8,22 @@ RSpec.describe Gitlab::DataBuilder::Note do
let(:data) { described_class.build(note, user) } let(:data) { described_class.build(note, user) }
let(:fixed_time) { Time.at(1425600000) } # Avoid time precision errors let(:fixed_time) { Time.at(1425600000) } # Avoid time precision errors
before do shared_examples 'includes general data' do
expect(data).to have_key(:object_attributes) specify do
expect(data[:object_attributes]).to have_key(:url) expect(data).to have_key(:object_attributes)
expect(data[:object_attributes][:url]) expect(data[:object_attributes]).to have_key(:url)
.to eq(Gitlab::UrlBuilder.build(note)) expect(data[:object_attributes][:url])
expect(data[:object_kind]).to eq('note') .to eq(Gitlab::UrlBuilder.build(note))
expect(data[:user]).to eq(user.hook_attrs) expect(data[:object_kind]).to eq('note')
expect(data[:user]).to eq(user.hook_attrs)
end
end end
describe 'When asking for a note on commit' do describe 'When asking for a note on commit' do
let(:note) { create(:note_on_commit, project: project) } let(:note) { create(:note_on_commit, project: project) }
it_behaves_like 'includes general data'
it 'returns the note and commit-specific data' do it 'returns the note and commit-specific data' do
expect(data).to have_key(:commit) expect(data).to have_key(:commit)
end end
...@@ -31,6 +35,8 @@ RSpec.describe Gitlab::DataBuilder::Note do ...@@ -31,6 +35,8 @@ RSpec.describe Gitlab::DataBuilder::Note do
describe 'When asking for a note on commit diff' do describe 'When asking for a note on commit diff' do
let(:note) { create(:diff_note_on_commit, project: project) } let(:note) { create(:diff_note_on_commit, project: project) }
it_behaves_like 'includes general data'
it 'returns the note and commit-specific data' do it 'returns the note and commit-specific data' do
expect(data).to have_key(:commit) expect(data).to have_key(:commit)
end end
...@@ -51,22 +57,21 @@ RSpec.describe Gitlab::DataBuilder::Note do ...@@ -51,22 +57,21 @@ RSpec.describe Gitlab::DataBuilder::Note do
create(:note_on_issue, noteable: issue, project: project) create(:note_on_issue, noteable: issue, project: project)
end end
it_behaves_like 'includes general data'
it 'returns the note and issue-specific data' do it 'returns the note and issue-specific data' do
without_timestamps = lambda { |label| label.except('created_at', 'updated_at') } expect_next_instance_of(Gitlab::HookData::IssueBuilder) do |issue_data_builder|
hook_attrs = issue.reload.hook_attrs expect(issue_data_builder).to receive(:build).and_return('Issue data')
end
expect(data).to have_key(:issue) expect(data[:issue]).to eq('Issue data')
expect(data[:issue].except('updated_at', 'labels'))
.to eq(hook_attrs.except('updated_at', 'labels'))
expect(data[:issue]['updated_at'])
.to be >= hook_attrs['updated_at']
expect(data[:issue]['labels'].map(&without_timestamps))
.to eq(hook_attrs['labels'].map(&without_timestamps))
end end
context 'with confidential issue' do context 'with confidential issue' do
let(:issue) { create(:issue, project: project, confidential: true) } let(:issue) { create(:issue, project: project, confidential: true) }
it_behaves_like 'includes general data'
it 'sets event_type to confidential_note' do it 'sets event_type to confidential_note' do
expect(data[:event_type]).to eq('confidential_note') expect(data[:event_type]).to eq('confidential_note')
end end
...@@ -77,10 +82,12 @@ RSpec.describe Gitlab::DataBuilder::Note do ...@@ -77,10 +82,12 @@ RSpec.describe Gitlab::DataBuilder::Note do
end end
describe 'When asking for a note on merge request' do describe 'When asking for a note on merge request' do
let(:label) { create(:label, project: project) }
let(:merge_request) do let(:merge_request) do
create(:merge_request, created_at: fixed_time, create(:labeled_merge_request, created_at: fixed_time,
updated_at: fixed_time, updated_at: fixed_time,
source_project: project) source_project: project,
labels: [label])
end end
let(:note) do let(:note) do
...@@ -88,12 +95,14 @@ RSpec.describe Gitlab::DataBuilder::Note do ...@@ -88,12 +95,14 @@ RSpec.describe Gitlab::DataBuilder::Note do
project: project) project: project)
end end
it 'returns the note and merge request data' do it_behaves_like 'includes general data'
expect(data).to have_key(:merge_request)
expect(data[:merge_request].except('updated_at')) it 'returns the merge request data' do
.to eq(merge_request.reload.hook_attrs.except('updated_at')) expect_next_instance_of(Gitlab::HookData::MergeRequestBuilder) do |mr_data_builder|
expect(data[:merge_request]['updated_at']) expect(mr_data_builder).to receive(:build).and_return('MR data')
.to be >= merge_request.hook_attrs['updated_at'] end
expect(data[:merge_request]).to eq('MR data')
end end
include_examples 'project hook data' include_examples 'project hook data'
...@@ -101,9 +110,11 @@ RSpec.describe Gitlab::DataBuilder::Note do ...@@ -101,9 +110,11 @@ RSpec.describe Gitlab::DataBuilder::Note 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(:label) { create(:label, project: project) }
let(:merge_request) do let(:merge_request) do
create(:merge_request, created_at: fixed_time, updated_at: fixed_time, create(:labeled_merge_request, created_at: fixed_time, updated_at: fixed_time,
source_project: project) source_project: project,
labels: [label])
end end
let(:note) do let(:note) do
...@@ -111,12 +122,14 @@ RSpec.describe Gitlab::DataBuilder::Note do ...@@ -111,12 +122,14 @@ RSpec.describe Gitlab::DataBuilder::Note do
project: project) project: project)
end end
it 'returns the note and merge request diff data' do it_behaves_like 'includes general data'
expect(data).to have_key(:merge_request)
expect(data[:merge_request].except('updated_at')) it 'returns the merge request data' do
.to eq(merge_request.reload.hook_attrs.except('updated_at')) expect_next_instance_of(Gitlab::HookData::MergeRequestBuilder) do |mr_data_builder|
expect(data[:merge_request]['updated_at']) expect(mr_data_builder).to receive(:build).and_return('MR data')
.to be >= merge_request.hook_attrs['updated_at'] end
expect(data[:merge_request]).to eq('MR data')
end end
include_examples 'project hook data' include_examples 'project hook data'
...@@ -134,6 +147,8 @@ RSpec.describe Gitlab::DataBuilder::Note do ...@@ -134,6 +147,8 @@ RSpec.describe Gitlab::DataBuilder::Note do
project: project) project: project)
end end
it_behaves_like 'includes general data'
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')) expect(data[:snippet].except('updated_at'))
......
...@@ -6,7 +6,7 @@ RSpec.describe Gitlab::HookData::IssuableBuilder do ...@@ -6,7 +6,7 @@ RSpec.describe Gitlab::HookData::IssuableBuilder do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
# This shared example requires a `builder` and `user` variable # This shared example requires a `builder` and `user` variable
shared_examples 'issuable hook data' do |kind| shared_examples 'issuable hook data' do |kind, hook_data_issuable_builder_class|
let(:data) { builder.build(user: user) } let(:data) { builder.build(user: user) }
include_examples 'project hook data' do include_examples 'project hook data' do
...@@ -20,7 +20,7 @@ RSpec.describe Gitlab::HookData::IssuableBuilder do ...@@ -20,7 +20,7 @@ RSpec.describe Gitlab::HookData::IssuableBuilder do
expect(data[:object_kind]).to eq(kind) expect(data[:object_kind]).to eq(kind)
expect(data[:user]).to eq(user.hook_attrs) expect(data[:user]).to eq(user.hook_attrs)
expect(data[:project]).to eq(builder.issuable.project.hook_attrs) expect(data[:project]).to eq(builder.issuable.project.hook_attrs)
expect(data[:object_attributes]).to eq(builder.issuable.hook_attrs) expect(data[:object_attributes]).to eq(hook_data_issuable_builder_class.new(issuable).build)
expect(data[:changes]).to eq({}) expect(data[:changes]).to eq({})
expect(data[:repository]).to eq(builder.issuable.project.hook_attrs.slice(:name, :url, :description, :homepage)) expect(data[:repository]).to eq(builder.issuable.project.hook_attrs.slice(:name, :url, :description, :homepage))
end end
...@@ -95,12 +95,12 @@ RSpec.describe Gitlab::HookData::IssuableBuilder do ...@@ -95,12 +95,12 @@ RSpec.describe Gitlab::HookData::IssuableBuilder do
end end
describe '#build' do describe '#build' do
it_behaves_like 'issuable hook data', 'issue' do it_behaves_like 'issuable hook data', 'issue', Gitlab::HookData::IssueBuilder do
let(:issuable) { create(:issue, description: 'A description') } let(:issuable) { create(:issue, description: 'A description') }
let(:builder) { described_class.new(issuable) } let(:builder) { described_class.new(issuable) }
end end
it_behaves_like 'issuable hook data', 'merge_request' do it_behaves_like 'issuable hook data', 'merge_request', Gitlab::HookData::MergeRequestBuilder do
let(:issuable) { create(:merge_request, description: 'A description') } let(:issuable) { create(:merge_request, description: 'A description') }
let(:builder) { described_class.new(issuable) } let(:builder) { described_class.new(issuable) }
end end
......
...@@ -62,6 +62,7 @@ RSpec.describe Gitlab::HookData::MergeRequestBuilder do ...@@ -62,6 +62,7 @@ RSpec.describe Gitlab::HookData::MergeRequestBuilder do
expect(data).to include(:human_time_estimate) expect(data).to include(:human_time_estimate)
expect(data).to include(:human_total_time_spent) expect(data).to include(:human_total_time_spent)
expect(data).to include(:human_time_change) expect(data).to include(:human_time_change)
expect(data).to include(:labels)
end end
context 'when the MR has an image in the description' do context 'when the MR has an image in the description' do
......
...@@ -625,6 +625,16 @@ RSpec.describe Issuable do ...@@ -625,6 +625,16 @@ RSpec.describe Issuable do
end end
end end
describe "#labels_hook_attrs" do
let(:project) { create(:project) }
let(:label) { create(:label) }
let(:issue) { create(:labeled_issue, project: project, labels: [label]) }
it "returns a list of label hook attributes" do
expect(issue.labels_hook_attrs).to match_array([label.hook_attrs])
end
end
describe '.labels_hash' do describe '.labels_hash' do
let(:feature_label) { create(:label, title: 'Feature') } let(:feature_label) { create(:label, title: 'Feature') }
let(:second_label) { create(:label, title: 'Second Label') } let(:second_label) { create(:label, title: 'Second Label') }
......
...@@ -1172,18 +1172,6 @@ RSpec.describe Issue do ...@@ -1172,18 +1172,6 @@ RSpec.describe Issue do
end end
end end
describe '#hook_attrs' do
it 'delegates to Gitlab::HookData::IssueBuilder#build' do
builder = double
expect(Gitlab::HookData::IssueBuilder)
.to receive(:new).with(subject).and_return(builder)
expect(builder).to receive(:build)
subject.hook_attrs
end
end
describe '#check_for_spam?' do describe '#check_for_spam?' do
let_it_be(:support_bot) { ::User.support_bot } let_it_be(:support_bot) { ::User.support_bot }
...@@ -1332,15 +1320,6 @@ RSpec.describe Issue do ...@@ -1332,15 +1320,6 @@ RSpec.describe Issue do
subject { create(:issue, updated_at: 1.hour.ago) } subject { create(:issue, updated_at: 1.hour.ago) }
end end
describe "#labels_hook_attrs" do
let(:label) { create(:label) }
let(:issue) { create(:labeled_issue, project: reusable_project, labels: [label]) }
it "returns a list of label hook attributes" do
expect(issue.labels_hook_attrs).to eq([label.hook_attrs])
end
end
context "relative positioning" do context "relative positioning" do
let_it_be(:group) { create(:group) } let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) } let_it_be(:project) { create(:project, group: group) }
......
...@@ -1757,18 +1757,6 @@ RSpec.describe MergeRequest, factory_default: :keep do ...@@ -1757,18 +1757,6 @@ RSpec.describe MergeRequest, factory_default: :keep do
end end
end end
describe '#hook_attrs' do
it 'delegates to Gitlab::HookData::MergeRequestBuilder#build' do
builder = double
expect(Gitlab::HookData::MergeRequestBuilder)
.to receive(:new).with(subject).and_return(builder)
expect(builder).to receive(:build)
subject.hook_attrs
end
end
describe '#diverged_commits_count' do describe '#diverged_commits_count' do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:forked_project) { fork_project(project, nil, repository: true) } let(:forked_project) { fork_project(project, nil, repository: true) }
......
# frozen_string_literal: true
# This shared example requires a `builder` and `user` variable
RSpec.shared_examples 'issuable hook data' do |kind|
let(:data) { builder.build(user: user) }
include_examples 'project hook data' do
let(:project) { builder.issuable.project }
end
include_examples 'deprecated repository hook data'
context "with a #{kind}" do
it 'contains issuable data' do
expect(data[:object_kind]).to eq(kind)
expect(data[:user]).to eq(user.hook_attrs)
expect(data[:project]).to eq(builder.issuable.project.hook_attrs)
expect(data[:object_attributes]).to eq(builder.issuable.hook_attrs)
expect(data[:changes]).to eq({})
expect(data[:repository]).to eq(builder.issuable.project.hook_attrs.slice(:name, :url, :description, :homepage))
end
it 'does not contain certain keys' do
expect(data).not_to have_key(:assignees)
expect(data).not_to have_key(:assignee)
end
describe 'changes are given' do
let(:changes) do
{
cached_markdown_version: %w[foo bar],
description: ['A description', 'A cool description'],
description_html: %w[foo bar],
in_progress_merge_commit_sha: %w[foo bar],
lock_version: %w[foo bar],
merge_jid: %w[foo bar],
title: ['A title', 'Hello World'],
title_html: %w[foo bar]
}
end
let(:data) { builder.build(user: user, changes: changes) }
it 'populates the :changes hash' do
expect(data[:changes]).to match(hash_including({
title: { previous: 'A title', current: 'Hello World' },
description: { previous: 'A description', current: 'A cool description' }
}))
end
it 'does not contain certain keys' do
expect(data[:changes]).not_to have_key('cached_markdown_version')
expect(data[:changes]).not_to have_key('description_html')
expect(data[:changes]).not_to have_key('lock_version')
expect(data[:changes]).not_to have_key('title_html')
expect(data[:changes]).not_to have_key('in_progress_merge_commit_sha')
expect(data[:changes]).not_to have_key('merge_jid')
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment