Skip to content
Snippets Groups Projects
Commit 387c4b2c authored by Valery Sizov's avatar Valery Sizov
Browse files

Backport of multiple_assignees_feature [ci skip]

parent 68c12e15
No related branches found
No related tags found
No related merge requests found
Showing
with 305 additions and 196 deletions
Loading
Loading
@@ -15,14 +15,14 @@ describe MergeRequests::AssignIssuesService, services: true do
expect(service.assignable_issues.map(&:id)).to include(issue.id)
end
 
it 'ignores issues already assigned to any user' do
issue.update!(assignee: create(:user))
it 'ignores issues the user cannot update assignee on' do
project.team.truncate
 
expect(service.assignable_issues).to be_empty
end
 
it 'ignores issues the user cannot update assignee on' do
project.team.truncate
it 'ignores issues already assigned to any user' do
issue.assignees = [create(:user)]
 
expect(service.assignable_issues).to be_empty
end
Loading
Loading
@@ -44,7 +44,7 @@ describe MergeRequests::AssignIssuesService, services: true do
end
 
it 'assigns these to the merge request owner' do
expect { service.execute }.to change { issue.reload.assignee }.to(user)
expect { service.execute }.to change { issue.assignees.first }.to(user)
end
 
it 'ignores external issues' do
Loading
Loading
Loading
Loading
@@ -84,7 +84,87 @@ describe MergeRequests::CreateService, services: true do
end
end
 
