Commit 89ecd8ab authored by Sean McGivern's avatar Sean McGivern

Merge branch '28799-todo-creation' into 'master'

Create todos only for new mentiones

Closes #28799

See merge request !10279
parents aa97ee54 a74a6cfd
...@@ -19,7 +19,7 @@ module Issues ...@@ -19,7 +19,7 @@ module Issues
if issue.previous_changes.include?('title') || if issue.previous_changes.include?('title') ||
issue.previous_changes.include?('description') issue.previous_changes.include?('description')
todo_service.update_issue(issue, current_user) todo_service.update_issue(issue, current_user, old_mentioned_users)
end end
if issue.previous_changes.include?('milestone_id') if issue.previous_changes.include?('milestone_id')
......
...@@ -28,7 +28,7 @@ module MergeRequests ...@@ -28,7 +28,7 @@ module MergeRequests
if merge_request.previous_changes.include?('title') || if merge_request.previous_changes.include?('title') ||
merge_request.previous_changes.include?('description') merge_request.previous_changes.include?('description')
todo_service.update_merge_request(merge_request, current_user) todo_service.update_merge_request(merge_request, current_user, old_mentioned_users)
end end
if merge_request.previous_changes.include?('target_branch') if merge_request.previous_changes.include?('target_branch')
......
...@@ -3,11 +3,13 @@ module Notes ...@@ -3,11 +3,13 @@ module Notes
def execute(note) def execute(note)
return note unless note.editable? return note unless note.editable?
old_mentioned_users = note.mentioned_users.to_a
note.update_attributes(params.merge(updated_by: current_user)) note.update_attributes(params.merge(updated_by: current_user))
note.create_new_cross_references!(current_user) note.create_new_cross_references!(current_user)
if note.previous_changes.include?('note') if note.previous_changes.include?('note')
TodoService.new.update_note(note, current_user) TodoService.new.update_note(note, current_user, old_mentioned_users)
end end
note note
......
...@@ -19,8 +19,8 @@ class TodoService ...@@ -19,8 +19,8 @@ class TodoService
# #
# * mark all pending todos related to the issue for the current user as done # * mark all pending todos related to the issue for the current user as done
# #
def update_issue(issue, current_user) def update_issue(issue, current_user, skip_users = [])
update_issuable(issue, current_user) update_issuable(issue, current_user, skip_users)
end end
# When close an issue we should: # When close an issue we should:
...@@ -60,8 +60,8 @@ class TodoService ...@@ -60,8 +60,8 @@ class TodoService
# #
# * create a todo for each mentioned user on merge request # * create a todo for each mentioned user on merge request
# #
def update_merge_request(merge_request, current_user) def update_merge_request(merge_request, current_user, skip_users = [])
update_issuable(merge_request, current_user) update_issuable(merge_request, current_user, skip_users)
end end
# When close a merge request we should: # When close a merge request we should:
...@@ -123,7 +123,7 @@ class TodoService ...@@ -123,7 +123,7 @@ class TodoService
mark_pending_todos_as_done(merge_request, merge_request.author) mark_pending_todos_as_done(merge_request, merge_request.author)
mark_pending_todos_as_done(merge_request, merge_request.merge_user) if merge_request.merge_when_pipeline_succeeds? mark_pending_todos_as_done(merge_request, merge_request.merge_user) if merge_request.merge_when_pipeline_succeeds?
end end
# When a merge request could not be automatically merged due to its unmergeable state we should: # When a merge request could not be automatically merged due to its unmergeable state we should:
# #
# * create a todo for a merge_user # * create a todo for a merge_user
...@@ -131,7 +131,7 @@ class TodoService ...@@ -131,7 +131,7 @@ class TodoService
def merge_request_became_unmergeable(merge_request) def merge_request_became_unmergeable(merge_request)
create_unmergeable_todo(merge_request, merge_request.merge_user) if merge_request.merge_when_pipeline_succeeds? create_unmergeable_todo(merge_request, merge_request.merge_user) if merge_request.merge_when_pipeline_succeeds?
end end
# When create a note we should: # When create a note we should:
# #
# * mark all pending todos related to the noteable for the note author as done # * mark all pending todos related to the noteable for the note author as done
...@@ -146,8 +146,8 @@ class TodoService ...@@ -146,8 +146,8 @@ class TodoService
# * mark all pending todos related to the noteable for the current user as done # * mark all pending todos related to the noteable for the current user as done
# * create a todo for each new user mentioned on note # * create a todo for each new user mentioned on note
# #
def update_note(note, current_user) def update_note(note, current_user, skip_users = [])
handle_note(note, current_user) handle_note(note, current_user, skip_users)
end end
# When an emoji is awarded we should: # When an emoji is awarded we should:
...@@ -223,11 +223,11 @@ class TodoService ...@@ -223,11 +223,11 @@ class TodoService
create_mention_todos(issuable.project, issuable, author) create_mention_todos(issuable.project, issuable, author)
end end
def update_issuable(issuable, author) def update_issuable(issuable, author, skip_users = [])
# Skip toggling a task list item in a description # Skip toggling a task list item in a description
return if toggling_tasks?(issuable) return if toggling_tasks?(issuable)
create_mention_todos(issuable.project, issuable, author) create_mention_todos(issuable.project, issuable, author, nil, skip_users)
end end
def destroy_issuable(issuable, user) def destroy_issuable(issuable, user)
...@@ -239,7 +239,7 @@ class TodoService ...@@ -239,7 +239,7 @@ class TodoService
issuable.tasks? && issuable.updated_tasks.any? issuable.tasks? && issuable.updated_tasks.any?
end end
def handle_note(note, author) def handle_note(note, author, skip_users = [])
# Skip system notes, and notes on project snippet # Skip system notes, and notes on project snippet
return if note.system? || note.for_snippet? return if note.system? || note.for_snippet?
...@@ -247,7 +247,7 @@ class TodoService ...@@ -247,7 +247,7 @@ class TodoService
target = note.noteable target = note.noteable
mark_pending_todos_as_done(target, author) mark_pending_todos_as_done(target, author)
create_mention_todos(project, target, author, note) create_mention_todos(project, target, author, note, skip_users)
end end
def create_assignment_todo(issuable, author) def create_assignment_todo(issuable, author)
...@@ -257,14 +257,14 @@ class TodoService ...@@ -257,14 +257,14 @@ class TodoService
end end
end end
def create_mention_todos(project, target, author, note = nil) def create_mention_todos(project, target, author, note = nil, skip_users = [])
# Create Todos for directly addressed users # Create Todos for directly addressed users
directly_addressed_users = filter_directly_addressed_users(project, note || target, author) directly_addressed_users = filter_directly_addressed_users(project, note || target, author, skip_users)
attributes = attributes_for_todo(project, target, author, Todo::DIRECTLY_ADDRESSED, note) attributes = attributes_for_todo(project, target, author, Todo::DIRECTLY_ADDRESSED, note)
create_todos(directly_addressed_users, attributes) create_todos(directly_addressed_users, attributes)
# Create Todos for mentioned users # Create Todos for mentioned users
mentioned_users = filter_mentioned_users(project, note || target, author) mentioned_users = filter_mentioned_users(project, note || target, author, skip_users)
attributes = attributes_for_todo(project, target, author, Todo::MENTIONED, note) attributes = attributes_for_todo(project, target, author, Todo::MENTIONED, note)
create_todos(mentioned_users, attributes) create_todos(mentioned_users, attributes)
end end
...@@ -307,13 +307,13 @@ class TodoService ...@@ -307,13 +307,13 @@ class TodoService
reject_users_without_access(users, project, target).uniq reject_users_without_access(users, project, target).uniq
end end
def filter_mentioned_users(project, target, author) def filter_mentioned_users(project, target, author, skip_users = [])
mentioned_users = target.mentioned_users(author) mentioned_users = target.mentioned_users(author) - skip_users
filter_todo_users(mentioned_users, project, target) filter_todo_users(mentioned_users, project, target)
end end
def filter_directly_addressed_users(project, target, author) def filter_directly_addressed_users(project, target, author, skip_users = [])
directly_addressed_users = target.directly_addressed_users(author) directly_addressed_users = target.directly_addressed_users(author) - skip_users
filter_todo_users(directly_addressed_users, project, target) filter_todo_users(directly_addressed_users, project, target)
end end
......
---
title: Create todos only for new mentions
merge_request:
author:
...@@ -13,6 +13,7 @@ describe Issues::UpdateService, services: true do ...@@ -13,6 +13,7 @@ describe Issues::UpdateService, services: true do
let(:issue) do let(:issue) do
create(:issue, title: 'Old title', create(:issue, title: 'Old title',
description: "for #{user2.to_reference}",
assignee_id: user3.id, assignee_id: user3.id,
project: project) project: project)
end end
...@@ -182,16 +183,24 @@ describe Issues::UpdateService, services: true do ...@@ -182,16 +183,24 @@ describe Issues::UpdateService, services: true do
it 'marks pending todos as done' do it 'marks pending todos as done' do
expect(todo.reload.done?).to eq true expect(todo.reload.done?).to eq true
end end
it 'does not create any new todos' do
expect(Todo.count).to eq(1)
end
end end
context 'when the description change' do context 'when the description change' do
before do before do
update_issue(description: 'Also please fix') update_issue(description: "Also please fix #{user2.to_reference} #{user3.to_reference}")
end end
it 'marks todos as done' do it 'marks todos as done' do
expect(todo.reload.done?).to eq true expect(todo.reload.done?).to eq true
end end
it 'creates only 1 new todo' do
expect(Todo.count).to eq(2)
end
end end
context 'when is reassigned' do context 'when is reassigned' do
......
...@@ -12,6 +12,7 @@ describe MergeRequests::UpdateService, services: true do ...@@ -12,6 +12,7 @@ describe MergeRequests::UpdateService, services: true do
let(:merge_request) do let(:merge_request) do
create(:merge_request, :simple, title: 'Old title', create(:merge_request, :simple, title: 'Old title',
description: "FYI #{user2.to_reference}",
assignee_id: user3.id, assignee_id: user3.id,
source_project: project) source_project: project)
end end
...@@ -225,16 +226,24 @@ describe MergeRequests::UpdateService, services: true do ...@@ -225,16 +226,24 @@ describe MergeRequests::UpdateService, services: true do
it 'marks pending todos as done' do it 'marks pending todos as done' do
expect(pending_todo.reload).to be_done expect(pending_todo.reload).to be_done
end end
it 'does not create any new todos' do
expect(Todo.count).to eq(1)
end
end end
context 'when the description change' do context 'when the description change' do
before do before do
update_merge_request({ description: 'Also please fix' }) update_merge_request({ description: "Also please fix #{user2.to_reference} #{user3.to_reference}" })
end end
it 'marks pending todos as done' do it 'marks pending todos as done' do
expect(pending_todo.reload).to be_done expect(pending_todo.reload).to be_done
end end
it 'creates only 1 new todo' do
expect(Todo.count).to eq(2)
end
end end
context 'when is reassigned' do context 'when is reassigned' do
......
...@@ -4,12 +4,14 @@ describe Notes::UpdateService, services: true do ...@@ -4,12 +4,14 @@ describe Notes::UpdateService, services: true do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) } let(:user2) { create(:user) }
let(:user3) { create(:user) }
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
let(:note) { create(:note, project: project, noteable: issue, author: user, note: 'Old note') } let(:note) { create(:note, project: project, noteable: issue, author: user, note: "Old note #{user2.to_reference}") }
before do before do
project.team << [user, :master] project.team << [user, :master]
project.team << [user2, :developer] project.team << [user2, :developer]
project.team << [user3, :developer]
end end
describe '#execute' do describe '#execute' do
...@@ -23,22 +25,30 @@ describe Notes::UpdateService, services: true do ...@@ -23,22 +25,30 @@ describe Notes::UpdateService, services: true do
context 'when the note change' do context 'when the note change' do
before do before do
update_note({ note: 'New note' }) update_note({ note: "New note #{user2.to_reference} #{user3.to_reference}" })
end end
it 'marks todos as done' do it 'marks todos as done' do
expect(todo.reload).to be_done expect(todo.reload).to be_done
end end
it 'creates only 1 new todo' do
expect(Todo.count).to eq(2)
end
end end
context 'when the note does not change' do context 'when the note does not change' do
before do before do
update_note({ note: 'Old note' }) update_note({ note: "Old note #{user2.to_reference}" })
end end
it 'keep todos' do it 'keep todos' do
expect(todo.reload).to be_pending expect(todo.reload).to be_pending
end end
it 'does not create any new todos' do
expect(Todo.count).to eq(1)
end
end end
end end
end end
......
This diff is collapsed.
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