diff options
author | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2016-06-14 13:44:03 +0200 |
---|---|---|
committer | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2016-06-14 13:44:03 +0200 |
commit | ab9a8643d80c178d4d16c15f4f72deb65210074c (patch) | |
tree | 9c0ff13c7aaaac4624389a640c1a5d45a40358bb /spec/services | |
parent | d8c4556d3c8623bf48e689f3734c9c35cda34c2f (diff) | |
parent | 066020fcd015ca92397b794342a49a46dd02582c (diff) | |
download | gitlab-ce-ab9a8643d80c178d4d16c15f4f72deb65210074c.tar.gz |
Merge branch 'master' into fix/status-of-pipeline-without-builds
* master: (538 commits)
Fix broken URI joining for `teamcity_url` with suffixes
Factorize duplicated code into a method in BambooService and update specs
Fix broken URI joining for `bamboo_url` with suffixes
Honor credentials on calling Bamboo CI trigger
Update CHANGELOG
Use Issue.visible_to_user in Notes.search to avoid query duplication
Project members with guest role can't access confidential issues
Allow users to create confidential issues in private projects
Update CHANGELOG
Remove deprecated issues_tracker and issues_tracker_id from project
Schema doesn’t reflect the changes of the last 3 migrations
Apply reviewer notes: update CHANGELOG, adjust code formatting
Move issue rendering tests into separate contexts
Move change description to proper release and fix typo
Add more information into RSS fead for issues
Revert CHANGELOG
Also rename "find" in the specs
Change to new Notes styleguide
Add guide on changing a document's location
Change logs.md location in README
...
Conflicts:
app/services/ci/create_builds_service.rb
app/services/ci/create_pipeline_service.rb
app/services/create_commit_builds_service.rb
spec/models/ci/commit_spec.rb
spec/services/ci/create_builds_service_spec.rb
spec/services/create_commit_builds_service_spec.rb
Diffstat (limited to 'spec/services')
-rw-r--r-- | spec/services/ci/create_builds_service_spec.rb | 4 | ||||
-rw-r--r-- | spec/services/ci/create_trigger_request_service_spec.rb | 6 | ||||
-rw-r--r-- | spec/services/ci/image_for_build_service_spec.rb | 4 | ||||
-rw-r--r-- | spec/services/ci/register_build_service_spec.rb | 4 | ||||
-rw-r--r-- | spec/services/create_commit_builds_service_spec.rb | 168 | ||||
-rw-r--r-- | spec/services/issues/bulk_update_service_spec.rb | 281 | ||||
-rw-r--r-- | spec/services/issues/move_service_spec.rb | 5 | ||||
-rw-r--r-- | spec/services/issues/update_service_spec.rb | 46 | ||||
-rw-r--r-- | spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb | 8 | ||||
-rw-r--r-- | spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb | 32 | ||||
-rw-r--r-- | spec/services/notes/create_service_spec.rb | 30 | ||||
-rw-r--r-- | spec/services/notification_service_spec.rb | 312 | ||||
-rw-r--r-- | spec/services/projects/autocomplete_service_spec.rb | 12 | ||||
-rw-r--r-- | spec/services/projects/import_service_spec.rb | 2 | ||||
-rw-r--r-- | spec/services/system_note_service_spec.rb | 3 | ||||
-rw-r--r-- | spec/services/todo_service_spec.rb | 65 |
16 files changed, 764 insertions, 218 deletions
diff --git a/spec/services/ci/create_builds_service_spec.rb b/spec/services/ci/create_builds_service_spec.rb index 8e737fd44f9..8b0becd83d3 100644 --- a/spec/services/ci/create_builds_service_spec.rb +++ b/spec/services/ci/create_builds_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Ci::CreateBuildsService, services: true do - let(:commit) { create(:ci_commit, ref: 'master') } + let(:pipeline) { create(:ci_pipeline, ref: 'master') } let(:user) { create(:user) } describe '#execute' do @@ -9,7 +9,7 @@ describe Ci::CreateBuildsService, services: true do # subject do - described_class.new(commit).execute('test', user, status, nil) + described_class.new(pipeline).execute('test', user, status, nil) end context 'next builds available' do diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb index dbdc5370bd8..ae4b7aca820 100644 --- a/spec/services/ci/create_trigger_request_service_spec.rb +++ b/spec/services/ci/create_trigger_request_service_spec.rb @@ -6,7 +6,7 @@ describe Ci::CreateTriggerRequestService, services: true do let(:trigger) { create(:ci_trigger, project: project) } before do - stub_ci_commit_to_return_yaml_file + stub_ci_pipeline_to_return_yaml_file end describe :execute do @@ -27,8 +27,8 @@ describe Ci::CreateTriggerRequestService, services: true do subject { service.execute(project, trigger, 'master') } before do - stub_ci_commit_yaml_file('{}') - FactoryGirl.create :ci_commit, project: project + stub_ci_pipeline_yaml_file('{}') + FactoryGirl.create :ci_pipeline, project: project end it { expect(subject).to be_nil } diff --git a/spec/services/ci/image_for_build_service_spec.rb b/spec/services/ci/image_for_build_service_spec.rb index 4cc4b3870d1..476a888e394 100644 --- a/spec/services/ci/image_for_build_service_spec.rb +++ b/spec/services/ci/image_for_build_service_spec.rb @@ -5,8 +5,8 @@ module Ci let(:service) { ImageForBuildService.new } let(:project) { FactoryGirl.create(:empty_project) } let(:commit_sha) { '01234567890123456789' } - let(:commit) { project.ensure_ci_commit(commit_sha, 'master') } - let(:build) { FactoryGirl.create(:ci_build, commit: commit) } + let(:commit) { project.ensure_pipeline(commit_sha, 'master') } + let(:build) { FactoryGirl.create(:ci_build, pipeline: commit) } describe :execute do before { build } diff --git a/spec/services/ci/register_build_service_spec.rb b/spec/services/ci/register_build_service_spec.rb index e81f9e757ac..d91fc574299 100644 --- a/spec/services/ci/register_build_service_spec.rb +++ b/spec/services/ci/register_build_service_spec.rb @@ -4,8 +4,8 @@ module Ci describe RegisterBuildService, services: true do let!(:service) { RegisterBuildService.new } let!(:project) { FactoryGirl.create :empty_project, shared_runners_enabled: false } - let!(:commit) { FactoryGirl.create :ci_commit, project: project } - let!(:pending_build) { FactoryGirl.create :ci_build, commit: commit } + let!(:pipeline) { FactoryGirl.create :ci_pipeline, project: project } + let!(:pending_build) { FactoryGirl.create :ci_build, pipeline: pipeline } let!(:shared_runner) { FactoryGirl.create(:ci_runner, is_shared: true) } let!(:specific_runner) { FactoryGirl.create(:ci_runner, is_shared: false) } diff --git a/spec/services/create_commit_builds_service_spec.rb b/spec/services/create_commit_builds_service_spec.rb index e3202c959d9..08cbc9beb5c 100644 --- a/spec/services/create_commit_builds_service_spec.rb +++ b/spec/services/create_commit_builds_service_spec.rb @@ -6,12 +6,12 @@ describe CreateCommitBuildsService, services: true do let(:user) { nil } before do - stub_ci_commit_to_return_yaml_file + stub_ci_pipeline_to_return_yaml_file end describe :execute do context 'valid params' do - let(:commit) do + let(:pipeline) do service.execute(project, user, ref: 'refs/heads/master', before: '00000000', @@ -20,11 +20,11 @@ describe CreateCommitBuildsService, services: true do ) end - it { expect(commit).to be_kind_of(Ci::Commit) } - it { expect(commit).to be_valid } - it { expect(commit).to be_persisted } - it { expect(commit).to eq(project.ci_commits.last) } - it { expect(commit.builds.first).to be_kind_of(Ci::Build) } + it { expect(pipeline).to be_kind_of(Ci::Pipeline) } + it { expect(pipeline).to be_valid } + it { expect(pipeline).to be_persisted } + it { expect(pipeline).to eq(project.pipelines.last) } + it { expect(pipeline.builds.first).to be_kind_of(Ci::Build) } end context "skip tag if there is no build for it" do @@ -39,8 +39,8 @@ describe CreateCommitBuildsService, services: true do end it "creates commit if there is no appropriate job but deploy job has right ref setting" do - config = YAML.dump({ deploy: { deploy: "ls", only: ["0_1"] } }) - stub_ci_commit_yaml_file(config) + config = YAML.dump({ deploy: { script: "ls", only: ["0_1"] } }) + stub_ci_pipeline_yaml_file(config) result = service.execute(project, user, ref: 'refs/heads/0_1', @@ -52,8 +52,8 @@ describe CreateCommitBuildsService, services: true do end end - it 'skips creating ci_commit for refs without .gitlab-ci.yml' do - stub_ci_commit_yaml_file(nil) + it 'skips creating pipeline for refs without .gitlab-ci.yml' do + stub_ci_pipeline_yaml_file(nil) result = service.execute(project, user, ref: 'refs/heads/0_1', before: '00000000', @@ -61,121 +61,121 @@ describe CreateCommitBuildsService, services: true do commits: [{ message: 'Message' }] ) expect(result).not_to be_persisted - expect(Ci::Commit.count).to eq(0) + expect(Ci::Pipeline.count).to eq(0) end it 'fails commits if yaml is invalid' do message = 'message' - allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message } - stub_ci_commit_yaml_file('invalid: file: file') + allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { message } + stub_ci_pipeline_yaml_file('invalid: file: file') commits = [{ message: message }] - commit = service.execute(project, user, - ref: 'refs/tags/0_1', - before: '00000000', - after: '31das312', - commits: commits - ) - expect(commit).to be_persisted - expect(commit.builds.any?).to be false - expect(commit.status).to eq('failed') - expect(commit.yaml_errors).not_to be_nil + pipeline = service.execute(project, user, + ref: 'refs/tags/0_1', + before: '00000000', + after: '31das312', + commits: commits + ) + expect(pipeline).to be_persisted + expect(pipeline.builds.any?).to be false + expect(pipeline.status).to eq('failed') + expect(pipeline.yaml_errors).not_to be_nil end context 'when commit contains a [ci skip] directive' do let(:message) { "some message[ci skip]" } before do - allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message } + allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { message } end it "skips builds creation if there is [ci skip] tag in commit message" do commits = [{ message: message }] - commit = service.execute(project, user, - ref: 'refs/tags/0_1', - before: '00000000', - after: '31das312', - commits: commits - ) - expect(commit).to be_persisted - expect(commit.builds.any?).to be false - expect(commit.status).to eq("skipped") + pipeline = service.execute(project, user, + ref: 'refs/tags/0_1', + before: '00000000', + after: '31das312', + commits: commits + ) + expect(pipeline).to be_persisted + expect(pipeline.builds.any?).to be false + expect(pipeline.status).to eq("skipped") end it "does not skips builds creation if there is no [ci skip] tag in commit message" do - allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { "some message" } + allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { "some message" } commits = [{ message: "some message" }] - commit = service.execute(project, user, - ref: 'refs/tags/0_1', - before: '00000000', - after: '31das312', - commits: commits - ) - - expect(commit).to be_persisted - expect(commit.builds.first.name).to eq("staging") + pipeline = service.execute(project, user, + ref: 'refs/tags/0_1', + before: '00000000', + after: '31das312', + commits: commits + ) + + expect(pipeline).to be_persisted + expect(pipeline.builds.first.name).to eq("staging") end it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do - stub_ci_commit_yaml_file('invalid: file: fiile') + stub_ci_pipeline_yaml_file('invalid: file: fiile') commits = [{ message: message }] - commit = service.execute(project, user, - ref: 'refs/tags/0_1', - before: '00000000', - after: '31das312', - commits: commits - ) - expect(commit).to be_persisted - expect(commit.builds.any?).to be false - expect(commit.status).to eq("skipped") - expect(commit.yaml_errors).to be_nil + pipeline = service.execute(project, user, + ref: 'refs/tags/0_1', + before: '00000000', + after: '31das312', + commits: commits + ) + expect(pipeline).to be_persisted + expect(pipeline.builds.any?).to be false + expect(pipeline.status).to eq("skipped") + expect(pipeline.yaml_errors).to be_nil end end it "skips build creation if there are already builds" do - allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { gitlab_ci_yaml } + allow_any_instance_of(Ci::Pipeline).to receive(:ci_yaml_file) { gitlab_ci_yaml } commits = [{ message: "message" }] - commit = service.execute(project, user, - ref: 'refs/heads/master', - before: '00000000', - after: '31das312', - commits: commits - ) - expect(commit).to be_persisted - expect(commit.builds.count(:all)).to eq(2) + pipeline = service.execute(project, user, + ref: 'refs/heads/master', + before: '00000000', + after: '31das312', + commits: commits + ) + expect(pipeline).to be_persisted + expect(pipeline.builds.count(:all)).to eq(2) - commit = service.execute(project, user, - ref: 'refs/heads/master', - before: '00000000', - after: '31das312', - commits: commits - ) - expect(commit).to be_persisted - expect(commit.builds.count(:all)).to eq(2) + pipeline = service.execute(project, user, + ref: 'refs/heads/master', + before: '00000000', + after: '31das312', + commits: commits + ) + expect(pipeline).to be_persisted + expect(pipeline.builds.count(:all)).to eq(2) end it "creates commit with failed status if yaml is invalid" do - stub_ci_commit_yaml_file('invalid: file') + stub_ci_pipeline_yaml_file('invalid: file') commits = [{ message: "some message" }] - commit = service.execute(project, user, - ref: 'refs/tags/0_1', - before: '00000000', - after: '31das312', - commits: commits - ) + pipeline = service.execute(project, user, + ref: 'refs/tags/0_1', + before: '00000000', + after: '31das312', + commits: commits + ) - expect(commit).to be_persisted - expect(commit.status).to eq("failed") - expect(commit.builds.any?).to be false + expect(pipeline).to be_persisted + expect(pipeline.status).to eq("failed") + expect(pipeline.builds.any?).to be false end context 'when there are no jobs for this pipeline' do before do config = YAML.dump({ test: { script: 'ls', only: ['feature'] } }) - stub_ci_commit_yaml_file(config) + stub_ci_pipeline_yaml_file(config) end it 'does not create a new pipeline' do @@ -186,7 +186,7 @@ describe CreateCommitBuildsService, services: true do commits: [{ message: 'some msg' }]) expect(result).not_to be_persisted expect(Ci::Build.all).to be_empty - expect(Ci::Commit.count).to eq(0) + expect(Ci::Pipeline.count).to eq(0) end end end diff --git a/spec/services/issues/bulk_update_service_spec.rb b/spec/services/issues/bulk_update_service_spec.rb index 96f050bbd9b..4a689e64dc5 100644 --- a/spec/services/issues/bulk_update_service_spec.rb +++ b/spec/services/issues/bulk_update_service_spec.rb @@ -1,114 +1,265 @@ require 'spec_helper' describe Issues::BulkUpdateService, services: true do - let(:issue) { create(:issue, project: @project) } - - before do - @user = create :user - opts = { - name: "GitLab", - namespace: @user.namespace - } - @project = Projects::CreateService.new(@user, opts).execute - end + let(:user) { create(:user) } + let(:project) { Projects::CreateService.new(user, namespace: user.namespace, name: 'test').execute } - describe :close_issue do + let!(:result) { Issues::BulkUpdateService.new(project, user, params).execute } - before do - @issues = create_list(:issue, 5, project: @project) - @params = { + describe :close_issue do + let(:issues) { create_list(:issue, 5, project: project) } + let(:params) do + { state_event: 'close', - issues_ids: @issues.map(&:id) + issues_ids: issues.map(&:id).join(',') } end - it do - result = Issues::BulkUpdateService.new(@project, @user, @params).execute + it 'succeeds and returns the correct number of issues updated' do expect(result[:success]).to be_truthy - expect(result[:count]).to eq(@issues.count) - - expect(@project.issues.opened).to be_empty - expect(@project.issues.closed).not_to be_empty + expect(result[:count]).to eq(issues.count) end + it 'closes all the issues passed' do + expect(project.issues.opened).to be_empty + expect(project.issues.closed).not_to be_empty + end end describe :reopen_issues do - before do - @issues = create_list(:closed_issue, 5, project: @project) - @params = { + let(:issues) { create_list(:closed_issue, 5, project: project) } + let(:params) do + { state_event: 'reopen', - issues_ids: @issues.map(&:id) + issues_ids: issues.map(&:id).join(',') } end - it do - result = Issues::BulkUpdateService.new(@project, @user, @params).execute + it 'succeeds and returns the correct number of issues updated' do expect(result[:success]).to be_truthy - expect(result[:count]).to eq(@issues.count) - - expect(@project.issues.closed).to be_empty - expect(@project.issues.opened).not_to be_empty + expect(result[:count]).to eq(issues.count) end + it 'reopens all the issues passed' do + expect(project.issues.closed).to be_empty + expect(project.issues.opened).not_to be_empty + end end - describe :update_assignee do + describe 'updating assignee' do + let(:issue) do + create(:issue, project: project) { |issue| issue.update_attributes(assignee: user) } + end - before do - @new_assignee = create :user - @params = { - issues_ids: [issue.id], - assignee_id: @new_assignee.id + let(:params) do + { + assignee_id: assignee_id, + issues_ids: issue.id.to_s } end - it do - result = Issues::BulkUpdateService.new(@project, @user, @params).execute - expect(result[:success]).to be_truthy - expect(result[:count]).to eq(1) + context 'when the new assignee ID is a valid user' do + let(:new_assignee) { create(:user) } + let(:assignee_id) { new_assignee.id } - expect(@project.issues.first.assignee).to eq(@new_assignee) - end + it 'succeeds' do + expect(result[:success]).to be_truthy + expect(result[:count]).to eq(1) + end - it 'allows mass-unassigning' do - @project.issues.first.update_attribute(:assignee, @new_assignee) - expect(@project.issues.first.assignee).not_to be_nil + it 'updates the assignee to the use ID passed' do + expect(issue.reload.assignee).to eq(new_assignee) + end + end - @params[:assignee_id] = -1 + context 'when the new assignee ID is -1' do + let(:assignee_id) { -1 } - Issues::BulkUpdateService.new(@project, @user, @params).execute - expect(@project.issues.first.assignee).to be_nil + it 'unassigns the issues' do + expect(issue.reload.assignee).to be_nil + end end - it 'does not unassign when assignee_id is not present' do - @project.issues.first.update_attribute(:assignee, @new_assignee) - expect(@project.issues.first.assignee).not_to be_nil + context 'when the new assignee ID is not present' do + let(:assignee_id) { nil } - @params[:assignee_id] = '' - - Issues::BulkUpdateService.new(@project, @user, @params).execute - expect(@project.issues.first.assignee).not_to be_nil + it 'does not unassign' do + expect(issue.reload.assignee).to eq(user) + end end end - describe :update_milestone do + describe 'updating milestones' do + let(:issue) { create(:issue, project: project) } + let(:milestone) { create(:milestone, project: project) } - before do - @milestone = create(:milestone, project: @project) - @params = { - issues_ids: [issue.id], - milestone_id: @milestone.id + let(:params) do + { + issues_ids: issue.id.to_s, + milestone_id: milestone.id } end - it do - result = Issues::BulkUpdateService.new(@project, @user, @params).execute + it 'succeeds' do expect(result[:success]).to be_truthy expect(result[:count]).to eq(1) + end - expect(@project.issues.first.milestone).to eq(@milestone) + it 'updates the issue milestone' do + expect(project.issues.first.milestone).to eq(milestone) end end + describe 'updating labels' do + def create_issue_with_labels(labels) + create(:issue, project: project) { |issue| issue.update_attributes(labels: labels) } + end + + let(:bug) { create(:label, project: project) } + let(:regression) { create(:label, project: project) } + let(:merge_requests) { create(:label, project: project) } + + let(:issue_all_labels) { create_issue_with_labels([bug, regression, merge_requests]) } + let(:issue_bug_and_regression) { create_issue_with_labels([bug, regression]) } + let(:issue_bug_and_merge_requests) { create_issue_with_labels([bug, merge_requests]) } + let(:issue_no_labels) { create(:issue, project: project) } + let(:issues) { [issue_all_labels, issue_bug_and_regression, issue_bug_and_merge_requests, issue_no_labels] } + + let(:labels) { [] } + let(:add_labels) { [] } + let(:remove_labels) { [] } + + let(:params) do + { + label_ids: labels.map(&:id), + add_label_ids: add_labels.map(&:id), + remove_label_ids: remove_labels.map(&:id), + issues_ids: issues.map(&:id).join(',') + } + end + + context 'when label_ids are passed' do + let(:issues) { [issue_all_labels, issue_no_labels] } + let(:labels) { [bug, regression] } + + it 'updates the labels of all issues passed to the labels passed' do + expect(issues.map(&:reload).map(&:label_ids)).to all(eq(labels.map(&:id))) + end + + it 'does not update issues not passed in' do + expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id) + end + + context 'when those label IDs are empty' do + let(:labels) { [] } + + it 'updates the issues passed to have no labels' do + expect(issues.map(&:reload).map(&:label_ids)).to all(be_empty) + end + end + end + + context 'when add_label_ids are passed' do + let(:issues) { [issue_all_labels, issue_bug_and_merge_requests, issue_no_labels] } + let(:add_labels) { [bug, regression, merge_requests] } + + it 'adds those label IDs to all issues passed' do + expect(issues.map(&:reload).map(&:label_ids)).to all(include(*add_labels.map(&:id))) + end + + it 'does not update issues not passed in' do + expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id) + end + end + + context 'when remove_label_ids are passed' do + let(:issues) { [issue_all_labels, issue_bug_and_merge_requests, issue_no_labels] } + let(:remove_labels) { [bug, regression, merge_requests] } + + it 'removes those label IDs from all issues passed' do + expect(issues.map(&:reload).map(&:label_ids)).to all(be_empty) + end + + it 'does not update issues not passed in' do + expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id) + end + end + + context 'when add_label_ids and remove_label_ids are passed' do + let(:issues) { [issue_all_labels, issue_bug_and_merge_requests, issue_no_labels] } + let(:add_labels) { [bug] } + let(:remove_labels) { [merge_requests] } + + it 'adds the label IDs to all issues passed' do + expect(issues.map(&:reload).map(&:label_ids)).to all(include(bug.id)) + end + + it 'removes the label IDs from all issues passed' do + expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id) + end + + it 'does not update issues not passed in' do + expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id) + end + end + + context 'when add_label_ids and label_ids are passed' do + let(:issues) { [issue_all_labels, issue_bug_and_regression, issue_bug_and_merge_requests] } + let(:labels) { [merge_requests] } + let(:add_labels) { [regression] } + + it 'adds the label IDs to all issues passed' do + expect(issues.map(&:reload).map(&:label_ids)).to all(include(regression.id)) + end + + it 'ignores the label IDs parameter' do + expect(issues.map(&:reload).map(&:label_ids)).to all(include(bug.id)) + end + + it 'does not update issues not passed in' do + expect(issue_no_labels.label_ids).to be_empty + end + end + + context 'when remove_label_ids and label_ids are passed' do + let(:issues) { [issue_no_labels, issue_bug_and_regression] } + let(:labels) { [merge_requests] } + let(:remove_labels) { [regression] } + + it 'remove the label IDs from all issues passed' do + expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(regression.id) + end + + it 'ignores the label IDs parameter' do + expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id) + end + + it 'does not update issues not passed in' do + expect(issue_all_labels.label_ids).to contain_exactly(bug.id, regression.id, merge_requests.id) + end + end + + context 'when add_label_ids, remove_label_ids, and label_ids are passed' do + let(:issues) { [issue_bug_and_merge_requests, issue_no_labels] } + let(:labels) { [regression] } + let(:add_labels) { [bug] } + let(:remove_labels) { [merge_requests] } + + it 'adds the label IDs to all issues passed' do + expect(issues.map(&:reload).map(&:label_ids)).to all(include(bug.id)) + end + + it 'removes the label IDs from all issues passed' do + expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id) + end + + it 'ignores the label IDs parameter' do + expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(regression.id) + end + + it 'does not update issues not passed in' do + expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id) + end + end + end end diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb index 95fe6c2400a..93bf0f64963 100644 --- a/spec/services/issues/move_service_spec.rb +++ b/spec/services/issues/move_service_spec.rb @@ -39,6 +39,7 @@ describe Issues::MoveService, services: true do let!(:milestone2) do create(:milestone, project_id: new_project.id, title: 'v9.0') end + let!(:award_emoji) { create(:award_emoji, awardable: old_issue) } let!(:new_issue) { move_service.execute(old_issue, new_project) } end @@ -115,6 +116,10 @@ describe Issues::MoveService, services: true do it 'preserves create time' do expect(old_issue.created_at).to eq new_issue.created_at end + + it 'moves the award emoji' do + expect(old_issue.award_emoji.first.name).to eq new_issue.reload.award_emoji.first.name + end end context 'issue with notes' do diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index be19be17151..dacbcd8fb46 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -1,3 +1,4 @@ +# coding: utf-8 require 'spec_helper' describe Issues::UpdateService, services: true do @@ -273,5 +274,50 @@ describe Issues::UpdateService, services: true do end end end + + context 'updating labels' do + let(:label3) { create(:label, project: project) } + let(:result) { Issues::UpdateService.new(project, user, params).execute(issue).reload } + + context 'when add_label_ids and label_ids are passed' do + let(:params) { { label_ids: [label.id], add_label_ids: [label3.id] } } + + it 'ignores the label_ids parameter' do + expect(result.label_ids).not_to include(label.id) + end + + it 'adds the passed labels' do + expect(result.label_ids).to include(label3.id) + end + end + + context 'when remove_label_ids and label_ids are passed' do + let(:params) { { label_ids: [], remove_label_ids: [label.id] } } + + before { issue.update_attributes(labels: [label, label3]) } + + it 'ignores the label_ids parameter' do + expect(result.label_ids).not_to be_empty + end + + it 'removes the passed labels' do + expect(result.label_ids).not_to include(label.id) + end + end + + context 'when add_label_ids and remove_label_ids are passed' do + let(:params) { { add_label_ids: [label3.id], remove_label_ids: [label.id] } } + + before { issue.update_attributes(labels: [label]) } + + it 'adds the passed labels' do + expect(result.label_ids).to include(label3.id) + end + + it 'removes the passed labels' do + expect(result.label_ids).not_to include(label.id) + end + end + end end end diff --git a/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb b/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb index f70716c9d19..dd656c3bbb7 100644 --- a/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb +++ b/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb @@ -6,7 +6,7 @@ describe MergeRequests::AddTodoWhenBuildFailsService do let(:merge_request) { create(:merge_request) } let(:project) { create(:project) } let(:sha) { '1234567890abcdef1234567890abcdef12345678' } - let(:ci_commit) { create(:ci_commit_with_one_job, ref: merge_request.source_branch, project: project, sha: sha) } + let(:pipeline) { create(:ci_pipeline_with_one_job, ref: merge_request.source_branch, project: project, sha: sha) } let(:service) { MergeRequests::AddTodoWhenBuildFailsService.new(project, user, commit_message: 'Awesome message') } let(:todo_service) { TodoService.new } @@ -17,13 +17,13 @@ describe MergeRequests::AddTodoWhenBuildFailsService do end before do - allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_return(ci_commit) + allow_any_instance_of(MergeRequest).to receive(:pipeline).and_return(pipeline) allow(service).to receive(:todo_service).and_return(todo_service) end describe '#execute' do context 'commit status with ref' do - let(:commit_status) { create(:generic_commit_status, ref: merge_request.source_branch, commit: ci_commit) } + let(:commit_status) { create(:generic_commit_status, ref: merge_request.source_branch, pipeline: pipeline) } it 'notifies the todo service' do expect(todo_service).to receive(:merge_request_build_failed).with(merge_request) @@ -52,7 +52,7 @@ describe MergeRequests::AddTodoWhenBuildFailsService do describe '#close' do context 'commit status with ref' do - let(:commit_status) { create(:generic_commit_status, ref: merge_request.source_branch, commit: ci_commit) } + let(:commit_status) { create(:generic_commit_status, ref: merge_request.source_branch, pipeline: pipeline) } it 'notifies the todo service' do expect(todo_service).to receive(:merge_request_build_retried).with(merge_request) diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb index 0861d74aede..4da8146e3d6 100644 --- a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb +++ b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb @@ -10,7 +10,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do source_project: project, target_project: project, state: "opened") end - let(:ci_commit) { create(:ci_commit_with_one_job, ref: mr_merge_if_green_enabled.source_branch, project: project) } + let(:pipeline) { create(:ci_pipeline_with_one_job, ref: mr_merge_if_green_enabled.source_branch, project: project) } let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, commit_message: 'Awesome message') } describe "#execute" do @@ -21,7 +21,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do context 'first time enabling' do before do - allow(merge_request).to receive(:ci_commit).and_return(ci_commit) + allow(merge_request).to receive(:pipeline).and_return(pipeline) service.execute(merge_request) end @@ -43,9 +43,9 @@ describe MergeRequests::MergeWhenBuildSucceedsService do let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch) } before do - allow(mr_merge_if_green_enabled).to receive(:ci_commit).and_return(ci_commit) + allow(mr_merge_if_green_enabled).to receive(:pipeline).and_return(pipeline) allow(mr_merge_if_green_enabled).to receive(:mergeable?).and_return(true) - allow(ci_commit).to receive(:success?).and_return(true) + allow(pipeline).to receive(:success?).and_return(true) end it 'updates the merge params' do @@ -62,8 +62,8 @@ describe MergeRequests::MergeWhenBuildSucceedsService do let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch, status: "success") } it "merges all merge requests with merge when build succeeds enabled" do - allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_return(ci_commit) - allow(ci_commit).to receive(:success?).and_return(true) + allow_any_instance_of(MergeRequest).to receive(:pipeline).and_return(pipeline) + allow(pipeline).to receive(:success?).and_return(true) expect(MergeWorker).to receive(:perform_async) service.trigger(build) @@ -75,8 +75,8 @@ describe MergeRequests::MergeWhenBuildSucceedsService do let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch, status: "success") } it "merges all merge requests with merge when build succeeds enabled" do - allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_return(ci_commit) - allow(ci_commit).to receive(:success?).and_return(true) + allow_any_instance_of(MergeRequest).to receive(:pipeline).and_return(pipeline) + allow(pipeline).to receive(:success?).and_return(true) allow(old_build).to receive(:sha).and_return('1234abcdef') expect(MergeWorker).not_to receive(:perform_async) @@ -99,9 +99,9 @@ describe MergeRequests::MergeWhenBuildSucceedsService do it 'discovers branches and merges all merge requests when status is success' do allow(project.repository).to receive(:branch_names_contains). with(commit_status.sha).and_return([mr_merge_if_green_enabled.source_branch]) - allow(ci_commit).to receive(:success?).and_return(true) - allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_return(ci_commit) - allow(ci_commit).to receive(:success?).and_return(true) + allow(pipeline).to receive(:success?).and_return(true) + allow_any_instance_of(MergeRequest).to receive(:pipeline).and_return(pipeline) + allow(pipeline).to receive(:success?).and_return(true) expect(MergeWorker).to receive(:perform_async) service.trigger(commit_status) @@ -110,17 +110,17 @@ describe MergeRequests::MergeWhenBuildSucceedsService do context 'properly handles multiple stages' do let(:ref) { mr_merge_if_green_enabled.source_branch } - let(:build) { create(:ci_build, commit: ci_commit, ref: ref, name: 'build', stage: 'build') } - let(:test) { create(:ci_build, commit: ci_commit, ref: ref, name: 'test', stage: 'test') } + let(:build) { create(:ci_build, pipeline: pipeline, ref: ref, name: 'build', stage: 'build') } + let(:test) { create(:ci_build, pipeline: pipeline, ref: ref, name: 'test', stage: 'test') } before do # This behavior of MergeRequest: we instantiate a new object - allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_wrap_original do - Ci::Commit.find(ci_commit.id) + allow_any_instance_of(MergeRequest).to receive(:pipeline).and_wrap_original do + Ci::Pipeline.find(pipeline.id) end # We create test after the build - allow(ci_commit).to receive(:create_next_builds).and_wrap_original do + allow(pipeline).to receive(:create_next_builds).and_wrap_original do test end end diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index ff23f13e1cb..35f576874b8 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -14,7 +14,7 @@ describe Notes::CreateService, services: true do noteable_type: 'Issue', noteable_id: issue.id } - + @note = Notes::CreateService.new(project, user, opts).execute end @@ -28,18 +28,16 @@ describe Notes::CreateService, services: true do project.team << [user, :master] end - it "creates emoji note" do + it "creates an award emoji" do opts = { note: ':smile: ', noteable_type: 'Issue', noteable_id: issue.id } + note = Notes::CreateService.new(project, user, opts).execute - @note = Notes::CreateService.new(project, user, opts).execute - - expect(@note).to be_valid - expect(@note.note).to eq('smile') - expect(@note.is_award).to be_truthy + expect(note).to be_valid + expect(note.name).to eq('smile') end it "creates regular note if emoji name is invalid" do @@ -48,12 +46,22 @@ describe Notes::CreateService, services: true do noteable_type: 'Issue', noteable_id: issue.id } + note = Notes::CreateService.new(project, user, opts).execute + + expect(note).to be_valid + expect(note.note).to eq(opts[:note]) + end + + it "normalizes the emoji name" do + opts = { + note: ':+1:', + noteable_type: 'Issue', + noteable_id: issue.id + } - @note = Notes::CreateService.new(project, user, opts).execute + expect_any_instance_of(TodoService).to receive(:new_award_emoji).with(issue, user) - expect(@note).to be_valid - expect(@note.note).to eq(opts[:note]) - expect(@note.is_award).to be_falsy + Notes::CreateService.new(project, user, opts).execute end end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index cef5e0d8659..e871a103d42 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -72,6 +72,7 @@ describe NotificationService, services: true do should_not_email(@u_disabled) should_not_email(@unsubscriber) should_not_email(@u_outsider_mentioned) + should_not_email(@u_lazy_participant) end it 'filters out "mentioned in" notes' do @@ -80,6 +81,20 @@ describe NotificationService, services: true do expect(Notify).not_to receive(:note_issue_email) notification.new_note(mentioned_note) end + + context 'participating' do + context 'by note' do + before do + ActionMailer::Base.deliveries.clear + note.author = @u_lazy_participant + note.save + notification.new_note(note) + end + + + it { should_not_email(@u_lazy_participant) } + end + end end describe 'new note on issue in project that belongs to a group' do @@ -106,6 +121,7 @@ describe NotificationService, services: true do should_not_email(note.author) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) end end end @@ -116,12 +132,14 @@ describe NotificationService, services: true do let(:assignee) { create(:user) } let(:non_member) { create(:user) } 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(: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}") } it 'filters out users that can not read the issue' do project.team << [member, :developer] + project.team << [guest, :guest] expect(SentNotification).to receive(:record).with(confidential_issue, any_args).exactly(4).times @@ -130,6 +148,7 @@ describe NotificationService, services: true do notification.new_note(note) should_not_email(non_member) + should_not_email(guest) should_email(author) should_email(assignee) should_email(member) @@ -235,6 +254,7 @@ describe NotificationService, services: true do should_not_email(note.author) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) end it do @@ -248,10 +268,11 @@ describe NotificationService, services: true do should_not_email(note.author) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) end it do - @u_committer.update_attributes(notification_level: :mention) + @u_committer = create_global_setting_for(@u_committer, :mention) notification.new_note(note) should_not_email(@u_committer) end @@ -280,10 +301,11 @@ describe NotificationService, services: true do should_not_email(@u_mentioned) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) end it do - issue.assignee.update_attributes(notification_level: :mention) + create_global_setting_for(issue.assignee, :mention) notification.new_issue(issue, @u_disabled) should_not_email(issue.assignee) @@ -303,17 +325,20 @@ describe NotificationService, services: true do let(:assignee) { create(:user) } let(:non_member) { create(:user) } 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) } it "emails subscribers of the issue's labels that can read the issue" do project.team << [member, :developer] + project.team << [guest, :guest] label = create(:label, issues: [confidential_issue]) label.toggle_subscription(non_member) label.toggle_subscription(author) label.toggle_subscription(assignee) label.toggle_subscription(member) + label.toggle_subscription(guest) label.toggle_subscription(admin) ActionMailer::Base.deliveries.clear @@ -322,6 +347,7 @@ describe NotificationService, services: true do should_not_email(non_member) should_not_email(author) + should_not_email(guest) should_email(assignee) should_email(member) should_email(admin) @@ -341,6 +367,7 @@ describe NotificationService, services: true do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) end it 'emails previous assignee even if he has the "on mention" notif level' do @@ -356,6 +383,7 @@ describe NotificationService, services: true do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) end it 'emails new assignee even if he has the "on mention" notif level' do @@ -371,6 +399,7 @@ describe NotificationService, services: true do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) end it 'emails new assignee' do @@ -386,6 +415,7 @@ describe NotificationService, services: true do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) end it 'does not email new assignee if they are the current user' do @@ -401,6 +431,35 @@ describe NotificationService, services: true do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) + end + + context 'participating' do + context 'by assignee' do + before do + issue.update_attribute(:assignee, @u_lazy_participant) + notification.reassigned_issue(issue, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end + + context 'by note' do + let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) } + + before { notification.reassigned_issue(issue, @u_disabled) } + + it { should_email(@u_lazy_participant) } + end + + context 'by author' do + before do + issue.author = @u_lazy_participant + notification.reassigned_issue(issue, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end end end @@ -438,6 +497,7 @@ describe NotificationService, services: true do let(:assignee) { create(:user) } let(:non_member) { create(:user) } 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!(:label_1) { create(:label, issues: [confidential_issue]) } @@ -445,11 +505,13 @@ describe NotificationService, services: true do it "emails subscribers of the issue's labels that can read the issue" do project.team << [member, :developer] + project.team << [guest, :guest] label_2.toggle_subscription(non_member) label_2.toggle_subscription(author) label_2.toggle_subscription(assignee) label_2.toggle_subscription(member) + label_2.toggle_subscription(guest) label_2.toggle_subscription(admin) ActionMailer::Base.deliveries.clear @@ -457,6 +519,7 @@ describe NotificationService, services: true do notification.relabeled_issue(confidential_issue, [label_2], @u_disabled) should_not_email(non_member) + should_not_email(guest) should_email(author) should_email(assignee) should_email(member) @@ -479,6 +542,35 @@ describe NotificationService, services: true do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) + end + + context 'participating' do + context 'by assignee' do + before do + issue.update_attribute(:assignee, @u_lazy_participant) + notification.close_issue(issue, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end + + context 'by note' do + let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) } + + before { notification.close_issue(issue, @u_disabled) } + + it { should_email(@u_lazy_participant) } + end + + context 'by author' do + before do + issue.author = @u_lazy_participant + notification.close_issue(issue, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end end end @@ -495,6 +587,35 @@ describe NotificationService, services: true do should_email(@watcher_and_subscriber) should_not_email(@unsubscriber) should_not_email(@u_participating) + should_not_email(@u_lazy_participant) + end + + context 'participating' do + context 'by assignee' do + before do + issue.update_attribute(:assignee, @u_lazy_participant) + notification.reopen_issue(issue, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end + + context 'by note' do + let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) } + + before { notification.reopen_issue(issue, @u_disabled) } + + it { should_email(@u_lazy_participant) } + end + + context 'by author' do + before do + issue.author = @u_lazy_participant + notification.reopen_issue(issue, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end end end end @@ -520,6 +641,7 @@ describe NotificationService, services: true do should_email(@u_guest_watcher) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) end it "emails subscribers of the merge request's labels" do @@ -530,6 +652,36 @@ describe NotificationService, services: true do should_email(subscriber) end + + + context 'participating' do + context 'by assignee' do + before do + merge_request.update_attribute(:assignee, @u_lazy_participant) + notification.new_merge_request(merge_request, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end + + context 'by note' do + let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } + + before { notification.new_merge_request(merge_request, @u_disabled) } + + it { should_email(@u_lazy_participant) } + end + + context 'by author' do + before do + merge_request.author = @u_lazy_participant + merge_request.save + notification.new_merge_request(merge_request, @u_disabled) + end + + it { should_not_email(@u_lazy_participant) } + end + end end describe '#reassigned_merge_request' do @@ -545,6 +697,36 @@ describe NotificationService, services: true do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) + end + + context 'participating' do + context 'by assignee' do + before do + merge_request.update_attribute(:assignee, @u_lazy_participant) + notification.reassigned_merge_request(merge_request, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end + + context 'by note' do + let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } + + before { notification.reassigned_merge_request(merge_request, @u_disabled) } + + it { should_email(@u_lazy_participant) } + end + + context 'by author' do + before do + merge_request.author = @u_lazy_participant + merge_request.save + notification.reassigned_merge_request(merge_request, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end end end @@ -572,6 +754,7 @@ describe NotificationService, services: true do should_not_email(@watcher_and_subscriber) should_not_email(@unsubscriber) should_not_email(@u_participating) + should_not_email(@u_lazy_participant) should_not_email(subscriber_to_label) should_email(subscriber_to_label2) end @@ -590,6 +773,36 @@ describe NotificationService, services: true do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) + end + + context 'participating' do + context 'by assignee' do + before do + merge_request.update_attribute(:assignee, @u_lazy_participant) + notification.close_mr(merge_request, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end + + context 'by note' do + let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } + + before { notification.close_mr(merge_request, @u_disabled) } + + it { should_email(@u_lazy_participant) } + end + + context 'by author' do + before do + merge_request.author = @u_lazy_participant + merge_request.save + notification.close_mr(merge_request, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end end end @@ -606,6 +819,36 @@ describe NotificationService, services: true do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) + end + + context 'participating' do + context 'by assignee' do + before do + merge_request.update_attribute(:assignee, @u_lazy_participant) + notification.merge_mr(merge_request, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end + + context 'by note' do + let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } + + before { notification.merge_mr(merge_request, @u_disabled) } + + it { should_email(@u_lazy_participant) } + end + + context 'by author' do + before do + merge_request.author = @u_lazy_participant + merge_request.save + notification.merge_mr(merge_request, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end end end @@ -622,6 +865,36 @@ describe NotificationService, services: true do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) + end + + context 'participating' do + context 'by assignee' do + before do + merge_request.update_attribute(:assignee, @u_lazy_participant) + notification.reopen_mr(merge_request, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end + + context 'by note' do + let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } + + before { notification.reopen_mr(merge_request, @u_disabled) } + + it { should_email(@u_lazy_participant) } + end + + context 'by author' do + before do + merge_request.author = @u_lazy_participant + merge_request.save + notification.reopen_mr(merge_request, @u_disabled) + end + + it { should_email(@u_lazy_participant) } + end end end end @@ -640,6 +913,7 @@ describe NotificationService, services: true do should_email(@u_watcher) should_email(@u_participating) + should_email(@u_lazy_participant) should_not_email(@u_guest_watcher) should_not_email(@u_disabled) end @@ -647,14 +921,19 @@ describe NotificationService, services: true do end def build_team(project) - @u_watcher = create(:user, notification_level: :watch) - @u_participating = create(:user, notification_level: :participating) - @u_participant_mentioned = create(:user, username: 'participant', notification_level: :participating) - @u_disabled = create(:user, notification_level: :disabled) - @u_mentioned = create(:user, username: 'mention', notification_level: :mention) - @u_committer = create(:user, username: 'committer') - @u_not_mentioned = create(:user, username: 'regular', notification_level: :participating) - @u_outsider_mentioned = create(:user, username: 'outsider') + @u_watcher = create_global_setting_for(create(:user), :watch) + @u_participating = create_global_setting_for(create(:user), :participating) + @u_participant_mentioned = create_global_setting_for(create(:user, username: 'participant'), :participating) + @u_disabled = create_global_setting_for(create(:user), :disabled) + @u_mentioned = create_global_setting_for(create(:user, username: 'mention'), :mention) + @u_committer = create(:user, username: 'committer') + @u_not_mentioned = create_global_setting_for(create(:user, username: 'regular'), :participating) + @u_outsider_mentioned = create(:user, username: 'outsider') + + # User to be participant by default + # This user does not contain any record in notification settings table + # It should be treated with a :participating notification_level + @u_lazy_participant = create(:user, username: 'lazy-participant') create_guest_watcher @@ -665,6 +944,15 @@ describe NotificationService, services: true do project.team << [@u_mentioned, :master] project.team << [@u_committer, :master] project.team << [@u_not_mentioned, :master] + project.team << [@u_lazy_participant, :master] + end + + def create_global_setting_for(user, level) + setting = user.global_notification_setting + setting.level = level + setting.save + + user end def create_guest_watcher @@ -677,8 +965,8 @@ describe NotificationService, services: true do def add_users_with_subscription(project, issuable) @subscriber = create :user @unsubscriber = create :user - @subscribed_participant = create(:user, username: 'subscribed_participant', notification_level: :participating) - @watcher_and_subscriber = create(:user, notification_level: :watch) + @subscribed_participant = create_global_setting_for(create(:user, username: 'subscribed_participant'), :participating) + @watcher_and_subscriber = create_global_setting_for(create(:user), :watch) project.team << [@subscribed_participant, :master] project.team << [@subscriber, :master] diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb index 6108c26a78b..0971fec2e9f 100644 --- a/spec/services/projects/autocomplete_service_spec.rb +++ b/spec/services/projects/autocomplete_service_spec.rb @@ -33,6 +33,18 @@ describe Projects::AutocompleteService, services: true do expect(issues.count).to eq 1 end + it 'should not list project confidential issues for project members with guest role' do + project.team << [member, :guest] + + autocomplete = described_class.new(project, non_member) + issues = autocomplete.issues.map(&:iid) + + expect(issues).to include issue.iid + expect(issues).not_to include security_issue_1.iid + expect(issues).not_to include security_issue_2.iid + expect(issues.count).to eq 1 + end + it 'should list project confidential issues for author' do autocomplete = described_class.new(project, author) issues = autocomplete.issues.map(&:iid) diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb index 9d90bfceb73..068c9a1219c 100644 --- a/spec/services/projects/import_service_spec.rb +++ b/spec/services/projects/import_service_spec.rb @@ -124,7 +124,7 @@ describe Projects::ImportService, services: true do } ) - Gitlab.config.omniauth.providers << provider + allow(Gitlab.config.omniauth).to receive(:providers).and_return([provider]) end end end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 29e0a63d8ce..09f0ee3871d 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -208,7 +208,7 @@ describe SystemNoteService, services: true do end describe '.merge_when_build_succeeds' do - let(:ci_commit) { build(:ci_commit_without_jobs )} + let(:pipeline) { build(:ci_pipeline_without_jobs )} let(:noteable) do create(:merge_request, source_project: project, target_project: project) end @@ -223,7 +223,6 @@ describe SystemNoteService, services: true do end describe '.cancel_merge_when_build_succeeds' do - let(:ci_commit) { build(:ci_commit_without_jobs) } let(:noteable) do create(:merge_request, source_project: project, target_project: project) end diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index 42147736532..549a936b060 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -5,20 +5,22 @@ describe TodoService, services: true do let(:assignee) { create(:user) } let(:non_member) { create(:user) } let(:member) { create(:user) } + let(:guest) { create(:user) } let(:admin) { create(:admin) } let(:john_doe) { create(:user) } let(:project) { create(:project) } - let(:mentions) { [author, assignee, john_doe, member, non_member, admin].map(&:to_reference).join(' ') } + let(:mentions) { [author, assignee, john_doe, member, guest, non_member, admin].map(&:to_reference).join(' ') } let(:service) { described_class.new } before do + project.team << [guest, :guest] project.team << [author, :developer] project.team << [member, :developer] project.team << [john_doe, :developer] end describe 'Issues' do - let(:issue) { create(:issue, project: project, assignee: john_doe, author: author, description: mentions) } + let(:issue) { create(:issue, project: project, assignee: john_doe, author: author, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") } let(:unassigned_issue) { create(:issue, project: project, assignee: nil) } let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee, description: mentions) } @@ -41,18 +43,20 @@ describe TodoService, services: true do service.new_issue(issue, author) should_create_todo(user: member, target: issue, action: Todo::MENTIONED) + should_create_todo(user: guest, target: issue, action: Todo::MENTIONED) should_not_create_todo(user: author, target: issue, action: Todo::MENTIONED) should_not_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED) end - it 'does not create todo for non project members when issue is confidential' do + it 'does not create todo if user can not see the issue when issue is confidential' do service.new_issue(confidential_issue, john_doe) should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::ASSIGNED) should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) + should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) end @@ -81,6 +85,7 @@ describe TodoService, services: true do service.update_issue(issue, author) should_create_todo(user: member, target: issue, action: Todo::MENTIONED) + should_create_todo(user: guest, target: issue, action: Todo::MENTIONED) should_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED) should_not_create_todo(user: author, target: issue, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED) @@ -92,15 +97,29 @@ describe TodoService, services: true do expect { service.update_issue(issue, author) }.not_to change(member.todos, :count) end - it 'does not create todo for non project members when issue is confidential' do + it 'does not create todo if user can not see the issue when issue is confidential' do service.update_issue(confidential_issue, john_doe) should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) + should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED) end + + it 'does not create todo when when tasks are marked as completed' do + issue.update(description: "- [x] Task 1\n- [X] Task 2 #{mentions}") + + service.update_issue(issue, author) + + should_not_create_todo(user: admin, target: issue, action: Todo::MENTIONED) + should_not_create_todo(user: assignee, target: issue, action: Todo::MENTIONED) + should_not_create_todo(user: author, target: issue, action: Todo::MENTIONED) + should_not_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED) + should_not_create_todo(user: member, target: issue, action: Todo::MENTIONED) + should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED) + end end describe '#close_issue' do @@ -156,7 +175,6 @@ describe TodoService, services: true do let(:note_on_commit) { create(:note_on_commit, project: project, author: john_doe, note: mentions) } let(:note_on_confidential_issue) { create(:note_on_issue, noteable: confidential_issue, project: project, note: mentions) } let(:note_on_project_snippet) { create(:note_on_project_snippet, project: project, author: john_doe, note: mentions) } - let(:award_note) { create(:note, :award, project: project, noteable: issue, author: john_doe, note: 'thumbsup') } let(:system_note) { create(:system_note, project: project, noteable: issue) } it 'mark related pending todos to the noteable for the note author as done' do @@ -169,13 +187,6 @@ describe TodoService, services: true do expect(second_todo.reload).to be_done end - it 'mark related pending todos to the noteable for the award note author as done' do - service.new_note(award_note, john_doe) - - expect(first_todo.reload).to be_done - expect(second_todo.reload).to be_done - end - it 'does not mark related pending todos it is a system note' do service.new_note(system_note, john_doe) @@ -187,18 +198,20 @@ describe TodoService, services: true do service.new_note(note, john_doe) should_create_todo(user: member, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) + should_create_todo(user: guest, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) should_create_todo(user: author, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) should_not_create_todo(user: john_doe, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) should_not_create_todo(user: non_member, target: issue, author: john_doe, action: Todo::MENTIONED, note: note) end - it 'does not create todo for non project members when leaving a note on a confidential issue' do + it 'does not create todo if user can not see the issue when leaving a note on a confidential issue' do service.new_note(note_on_confidential_issue, john_doe) should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) + should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue) end @@ -218,7 +231,7 @@ describe TodoService, services: true do end describe 'Merge Requests' do - let(:mr_assigned) { create(:merge_request, source_project: project, author: author, assignee: john_doe, description: mentions) } + let(:mr_assigned) { create(:merge_request, source_project: project, author: author, assignee: john_doe, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") } let(:mr_unassigned) { create(:merge_request, source_project: project, author: author, assignee: nil) } describe '#new_merge_request' do @@ -240,6 +253,7 @@ describe TodoService, services: true do service.new_merge_request(mr_assigned, author) should_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED) + should_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED) @@ -251,6 +265,7 @@ describe TodoService, services: true do service.update_merge_request(mr_assigned, author) should_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED) + should_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED) should_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED) should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED) @@ -261,6 +276,19 @@ describe TodoService, services: true do expect { service.update_merge_request(mr_assigned, author) }.not_to change(member.todos, :count) end + + it 'does not create todo when when tasks are marked as completed' do + mr_assigned.update(description: "- [x] Task 1\n- [X] Task 2 #{mentions}") + + service.update_merge_request(mr_assigned, author) + + should_not_create_todo(user: admin, target: mr_assigned, action: Todo::MENTIONED) + should_not_create_todo(user: assignee, target: mr_assigned, action: Todo::MENTIONED) + should_not_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED) + should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED) + should_not_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED) + should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED) + end end describe '#close_merge_request' do @@ -306,6 +334,15 @@ describe TodoService, services: true do end end + describe '#new_award_emoji' do + it 'marks related pending todos to the target for the user as done' do + todo = create(:todo, user: john_doe, project: project, target: mr_assigned, author: author) + service.new_award_emoji(mr_assigned, john_doe) + + expect(todo.reload).to be_done + end + end + describe '#merge_request_build_failed' do it 'creates a pending todo for the merge request author' do service.merge_request_build_failed(mr_unassigned) |