it_behaves_like 'issuable create service'
context 'Slash commands' do
context 'with assignee and milestone in params and command' do
let(:merge_request) { described_class.new(project, user, opts).execute }
let(:milestone) { create(:milestone, project: project) }
let(:opts) do
{
assignee_id: create(:user).id,
milestone_id: 1,
title: 'Title',
description: %(/assign @#{assignee.username}\n/milestone %"#{milestone.name}"),
source_branch: 'feature',
target_branch: 'master'
}
end
before do
project.team << [user, :master]
project.team << [assignee, :master]
end
it 'assigns and sets milestone to issuable from command' do
expect(merge_request).to be_persisted
expect(merge_request.assignee).to eq(assignee)
expect(merge_request.milestone).to eq(milestone)
end
end
end
context 'merge request create service' do
context 'asssignee_id' do
let(:assignee) { create(:user) }
before { project.team << [user, :master] }
it 'removes assignee_id when user id is invalid' do
opts = { title: 'Title', description: 'Description', assignee_id: -1 }
merge_request = described_class.new(project, user, opts).execute
expect(merge_request.assignee_id).to be_nil
end
it 'removes assignee_id when user id is 0' do
opts = { title: 'Title', description: 'Description', assignee_id: 0 }
merge_request = described_class.new(project, user, opts).execute
expect(merge_request.assignee_id).to be_nil
end
it 'saves assignee when user id is valid' do
project.team << [assignee, :master]
opts = { title: 'Title', description: 'Description', assignee_id: assignee.id }
merge_request = described_class.new(project, user, opts).execute
expect(merge_request.assignee).to eq(assignee)
end
context "when issuable feature is private" do
before do
project.project_feature.update(issues_access_level: ProjectFeature::PRIVATE,
merge_requests_access_level: ProjectFeature::PRIVATE)
end
levels = [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC]
levels.each do |level|
it "removes not authorized assignee when project is #{Gitlab::VisibilityLevel.level_name(level)}" do
project.update(visibility_level: level)
opts = { title: 'Title', description: 'Description', assignee_id: assignee.id }
merge_request = described_class.new(project, user, opts).execute
expect(merge_request.assignee_id).to be_nil
end
end
end
end
end
 
context 'while saving references to issues that the created merge request closes' do
let(:first_issue) { create(:issue, project: project) }
Loading
Loading
Loading
Loading
@@ -423,6 +423,54 @@ describe MergeRequests::UpdateService, services: true do
end
end
 
context 'updating asssignee_id' do
it 'does not update assignee when assignee_id is invalid' do
merge_request.update(assignee_id: user.id)
update_merge_request(assignee_id: -1)
expect(merge_request.reload.assignee).to eq(user)
end
it 'unassigns assignee when user id is 0' do
merge_request.update(assignee_id: user.id)
update_merge_request(assignee_id: 0)
expect(merge_request.assignee_id).to be_nil
end
it 'saves assignee when user id is valid' do
update_merge_request(assignee_id: user.id)
expect(merge_request.assignee_id).to eq(user.id)
end
it 'does not update assignee_id when user cannot read issue' do
non_member = create(:user)
original_assignee = merge_request.assignee
update_merge_request(assignee_id: non_member.id)
expect(merge_request.assignee_id).to eq(original_assignee.id)
end
context "when issuable feature is private" do
levels = [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC]
levels.each do |level|
it "does not update with unauthorized assignee when project is #{Gitlab::VisibilityLevel.level_name(level)}" do
assignee = create(:user)
project.update(visibility_level: level)
feature_visibility_attr = :"#{merge_request.model_name.plural}_access_level"
project.project_feature.update_attribute(feature_visibility_attr, ProjectFeature::PRIVATE)
expect{ update_merge_request(assignee_id: assignee) }.not_to change{ merge_request.assignee }
end
end
end
end
include_examples 'issuable update service' do
let(:open_issuable) { merge_request }
let(:closed_issuable) { create(:closed_merge_request, source_project: project) }
Loading
Loading
Loading
Loading
@@ -66,7 +66,7 @@ describe Notes::SlashCommandsService, services: true do
expect(content).to eq ''
expect(note.noteable).to be_closed
expect(note.noteable.labels).to match_array(labels)
expect(note.noteable.assignee).to eq(assignee)
expect(note.noteable.assignees).to eq([assignee])
expect(note.noteable.milestone).to eq(milestone)
end
end
Loading
Loading
@@ -113,7 +113,7 @@ describe Notes::SlashCommandsService, services: true do
expect(content).to eq "HELLO\nWORLD"
expect(note.noteable).to be_closed
expect(note.noteable.labels).to match_array(labels)
expect(note.noteable.assignee).to eq(assignee)
expect(note.noteable.assignees).to eq([assignee])
expect(note.noteable.milestone).to eq(milestone)
end
end
Loading
Loading
Loading
Loading
@@ -4,6 +4,7 @@ describe NotificationService, services: true do
include EmailHelpers
 
let(:notification) { NotificationService.new }
let(:assignee) { create(:user) }
 
around(:each) do |example|
perform_enqueued_jobs do
Loading
Loading
@@ -52,7 +53,11 @@ describe NotificationService, services: true do
 
shared_examples 'participating by assignee notification' do
it 'emails the participant' do
issuable.update_attribute(:assignee, participant)
if issuable.is_a?(Issue)
issuable.assignees << participant
else
issuable.update_attribute(:assignee, participant)
end
 
notification_trigger
 
Loading
Loading
@@ -103,14 +108,14 @@ describe NotificationService, services: true do
describe 'Notes' do
context 'issue note' do
let(:project) { create(:empty_project, :private) }
let(:issue) { create(:issue, project: project, assignee: create(:user)) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) }
let(:issue) { create(:issue, project: project, assignees: [assignee]) }
let(:mentioned_issue) { create(:issue, assignees: issue.assignees) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced, @outsider also') }
 
before do
build_team(note.project)
project.add_master(issue.author)
project.add_master(issue.assignee)
project.add_master(assignee)
project.add_master(note.author)
create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@subscribed_participant cc this guy')
update_custom_notification(:new_note, @u_guest_custom, resource: project)
Loading
Loading
@@ -130,7 +135,7 @@ describe NotificationService, services: true do
 
should_email(@u_watcher)
should_email(note.noteable.author)
should_email(note.noteable.assignee)
should_email(note.noteable.assignees.first)
should_email(@u_custom_global)
should_email(@u_mentioned)
should_email(@subscriber)
Loading
Loading
@@ -196,7 +201,7 @@ describe NotificationService, services: true do
notification.new_note(note)
 
should_email(note.noteable.author)
should_email(note.noteable.assignee)
should_email(note.noteable.assignees.first)
should_email(@u_mentioned)
should_email(@u_custom_global)
should_not_email(@u_guest_custom)
Loading
Loading
@@ -218,7 +223,7 @@ describe NotificationService, services: true do
let(:member) { create(:user) }
let(:guest) { create(:user) }
let(:admin) { create(:admin) }
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee) }
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignees: [assignee]) }
let(:note) { create(:note_on_issue, noteable: confidential_issue, project: project, note: "#{author.to_reference} #{assignee.to_reference} #{non_member.to_reference} #{member.to_reference} #{admin.to_reference}") }
let(:guest_watcher) { create_user_with_notification(:watch, "guest-watcher-confidential") }
 
