diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-26 00:06:28 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-26 00:06:28 +0000 |
commit | 9615736987b94a783845354ba881008e49d39238 (patch) | |
tree | 0620a1d06e44df92fa936b7a86e57d282f690181 | |
parent | eb7390edf3afd52174b786fff1e06d5ffae0cec5 (diff) | |
download | gitlab-ce-9615736987b94a783845354ba881008e49d39238.tar.gz |
Add latest changes from gitlab-org/gitlab@master
-rw-r--r-- | app/controllers/admin/jobs_controller.rb | 20 | ||||
-rw-r--r-- | app/controllers/projects/jobs_controller.rb | 29 | ||||
-rw-r--r-- | app/finders/jobs_finder.rb | 51 | ||||
-rw-r--r-- | app/models/ci/build.rb | 15 | ||||
-rw-r--r-- | app/models/ci/pipeline.rb | 12 | ||||
-rw-r--r-- | changelogs/unreleased/35616-broken-anchor-for-learn-more-about-interacting-with-security-report.yml | 5 | ||||
-rw-r--r-- | doc/development/build_test_package.md | 6 | ||||
-rw-r--r-- | doc/development/img/build_package_v12_6.png | bin | 0 -> 124510 bytes | |||
-rw-r--r-- | doc/development/img/trigger_build_package_v12_6.png | bin | 0 -> 141603 bytes | |||
-rw-r--r-- | doc/development/img/trigger_ss1.png | bin | 35756 -> 0 bytes | |||
-rw-r--r-- | doc/development/img/trigger_ss2.png | bin | 36082 -> 0 bytes | |||
-rw-r--r-- | locale/gitlab.pot | 9 | ||||
-rw-r--r-- | spec/finders/jobs_finder_spec.rb | 89 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/markdown/field_spec.js | 179 | ||||
-rw-r--r-- | spec/javascripts/vue_shared/components/markdown/field_spec.js | 173 | ||||
-rw-r--r-- | spec/models/ci/pipeline_spec.rb | 49 |
16 files changed, 361 insertions, 276 deletions
diff --git a/app/controllers/admin/jobs_controller.rb b/app/controllers/admin/jobs_controller.rb index 0c1afdc3d3b..892f6dc657c 100644 --- a/app/controllers/admin/jobs_controller.rb +++ b/app/controllers/admin/jobs_controller.rb @@ -1,25 +1,15 @@ # frozen_string_literal: true class Admin::JobsController < Admin::ApplicationController - # rubocop: disable CodeReuse/ActiveRecord def index + # We need all builds for tabs counters + @all_builds = JobsFinder.new(current_user: current_user).execute + @scope = params[:scope] - @all_builds = Ci::Build - @builds = @all_builds.order('id DESC') - @builds = - case @scope - when 'pending' - @builds.pending.reverse_order - when 'running' - @builds.running.reverse_order - when 'finished' - @builds.finished - else - @builds - end + @builds = JobsFinder.new(current_user: current_user, params: params).execute + @builds = @builds.eager_load_everything @builds = @builds.page(params[:page]).per(30) end - # rubocop: enable CodeReuse/ActiveRecord def cancel_all Ci::Build.running_or_pending.each(&:cancel) diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 1d914ab6011..9480900b57a 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -17,34 +17,15 @@ class Projects::JobsController < Projects::ApplicationController layout 'project' - # rubocop: disable CodeReuse/ActiveRecord def index + # We need all builds for tabs counters + @all_builds = JobsFinder.new(current_user: current_user, project: @project).execute + @scope = params[:scope] - @all_builds = project.builds.relevant - @builds = @all_builds.order('ci_builds.id DESC') - @builds = - case @scope - when 'pending' - @builds.pending.reverse_order - when 'running' - @builds.running.reverse_order - when 'finished' - @builds.finished - else - @builds - end - @builds = @builds.includes([ - { pipeline: [:project, :user] }, - :job_artifacts_archive, - :metadata, - :trigger_request, - :project, - :user, - :tags - ]) + @builds = JobsFinder.new(current_user: current_user, project: @project, params: params).execute + @builds = @builds.eager_load_everything @builds = @builds.page(params[:page]).per(30).without_count end - # rubocop: enable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord def show diff --git a/app/finders/jobs_finder.rb b/app/finders/jobs_finder.rb new file mode 100644 index 00000000000..bac18e69618 --- /dev/null +++ b/app/finders/jobs_finder.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +class JobsFinder + include Gitlab::Allowable + + def initialize(current_user:, project: nil, params: {}) + @current_user = current_user + @project = project + @params = params + end + + def execute + builds = init_collection.order_id_desc + filter_by_scope(builds) + rescue Gitlab::Access::AccessDeniedError + Ci::Build.none + end + + private + + attr_reader :current_user, :project, :params + + def init_collection + project ? project_builds : all_builds + end + + def all_builds + raise Gitlab::Access::AccessDeniedError unless current_user&.admin? + + Ci::Build.all + end + + def project_builds + raise Gitlab::Access::AccessDeniedError unless can?(current_user, :read_build, project) + + project.builds.relevant + end + + def filter_by_scope(builds) + case params[:scope] + when 'pending' + builds.pending.reverse_order + when 'running' + builds.running.reverse_order + when 'finished' + builds.finished + else + builds + end + end +end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 59bff4e2d2b..4679e8b74d7 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -120,6 +120,20 @@ module Ci scope :eager_load_job_artifacts, -> { includes(:job_artifacts) } + scope :eager_load_everything, -> do + includes( + [ + { pipeline: [:project, :user] }, + :job_artifacts_archive, + :metadata, + :trigger_request, + :project, + :user, + :tags + ] + ) + end + scope :with_exposed_artifacts, -> do joins(:metadata).merge(Ci::BuildMetadata.with_exposed_artifacts) .includes(:metadata, :job_artifacts_metadata) @@ -161,6 +175,7 @@ module Ci end scope :queued_before, ->(time) { where(arel_table[:queued_at].lt(time)) } + scope :order_id_desc, -> { order('ci_builds.id DESC') } acts_as_taggable diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 6d38b58c301..b411bc296c5 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -772,18 +772,10 @@ module Ci triggered_by_merge_request? && target_sha.present? end - def merge_train_pipeline? - merge_request_pipeline? && merge_train_ref? - end - def merge_request_ref? MergeRequest.merge_request_ref?(ref) end - def merge_train_ref? - MergeRequest.merge_train_ref?(ref) - end - def matches_sha_or_source_sha?(sha) self.sha == sha || self.source_sha == sha end @@ -816,9 +808,7 @@ module Ci return unless merge_request_event? strong_memoize(:merge_request_event_type) do - if merge_train_pipeline? - :merge_train - elsif merge_request_pipeline? + if merge_request_pipeline? :merged_result elsif detached_merge_request_pipeline? :detached diff --git a/changelogs/unreleased/35616-broken-anchor-for-learn-more-about-interacting-with-security-report.yml b/changelogs/unreleased/35616-broken-anchor-for-learn-more-about-interacting-with-security-report.yml new file mode 100644 index 00000000000..6babed09767 --- /dev/null +++ b/changelogs/unreleased/35616-broken-anchor-for-learn-more-about-interacting-with-security-report.yml @@ -0,0 +1,5 @@ +--- +title: Use correct fragment identifier for vulnerability help path +merge_request: 20524 +author: +type: fixed diff --git a/doc/development/build_test_package.md b/doc/development/build_test_package.md index f58ac79b6f4..d478d6e1653 100644 --- a/doc/development/build_test_package.md +++ b/doc/development/build_test_package.md @@ -9,16 +9,16 @@ that will create: - A deb package for Ubuntu 16.04, available as a build artifact, and - A docker image, which is pushed to [Omnibus GitLab's container registry](https://gitlab.com/gitlab-org/omnibus-gitlab/container_registry) - (images titled `gitlab-foss` and `gitlab-ee` respectively and image tag is the + (images titled `gitlab-ce` and `gitlab-ee` respectively and image tag is the commit which triggered the pipeline). When you push a commit to either the GitLab CE or GitLab EE project, the pipeline for that commit will have a `build-package` manual action you can trigger. -![Manual actions](img/trigger_ss1.png) +![Manual actions](img/build_package_v12_6.png) -![Build package manual action](img/trigger_ss2.png) +![Build package manual action](img/trigger_build_package_v12_6.png) ## Specifying versions of components diff --git a/doc/development/img/build_package_v12_6.png b/doc/development/img/build_package_v12_6.png Binary files differnew file mode 100644 index 00000000000..c3d99e6c6ce --- /dev/null +++ b/doc/development/img/build_package_v12_6.png diff --git a/doc/development/img/trigger_build_package_v12_6.png b/doc/development/img/trigger_build_package_v12_6.png Binary files differnew file mode 100644 index 00000000000..6f5879bd8c4 --- /dev/null +++ b/doc/development/img/trigger_build_package_v12_6.png diff --git a/doc/development/img/trigger_ss1.png b/doc/development/img/trigger_ss1.png Binary files differdeleted file mode 100644 index addbc551f73..00000000000 --- a/doc/development/img/trigger_ss1.png +++ /dev/null diff --git a/doc/development/img/trigger_ss2.png b/doc/development/img/trigger_ss2.png Binary files differdeleted file mode 100644 index 02ef3810a59..00000000000 --- a/doc/development/img/trigger_ss2.png +++ /dev/null diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a4f92ede7dc..e703e87f0d6 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -5257,14 +5257,15 @@ msgid_plural "CycleAnalytics|%d projects selected" msgstr[0] "" msgstr[1] "" -msgid "CycleAnalytics|%{stageName}" -msgid_plural "CycleAnalytics|%d stages selected" -msgstr[0] "" -msgstr[1] "" +msgid "CycleAnalytics|%{stageCount} stages selected" +msgstr "" msgid "CycleAnalytics|All stages" msgstr "" +msgid "CycleAnalytics|No stages selected" +msgstr "" + msgid "CycleAnalytics|Stages" msgstr "" diff --git a/spec/finders/jobs_finder_spec.rb b/spec/finders/jobs_finder_spec.rb new file mode 100644 index 00000000000..675d170b90e --- /dev/null +++ b/spec/finders/jobs_finder_spec.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe JobsFinder, '#execute' do + set(:user) { create(:user) } + set(:admin) { create(:user, :admin) } + set(:project) { create(:project, :private, public_builds: false) } + set(:pipeline) { create(:ci_pipeline, project: project) } + set(:job_1) { create(:ci_build) } + set(:job_2) { create(:ci_build, :running) } + set(:job_3) { create(:ci_build, :success, pipeline: pipeline) } + + let(:params) { {} } + + context 'no project' do + subject { described_class.new(current_user: admin, params: params).execute } + + it 'returns all jobs' do + expect(subject).to match_array([job_1, job_2, job_3]) + end + + context 'non admin user' do + let(:admin) { user } + + it 'returns no jobs' do + expect(subject).to be_empty + end + end + + context 'without user' do + let(:admin) { nil } + + it 'returns no jobs' do + expect(subject).to be_empty + end + end + + context 'scope is present' do + let(:jobs) { [job_1, job_2, job_3] } + + where(:scope, :index) do + [ + ['pending', 0], + ['running', 1], + ['finished', 2] + ] + end + + with_them do + let(:params) { { scope: scope } } + + it { expect(subject).to match_array([jobs[index]]) } + end + end + end + + context 'a project is present' do + subject { described_class.new(current_user: user, project: project, params: params).execute } + + context 'user has access to the project' do + before do + project.add_maintainer(user) + end + + it 'returns jobs for the specified project' do + expect(subject).to match_array([job_3]) + end + end + + context 'user has no access to project builds' do + before do + project.add_guest(user) + end + + it 'returns no jobs' do + expect(subject).to be_empty + end + end + + context 'without user' do + let(:user) { nil } + + it 'returns no jobs' do + expect(subject).to be_empty + end + end + end +end diff --git a/spec/frontend/vue_shared/components/markdown/field_spec.js b/spec/frontend/vue_shared/components/markdown/field_spec.js new file mode 100644 index 00000000000..b006f72b8ee --- /dev/null +++ b/spec/frontend/vue_shared/components/markdown/field_spec.js @@ -0,0 +1,179 @@ +import { mount, createLocalVue } from '@vue/test-utils'; +import fieldComponent from '~/vue_shared/components/markdown/field.vue'; +import { TEST_HOST } from 'spec/test_constants'; +import AxiosMockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; +import $ from 'jquery'; + +const markdownPreviewPath = `${TEST_HOST}/preview`; +const markdownDocsPath = `${TEST_HOST}/docs`; + +function assertMarkdownTabs(isWrite, writeLink, previewLink, wrapper) { + expect(writeLink.element.parentNode.classList.contains('active')).toEqual(isWrite); + expect(previewLink.element.parentNode.classList.contains('active')).toEqual(!isWrite); + expect(wrapper.find('.md-preview-holder').element.style.display).toEqual(isWrite ? 'none' : ''); +} + +function createComponent() { + const wrapper = mount(fieldComponent, { + propsData: { + markdownDocsPath, + markdownPreviewPath, + }, + slots: { + textarea: '<textarea>testing\n123</textarea>', + }, + template: ` + <field-component + markdown-preview-path="${markdownPreviewPath}" + markdown-docs-path="${markdownDocsPath}" + > + <textarea + slot="textarea" + v-model="text"> + <slot>this is a test</slot> + </textarea> + </field-component> + `, + sync: false, + }); + return wrapper; +} + +const getPreviewLink = wrapper => wrapper.find('.nav-links .js-preview-link'); +const getWriteLink = wrapper => wrapper.find('.nav-links .js-write-link'); +const getMarkdownButton = wrapper => wrapper.find('.js-md'); +const getAllMarkdownButtons = wrapper => wrapper.findAll('.js-md'); + +describe('Markdown field component', () => { + let axiosMock; + const localVue = createLocalVue(); + + beforeEach(() => { + axiosMock = new AxiosMockAdapter(axios); + }); + + afterEach(() => { + axiosMock.restore(); + }); + + describe('mounted', () => { + let wrapper; + const previewHTML = '<p>markdown preview</p>'; + let previewLink; + let writeLink; + + it('renders textarea inside backdrop', () => { + wrapper = createComponent(); + expect(wrapper.find('.zen-backdrop textarea').element).not.toBeNull(); + }); + + describe('markdown preview', () => { + beforeEach(() => { + axiosMock.onPost(markdownPreviewPath).reply(200, { body: previewHTML }); + }); + + it('sets preview link as active', () => { + wrapper = createComponent(); + previewLink = getPreviewLink(wrapper); + previewLink.trigger('click'); + + return localVue.nextTick().then(() => { + expect(previewLink.element.parentNode.classList.contains('active')).toBeTruthy(); + }); + }); + + it('shows preview loading text', () => { + wrapper = createComponent(); + previewLink = getPreviewLink(wrapper); + previewLink.trigger('click'); + + localVue.nextTick(() => { + expect(wrapper.find('.md-preview-holder').element.textContent.trim()).toContain( + 'Loading…', + ); + }); + }); + + it('renders markdown preview', () => { + wrapper = createComponent(); + previewLink = getPreviewLink(wrapper); + previewLink.trigger('click'); + + setTimeout(() => { + expect(wrapper.find('.md-preview-holder').element.innerHTML).toContain(previewHTML); + }); + }); + + it('renders GFM with jQuery', () => { + wrapper = createComponent(); + previewLink = getPreviewLink(wrapper); + jest.spyOn($.fn, 'renderGFM'); + + previewLink.trigger('click'); + + setTimeout(() => { + expect($.fn.renderGFM).toHaveBeenCalled(); + }, 0); + }); + + it('clicking already active write or preview link does nothing', () => { + wrapper = createComponent(); + writeLink = getWriteLink(wrapper); + previewLink = getPreviewLink(wrapper); + + writeLink.trigger('click'); + return localVue + .nextTick() + .then(() => assertMarkdownTabs(true, writeLink, previewLink, wrapper)) + .then(() => writeLink.trigger('click')) + .then(() => localVue.nextTick()) + .then(() => assertMarkdownTabs(true, writeLink, previewLink, wrapper)) + .then(() => previewLink.trigger('click')) + .then(() => localVue.nextTick()) + .then(() => assertMarkdownTabs(false, writeLink, previewLink, wrapper)) + .then(() => previewLink.trigger('click')) + .then(() => localVue.nextTick()) + .then(() => assertMarkdownTabs(false, writeLink, previewLink, wrapper)); + }); + }); + + describe('markdown buttons', () => { + it('converts single words', () => { + wrapper = createComponent(); + const textarea = wrapper.find('textarea').element; + textarea.setSelectionRange(0, 7); + const markdownButton = getMarkdownButton(wrapper); + markdownButton.trigger('click'); + + localVue.nextTick(() => { + expect(textarea.value).toContain('**testing**'); + }); + }); + + it('converts a line', () => { + wrapper = createComponent(); + const textarea = wrapper.find('textarea').element; + textarea.setSelectionRange(0, 0); + const markdownButton = getAllMarkdownButtons(wrapper).wrappers[5]; + markdownButton.trigger('click'); + + localVue.nextTick(() => { + expect(textarea.value).toContain('* testing'); + }); + }); + + it('converts multiple lines', () => { + wrapper = createComponent(); + const textarea = wrapper.find('textarea').element; + textarea.setSelectionRange(0, 50); + const markdownButton = getAllMarkdownButtons(wrapper).wrappers[5]; + markdownButton.trigger('click'); + + localVue.nextTick(() => { + expect(textarea.value).toContain('* testing\n* 123'); + }); + }); + }); + }); +}); diff --git a/spec/javascripts/vue_shared/components/markdown/field_spec.js b/spec/javascripts/vue_shared/components/markdown/field_spec.js deleted file mode 100644 index da984175f9f..00000000000 --- a/spec/javascripts/vue_shared/components/markdown/field_spec.js +++ /dev/null @@ -1,173 +0,0 @@ -import $ from 'jquery'; -import '~/behaviors/markdown/render_gfm'; -import Vue from 'vue'; -import AxiosMockAdapter from 'axios-mock-adapter'; -import axios from '~/lib/utils/axios_utils'; -import fieldComponent from '~/vue_shared/components/markdown/field.vue'; -import { TEST_HOST } from 'spec/test_constants'; - -function assertMarkdownTabs(isWrite, writeLink, previewLink, vm) { - expect(writeLink.parentNode.classList.contains('active')).toEqual(isWrite); - expect(previewLink.parentNode.classList.contains('active')).toEqual(!isWrite); - expect(vm.$el.querySelector('.md-preview-holder').style.display).toEqual(isWrite ? 'none' : ''); -} - -describe('Markdown field component', () => { - const markdownPreviewPath = `${TEST_HOST}/preview`; - const markdownDocsPath = `${TEST_HOST}/docs`; - let axiosMock; - let vm; - - beforeEach(done => { - axiosMock = new AxiosMockAdapter(axios); - vm = new Vue({ - components: { - fieldComponent, - }, - data() { - return { - text: 'testing\n123', - }; - }, - template: ` - <field-component - markdown-preview-path="${markdownPreviewPath}" - markdown-docs-path="${markdownDocsPath}" - > - <textarea - slot="textarea" - v-model="text"> - </textarea> - </field-component> - `, - }).$mount(); - - Vue.nextTick(done); - }); - - afterEach(() => { - axiosMock.restore(); - }); - - describe('mounted', () => { - const previewHTML = '<p>markdown preview</p>'; - - it('renders textarea inside backdrop', () => { - expect(vm.$el.querySelector('.zen-backdrop textarea')).not.toBeNull(); - }); - - describe('markdown preview', () => { - let previewLink; - let writeLink; - - beforeEach(() => { - axiosMock.onPost(markdownPreviewPath).replyOnce(200, { body: previewHTML }); - - previewLink = vm.$el.querySelector('.nav-links .js-preview-link'); - writeLink = vm.$el.querySelector('.nav-links .js-write-link'); - }); - - it('sets preview link as active', done => { - previewLink.click(); - - Vue.nextTick(() => { - expect(previewLink.parentNode.classList.contains('active')).toBeTruthy(); - - done(); - }); - }); - - it('shows preview loading text', done => { - previewLink.click(); - - Vue.nextTick(() => { - expect(vm.$el.querySelector('.md-preview-holder').textContent.trim()).toContain( - 'Loading…', - ); - - done(); - }); - }); - - it('renders markdown preview', done => { - previewLink.click(); - - setTimeout(() => { - expect(vm.$el.querySelector('.md-preview-holder').innerHTML).toContain(previewHTML); - - done(); - }); - }); - - it('renders GFM with jQuery', done => { - spyOn($.fn, 'renderGFM'); - - previewLink.click(); - - setTimeout(() => { - expect($.fn.renderGFM).toHaveBeenCalled(); - - done(); - }, 0); - }); - - it('clicking already active write or preview link does nothing', done => { - writeLink.click(); - Vue.nextTick() - .then(() => assertMarkdownTabs(true, writeLink, previewLink, vm)) - .then(() => writeLink.click()) - .then(() => Vue.nextTick()) - .then(() => assertMarkdownTabs(true, writeLink, previewLink, vm)) - .then(() => previewLink.click()) - .then(() => Vue.nextTick()) - .then(() => assertMarkdownTabs(false, writeLink, previewLink, vm)) - .then(() => previewLink.click()) - .then(() => Vue.nextTick()) - .then(() => assertMarkdownTabs(false, writeLink, previewLink, vm)) - .then(done) - .catch(done.fail); - }); - }); - - describe('markdown buttons', () => { - it('converts single words', done => { - const textarea = vm.$el.querySelector('textarea'); - - textarea.setSelectionRange(0, 7); - vm.$el.querySelector('.js-md').click(); - - Vue.nextTick(() => { - expect(textarea.value).toContain('**testing**'); - - done(); - }); - }); - - it('converts a line', done => { - const textarea = vm.$el.querySelector('textarea'); - - textarea.setSelectionRange(0, 0); - vm.$el.querySelectorAll('.js-md')[5].click(); - - Vue.nextTick(() => { - expect(textarea.value).toContain('* testing'); - - done(); - }); - }); - - it('converts multiple lines', done => { - const textarea = vm.$el.querySelector('textarea'); - - textarea.setSelectionRange(0, 50); - vm.$el.querySelectorAll('.js-md')[5].click(); - - Vue.nextTick(() => { - expect(textarea.value).toContain('* testing\n* 123'); - - done(); - }); - }); - }); - }); -}); diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 977f1fdd267..d34919d17fe 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -199,25 +199,6 @@ describe Ci::Pipeline, :mailer do end end - describe '#merge_train_pipeline?' do - subject { pipeline.merge_train_pipeline? } - - let!(:pipeline) do - create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, ref: ref, target_sha: 'xxx') - end - - let(:merge_request) { create(:merge_request) } - let(:ref) { 'refs/merge-requests/1/train' } - - it { is_expected.to be_truthy } - - context 'when ref is merge ref' do - let(:ref) { 'refs/merge-requests/1/merge' } - - it { is_expected.to be_falsy } - end - end - describe '#merge_request_ref?' do subject { pipeline.merge_request_ref? } @@ -228,43 +209,19 @@ describe Ci::Pipeline, :mailer do end end - describe '#merge_train_ref?' do - subject { pipeline.merge_train_ref? } - - it 'calls Mergetrain#merge_train_ref?' do - expect(MergeRequest).to receive(:merge_train_ref?).with(pipeline.ref) - - subject - end - end - describe '#merge_request_event_type' do subject { pipeline.merge_request_event_type } - before do - allow(pipeline).to receive(:merge_request_event?) { true } - end - - context 'when pipeline is merge train pipeline' do - before do - allow(pipeline).to receive(:merge_train_pipeline?) { true } - end - - it { is_expected.to eq(:merge_train) } - end + let(:pipeline) { merge_request.all_pipelines.last } context 'when pipeline is merge request pipeline' do - before do - allow(pipeline).to receive(:merge_request_pipeline?) { true } - end + let(:merge_request) { create(:merge_request, :with_merge_request_pipeline) } it { is_expected.to eq(:merged_result) } end context 'when pipeline is detached merge request pipeline' do - before do - allow(pipeline).to receive(:detached_merge_request_pipeline?) { true } - end + let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) } it { is_expected.to eq(:detached) } end |