Loading
Loading
@@ -244,8 +249,8 @@ describe NotificationService, services: true do
 
context 'issue note mention' do
let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project, assignee: create(:user)) }
let(:mentioned_issue) { create(:issue, assignee: issue.assignee) }
let(:issue) { create(:issue, project: project, assignees: [assignee]) }
let(:mentioned_issue) { create(:issue, assignees: issue.assignees) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@all mentioned') }
 
before do
Loading
Loading
@@ -269,7 +274,7 @@ describe NotificationService, services: true do
 
should_email(@u_guest_watcher)
should_email(note.noteable.author)
should_email(note.noteable.assignee)
should_email(note.noteable.assignees.first)
should_not_email(note.author)
should_email(@u_mentioned)
should_not_email(@u_disabled)
Loading
Loading
@@ -449,7 +454,7 @@ describe NotificationService, services: true do
let(:group) { create(:group) }
let(:project) { create(:empty_project, :public, namespace: group) }
let(:another_project) { create(:empty_project, :public, namespace: group) }
let(:issue) { create :issue, project: project, assignee: create(:user), description: 'cc @participant' }
let(:issue) { create :issue, project: project, assignees: [assignee], description: 'cc @participant' }
 
before do
build_team(issue.project)
Loading
Loading
@@ -465,7 +470,7 @@ describe NotificationService, services: true do
it do
notification.new_issue(issue, @u_disabled)
 
should_email(issue.assignee)
should_email(assignee)
should_email(@u_watcher)
should_email(@u_guest_watcher)
should_email(@u_guest_custom)
Loading
Loading
@@ -480,10 +485,10 @@ describe NotificationService, services: true do
end
 
it do
create_global_setting_for(issue.assignee, :mention)
create_global_setting_for(issue.assignees.first, :mention)
notification.new_issue(issue, @u_disabled)
 
should_not_email(issue.assignee)
should_not_email(issue.assignees.first)
end
 
it "emails the author if they've opted into notifications about their activity" do
Loading
Loading
@@ -528,7 +533,7 @@ describe NotificationService, services: true do
let(:member) { create(:user) }
let(:guest) { create(:user) }
let(:admin) { create(:admin) }
let(:confidential_issue) { create(:issue, :confidential, project: project, title: 'Confidential issue', author: author, assignee: assignee) }
let(:confidential_issue) { create(:issue, :confidential, project: project, title: 'Confidential issue', author: author, assignees: [assignee]) }
 
it "emails subscribers of the issue's labels that can read the issue" do
project.add_developer(member)
Loading
Loading
@@ -572,9 +577,9 @@ describe NotificationService, services: true do
end
 
it 'emails new assignee' do
notification.reassigned_issue(issue, @u_disabled)
notification.reassigned_issue(issue, @u_disabled, [assignee])
 
should_email(issue.assignee)
should_email(issue.assignees.first)
should_email(@u_watcher)
should_email(@u_guest_watcher)
should_email(@u_guest_custom)
Loading
Loading
@@ -588,9 +593,8 @@ describe NotificationService, services: true do
end
 
it 'emails previous assignee even if he has the "on mention" notif level' do
issue.update_attribute(:assignee, @u_mentioned)
issue.update_attributes(assignee: @u_watcher)
notification.reassigned_issue(issue, @u_disabled)
issue.assignees = [@u_mentioned]
notification.reassigned_issue(issue, @u_disabled, [@u_watcher])
 
should_email(@u_mentioned)
should_email(@u_watcher)
Loading
Loading
@@ -606,11 +610,11 @@ describe NotificationService, services: true do
end
 
it 'emails new assignee even if he has the "on mention" notif level' do
issue.update_attributes(assignee: @u_mentioned)
notification.reassigned_issue(issue, @u_disabled)
issue.assignees = [@u_mentioned]
notification.reassigned_issue(issue, @u_disabled, [@u_mentioned])
 
expect(issue.assignee).to be @u_mentioned
should_email(issue.assignee)
expect(issue.assignees.first).to be @u_mentioned
should_email(issue.assignees.first)
should_email(@u_watcher)
should_email(@u_guest_watcher)
should_email(@u_guest_custom)
Loading
Loading
@@ -624,11 +628,11 @@ describe NotificationService, services: true do
end
 
it 'emails new assignee' do
issue.update_attribute(:assignee, @u_mentioned)
notification.reassigned_issue(issue, @u_disabled)
issue.assignees = [@u_mentioned]
notification.reassigned_issue(issue, @u_disabled, [@u_mentioned])
 
expect(issue.assignee).to be @u_mentioned
should_email(issue.assignee)
expect(issue.assignees.first).to be @u_mentioned
should_email(issue.assignees.first)
should_email(@u_watcher)
should_email(@u_guest_watcher)
should_email(@u_guest_custom)
Loading
Loading
@@ -642,17 +646,17 @@ describe NotificationService, services: true do
end
 
it 'does not email new assignee if they are the current user' do
issue.update_attribute(:assignee, @u_mentioned)
notification.reassigned_issue(issue, @u_mentioned)
issue.assignees = [@u_mentioned]
notification.reassigned_issue(issue, @u_mentioned, [@u_mentioned])
 
expect(issue.assignee).to be @u_mentioned
expect(issue.assignees.first).to be @u_mentioned
should_email(@u_watcher)
should_email(@u_guest_watcher)
should_email(@u_guest_custom)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@u_custom_global)
should_not_email(issue.assignee)
should_not_email(issue.assignees.first)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
Loading
Loading
@@ -662,7 +666,7 @@ describe NotificationService, services: true do
it_behaves_like 'participating notifications' do
let(:participant) { create(:user, username: 'user-participant') }
let(:issuable) { issue }
let(:notification_trigger) { notification.reassigned_issue(issue, @u_disabled) }
let(:notification_trigger) { notification.reassigned_issue(issue, @u_disabled, [assignee]) }
end
end
 
Loading
Loading
@@ -705,7 +709,7 @@ describe NotificationService, services: true do
it "doesn't send email to anyone but subscribers of the given labels" do
notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled)
 
should_not_email(issue.assignee)
should_not_email(issue.assignees.first)
should_not_email(issue.author)
should_not_email(@u_watcher)
should_not_email(@u_guest_watcher)
Loading
Loading
@@ -729,7 +733,7 @@ describe NotificationService, services: true do
let(:member) { create(:user) }
let(:guest) { create(:user) }
let(:admin) { create(:admin) }
let(:confidential_issue) { create(:issue, :confidential, project: project, title: 'Confidential issue', author: author, assignee: assignee) }
let(:confidential_issue) { create(:issue, :confidential, project: project, title: 'Confidential issue', author: author, assignees: [assignee]) }
let!(:label_1) { create(:label, project: project, issues: [confidential_issue]) }
let!(:label_2) { create(:label, project: project) }
 
Loading
Loading
@@ -767,7 +771,7 @@ describe NotificationService, services: true do
it 'sends email to issue assignee and issue author' do
notification.close_issue(issue, @u_disabled)
 
should_email(issue.assignee)
should_email(issue.assignees.first)
should_email(issue.author)
should_email(@u_watcher)
should_email(@u_guest_watcher)
Loading
Loading
@@ -798,7 +802,7 @@ describe NotificationService, services: true do
it 'sends email to issue notification recipients' do
notification.reopen_issue(issue, @u_disabled)
 
should_email(issue.assignee)
should_email(issue.assignees.first)
should_email(issue.author)
should_email(@u_watcher)
should_email(@u_guest_watcher)
Loading
Loading
@@ -826,7 +830,7 @@ describe NotificationService, services: true do
it 'sends email to issue notification recipients' do
notification.issue_moved(issue, new_issue, @u_disabled)
 
should_email(issue.assignee)
should_email(issue.assignees.first)
should_email(issue.author)
should_email(@u_watcher)
should_email(@u_guest_watcher)
Loading
Loading
Loading
Loading
@@ -11,7 +11,7 @@ describe Projects::AutocompleteService, services: true do
let(:project) { create(:empty_project, :public) }
let!(:issue) { create(:issue, project: project, title: 'Issue 1') }
let!(:security_issue_1) { create(:issue, :confidential, project: project, title: 'Security issue 1', author: author) }
let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project, assignee: assignee) }
let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project, assignees: [assignee]) }
 
it 'does not list project confidential issues for guests' do
autocomplete = described_class.new(project, nil)
Loading
Loading
Loading
Loading
@@ -3,6 +3,7 @@ require 'spec_helper'
describe SlashCommands::InterpretService, services: true do
let(:project) { create(:empty_project, :public) }
let(:developer) { create(:user) }
let(:developer2) { create(:user) }
let(:issue) { create(:issue, project: project) }
let(:milestone) { create(:milestone, project: project, title: '9.10') }
let(:inprogress) { create(:label, project: project, title: 'In Progress') }
Loading
Loading
@@ -42,6 +43,7 @@ describe SlashCommands::InterpretService, services: true do
end
end
 
<<<<<<< HEAD
shared_examples 'assign command' do
it 'fetches assignee and populates assignee_id if content contains /assign' do
_, updates = service.execute(content, issuable)
Loading
Loading
@@ -59,6 +61,8 @@ describe SlashCommands::InterpretService, services: true do
end
end
 
=======
>>>>>>> b0a2435... Merge branch 'multiple_assignees_review_upstream' into ee_master
shared_examples 'milestone command' do
it 'fetches milestone and populates milestone_id if content contains /milestone' do
milestone # populate the milestone
Loading
Loading
@@ -371,14 +375,46 @@ describe SlashCommands::InterpretService, services: true do
let(:issuable) { issue }
end
 
it_behaves_like 'assign command' do
context 'assign command' do
let(:content) { "/assign @#{developer.username}" }
let(:issuable) { issue }
context 'Issue' do
it 'fetches assignee and populates assignee_id if content contains /assign' do
_, updates = service.execute(content, issue)
expect(updates).to eq(assignee_ids: [developer.id])
end
end
context 'Merge Request' do
it 'fetches assignee and populates assignee_id if content contains /assign' do
_, updates = service.execute(content, merge_request)
expect(updates).to eq(assignee_id: developer.id)
end
end
end
 
it_behaves_like 'assign command' do
let(:content) { "/assign @#{developer.username}" }
let(:issuable) { merge_request }
context 'assign command with multiple assignees' do
let(:content) { "/assign @#{developer.username} @#{developer2.username}" }
before{ project.team << [developer2, :developer] }
context 'Issue' do
it 'fetches assignee and populates assignee_id if content contains /assign' do
_, updates = service.execute(content, issue)
expect(updates[:assignee_ids]).to match_array([developer.id, developer2.id])
end
end
context 'Merge Request' do
it 'fetches assignee and populates assignee_id if content contains /assign' do
_, updates = service.execute(content, merge_request)
expect(updates).to eq(assignee_id: developer.id)
end
end
end
 
it_behaves_like 'empty command' do
Loading
Loading
@@ -391,14 +427,26 @@ describe SlashCommands::InterpretService, services: true do
let(:issuable) { issue }
end
 
it_behaves_like 'unassign command' do
context 'unassign command' do
let(:content) { '/unassign' }
let(:issuable) { issue }
end
 
it_behaves_like 'unassign command' do
let(:content) { '/unassign' }
let(:issuable) { merge_request }
context 'Issue' do
it 'populates assignee_ids: [] if content contains /unassign' do
issue.update(assignee_ids: [developer.id])
_, updates = service.execute(content, issue)
expect(updates).to eq(assignee_ids: [])
end
end
context 'Merge Request' do
it 'populates assignee_id: nil if content contains /unassign' do
merge_request.update(assignee_id: developer.id)
_, updates = service.execute(content, merge_request)
expect(updates).to eq(assignee_id: nil)
end
end
end
 
it_behaves_like 'milestone command' do
Loading
Loading
Loading
Loading
@@ -6,6 +6,7 @@ describe SystemNoteService, services: true do
let(:project) { create(:empty_project) }
let(:author) { create(:user) }
let(:noteable) { create(:issue, project: project) }
let(:issue) { noteable }
 
shared_examples_for 'a system note' do
let(:expected_noteable) { noteable }
Loading
Loading
@@ -155,6 +156,50 @@ describe SystemNoteService, services: true do
end
end
 
describe '.change_issue_assignees' do
subject { described_class.change_issue_assignees(noteable, project, author, [assignee]) }
let(:assignee) { create(:user) }
let(:assignee1) { create(:user) }
let(:assignee2) { create(:user) }
let(:assignee3) { create(:user) }
it_behaves_like 'a system note'
def build_note(old_assignees, new_assignees)
issue.assignees = new_assignees
described_class.change_issue_assignees(issue, project, author, old_assignees).note
end
it 'builds a correct phrase when an assignee is added to a non-assigned issue' do
expect(build_note([], [assignee1])).to eq "assigned to @#{assignee1.username}"
end
it 'builds a correct phrase when assignee removed' do
expect(build_note([assignee1], [])).to eq 'removed all assignees'
end
it 'builds a correct phrase when assignees changed' do
expect(build_note([assignee1], [assignee2])).to eq \
"assigned to @#{assignee2.username} and unassigned @#{assignee1.username}"
end
it 'builds a correct phrase when three assignees removed and one added' do
expect(build_note([assignee, assignee1, assignee2], [assignee3])).to eq \
"assigned to @#{assignee3.username} and unassigned @#{assignee.username}, @#{assignee1.username}, and @#{assignee2.username}"
end
it 'builds a correct phrase when one assignee changed from a set' do
expect(build_note([assignee, assignee1], [assignee, assignee2])).to eq \
"assigned to @#{assignee2.username} and unassigned @#{assignee1.username}"
end
it 'builds a correct phrase when one assignee removed from a set' do
expect(build_note([assignee, assignee1, assignee2], [assignee, assignee1])).to eq \
"unassigned @#{assignee2.username}"
end
end
describe '.change_label' do
subject { described_class.change_label(noteable, project, author, added, removed) }
 
Loading
Loading
Loading
Loading
@@ -25,11 +25,11 @@ describe TodoService, services: true do
end
 
describe 'Issues' do
let(:issue) { create(:issue, project: project, assignee: john_doe, author: author, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") }
let(:addressed_issue) { create(:issue, project: project, assignee: john_doe, author: author, description: "#{directly_addressed}\n- [ ] Task 1\n- [ ] Task 2") }
let(:unassigned_issue) { create(:issue, project: project, assignee: nil) }
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee, description: mentions) }
let(:addressed_confident_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee, description: directly_addressed) }
let(:issue) { create(:issue, project: project, assignees: [john_doe], author: author, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") }
let(:addressed_issue) { create(:issue, project: project, assignees: [john_doe], author: author, description: "#{directly_addressed}\n- [ ] Task 1\n- [ ] Task 2") }
let(:unassigned_issue) { create(:issue, project: project, assignees: []) }
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignees: [assignee], description: mentions) }
let(:addressed_confident_issue) { create(:issue, :confidential, project: project, author: author, assignees: [assignee], description: directly_addressed) }
 
describe '#new_issue' do
it 'creates a todo if assigned' do
Loading
Loading
@@ -43,7 +43,7 @@ describe TodoService, services: true do
end
 
it 'creates a todo if assignee is the current user' do
unassigned_issue.update_attribute(:assignee, john_doe)
unassigned_issue.assignees = [john_doe]
service.new_issue(unassigned_issue, john_doe)
 
should_create_todo(user: john_doe, target: unassigned_issue, author: john_doe, action: Todo::ASSIGNED)
Loading
Loading
@@ -258,20 +258,20 @@ describe TodoService, services: true do
 
describe '#reassigned_issue' do
it 'creates a pending todo for new assignee' do
unassigned_issue.update_attribute(:assignee, john_doe)
unassigned_issue.assignees << john_doe
service.reassigned_issue(unassigned_issue, author)
 
should_create_todo(user: john_doe, target: unassigned_issue, action: Todo::ASSIGNED)
end
 
it 'does not create a todo if unassigned' do
issue.update_attribute(:assignee, nil)
issue.assignees.destroy_all
 
should_not_create_any_todo { service.reassigned_issue(issue, author) }
end
 
it 'creates a todo if new assignee is the current user' do
unassigned_issue.update_attribute(:assignee, john_doe)
unassigned_issue.assignees << john_doe
service.reassigned_issue(unassigned_issue, john_doe)
 
should_create_todo(user: john_doe, target: unassigned_issue, author: john_doe, action: Todo::ASSIGNED)
Loading
Loading
@@ -361,7 +361,7 @@ describe TodoService, services: true do
describe '#new_note' do
let!(:first_todo) { create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author) }
let!(:second_todo) { create(:todo, :assigned, user: john_doe, project: project, target: issue, author: author) }
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee) }
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignees: [assignee]) }
let(:note) { create(:note, project: project, noteable: issue, author: john_doe, note: mentions) }
let(:addressed_note) { create(:note, project: project, noteable: issue, author: john_doe, note: directly_addressed) }
let(:note_on_commit) { create(:note_on_commit, project: project, author: john_doe, note: mentions) }
Loading
Loading
@@ -854,7 +854,7 @@ describe TodoService, services: true do
end
 
it 'updates cached counts when a todo is created' do
issue = create(:issue, project: project, assignee: john_doe, author: author, description: mentions)
issue = create(:issue, project: project, assignees: [john_doe], author: author, description: mentions)
 
expect(john_doe.todos_pending_count).to eq(0)
expect(john_doe).to receive(:update_todos_count_cache).and_call_original
Loading
Loading
@@ -866,8 +866,8 @@ describe TodoService, services: true do
end
 
describe '#mark_todos_as_done' do
let(:issue) { create(:issue, project: project, author: author, assignee: john_doe) }
let(:another_issue) { create(:issue, project: project, author: author, assignee: john_doe) }
let(:issue) { create(:issue, project: project, author: author, assignees: [john_doe]) }
let(:another_issue) { create(:issue, project: project, author: author, assignees: [john_doe]) }
 
it 'marks a relation of todos as done' do
create(:todo, :mentioned, user: john_doe, target: issue, project: project)
Loading
Loading
Loading
Loading
@@ -62,7 +62,7 @@ shared_examples 'issuable record that supports slash commands in its description
note = issuable.notes.user.first
 
expect(note.note).to eq "Awesome!"
expect(issuable.assignee).to eq assignee
expect(issuable.assignees).to eq [assignee]
expect(issuable.labels).to eq [label_bug]
expect(issuable.milestone).to eq milestone
end
Loading
Loading
@@ -80,7 +80,7 @@ shared_examples 'issuable record that supports slash commands in its description
issuable.reload
 
expect(issuable.notes.user).to be_empty
expect(issuable.assignee).to eq assignee
expect(issuable.assignees).to eq [assignee]
expect(issuable.labels).to eq [label_bug]
expect(issuable.milestone).to eq milestone
end
Loading
Loading
Loading
Loading
@@ -10,7 +10,7 @@ module ExportFileHelper
 
create(:release, project: project)
 
issue = create(:issue, assignee: user, project: project)
issue = create(:issue, assignees: [user], project: project)
snippet = create(:project_snippet, project: project)
label = create(:label, project: project)
milestone = create(:milestone, project: project)
Loading
Loading
shared_examples 'issuable create service' do
context 'asssignee_id' do
let(:assignee) { create(:user) }
before { project.team << [user, :master] }
it 'removes assignee_id when user id is invalid' do
opts = { title: 'Title', description: 'Description', assignee_id: -1 }
issuable = described_class.new(project, user, opts).execute
expect(issuable.assignee_id).to be_nil
end
it 'removes assignee_id when user id is 0' do
opts = { title: 'Title', description: 'Description', assignee_id: 0 }
issuable = described_class.new(project, user, opts).execute
expect(issuable.assignee_id).to be_nil
end
it 'saves assignee when user id is valid' do
project.team << [assignee, :master]
opts = { title: 'Title', description: 'Description', assignee_id: assignee.id }
issuable = described_class.new(project, user, opts).execute
expect(issuable.assignee_id).to eq(assignee.id)
end
context "when issuable feature is private" do
before do
project.project_feature.update(issues_access_level: ProjectFeature::PRIVATE,
merge_requests_access_level: ProjectFeature::PRIVATE)
end
levels = [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC]
levels.each do |level|
it "removes not authorized assignee when project is #{Gitlab::VisibilityLevel.level_name(level)}" do
project.update(visibility_level: level)
opts = { title: 'Title', description: 'Description', assignee_id: assignee.id }
issuable = described_class.new(project, user, opts).execute
expect(issuable.assignee_id).to be_nil
end
end
end
end
end
Loading
Loading
@@ -49,23 +49,7 @@ shared_examples 'new issuable record that supports slash commands' do
 
it 'assigns and sets milestone to issuable' do
expect(issuable).to be_persisted
expect(issuable.assignee).to eq(assignee)
expect(issuable.milestone).to eq(milestone)
end
end
context 'with assignee and milestone in params and command' do
let(:example_params) do
{
assignee: create(:user),
milestone_id: 1,
description: %(/assign @#{assignee.username}\n/milestone %"#{milestone.name}")
}
end
it 'assigns and sets milestone to issuable from command' do
expect(issuable).to be_persisted
expect(issuable.assignee).to eq(assignee)
expect(issuable.assignees).to eq([assignee])
expect(issuable.milestone).to eq(milestone)
end
end
Loading
Loading
Loading
Loading
@@ -18,52 +18,4 @@ shared_examples 'issuable update service' do
end
end
end
context 'asssignee_id' do
it 'does not update assignee when assignee_id is invalid' do
open_issuable.update(assignee_id: user.id)
update_issuable(assignee_id: -1)
expect(open_issuable.reload.assignee).to eq(user)
end
it 'unassigns assignee when user id is 0' do
open_issuable.update(assignee_id: user.id)
update_issuable(assignee_id: 0)
expect(open_issuable.assignee_id).to be_nil
end
it 'saves assignee when user id is valid' do
update_issuable(assignee_id: user.id)
expect(open_issuable.assignee_id).to eq(user.id)
end
it 'does not update assignee_id when user cannot read issue' do
non_member = create(:user)
original_assignee = open_issuable.assignee
update_issuable(assignee_id: non_member.id)
expect(open_issuable.assignee_id).to eq(original_assignee.id)
end
context "when issuable feature is private" do
levels = [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC]
levels.each do |level|
it "does not update with unauthorized assignee when project is #{Gitlab::VisibilityLevel.level_name(level)}" do
assignee = create(:user)
project.update(visibility_level: level)
feature_visibility_attr = :"#{open_issuable.model_name.plural}_access_level"
project.project_feature.update_attribute(feature_visibility_attr, ProjectFeature::PRIVATE)
expect{ update_issuable(assignee_id: assignee) }.not_to change{ open_issuable.assignee }
end
end
end
end
end
Loading
Loading
@@ -34,7 +34,7 @@ shared_examples 'issuable time tracker' do
submit_time('/estimate 3w 1d 1h')
submit_time('/remove_estimate')
 
page.within '#issuable-time-tracker' do
page.within '.time-tracking-component-wrap' do
expect(page).to have_content 'No estimate or time spent'
end
end
Loading
Loading
@@ -43,13 +43,13 @@ shared_examples 'issuable time tracker' do
submit_time('/spend 3w 1d 1h')
submit_time('/remove_time_spent')
 
page.within '#issuable-time-tracker' do
page.within '.time-tracking-component-wrap' do
expect(page).to have_content 'No estimate or time spent'
end
end
 
it 'shows the help state when icon is clicked' do
page.within '#issuable-time-tracker' do
page.within '.time-tracking-component-wrap' do
find('.help-button').click
expect(page).to have_content 'Track time with slash commands'
expect(page).to have_content 'Learn more'
Loading
Loading
@@ -57,7 +57,7 @@ shared_examples 'issuable time tracker' do
end
 
it 'hides the help state when close icon is clicked' do
page.within '#issuable-time-tracker' do
page.within '.time-tracking-component-wrap' do
find('.help-button').click
find('.close-help-button').click
 
Loading
Loading
@@ -67,7 +67,7 @@ shared_examples 'issuable time tracker' do
end
 
it 'displays the correct help url' do
page.within '#issuable-time-tracker' do
page.within '.time-tracking-component-wrap' do
find('.help-button').click
 
expect(find_link('Learn more')[:href]).to have_content('/help/workflow/time_tracking.md')
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment