Commit 2eb74fb7 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents 38921267 0d26c483
...@@ -26,7 +26,8 @@ module Ci ...@@ -26,7 +26,8 @@ module Ci
belongs_to :erased_by, class_name: 'User' belongs_to :erased_by, class_name: 'User'
RUNNER_FEATURES = { RUNNER_FEATURES = {
upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? } upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? },
refspecs: -> (build) { build.merge_request_ref? }
}.freeze }.freeze
has_one :deployment, as: :deployable, class_name: 'Deployment' has_one :deployment, as: :deployable, class_name: 'Deployment'
...@@ -47,7 +48,8 @@ module Ci ...@@ -47,7 +48,8 @@ module Ci
delegate :terminal_specification, to: :runner_session, allow_nil: true delegate :terminal_specification, to: :runner_session, allow_nil: true
delegate :gitlab_deploy_token, to: :project delegate :gitlab_deploy_token, to: :project
delegate :trigger_short_token, to: :trigger_request, allow_nil: true delegate :trigger_short_token, to: :trigger_request, allow_nil: true
delegate :merge_request_event?, to: :pipeline delegate :merge_request_event?, :merge_request_ref?,
:legacy_detached_merge_request_pipeline?, to: :pipeline
## ##
# Since Gitlab 11.5, deployments records started being created right after # Since Gitlab 11.5, deployments records started being created right after
......
...@@ -738,6 +738,10 @@ module Ci ...@@ -738,6 +738,10 @@ module Ci
triggered_by_merge_request? && target_sha.nil? triggered_by_merge_request? && target_sha.nil?
end end
def legacy_detached_merge_request_pipeline?
detached_merge_request_pipeline? && !merge_request_ref?
end
def merge_request_pipeline? def merge_request_pipeline?
triggered_by_merge_request? && target_sha.present? triggered_by_merge_request? && target_sha.present?
end end
...@@ -746,6 +750,10 @@ module Ci ...@@ -746,6 +750,10 @@ module Ci
triggered_by_merge_request? && target_sha == merge_request.target_branch_sha triggered_by_merge_request? && target_sha == merge_request.target_branch_sha
end end
def merge_request_ref?
MergeRequest.merge_request_ref?(ref)
end
def matches_sha_or_source_sha?(sha) def matches_sha_or_source_sha?(sha)
self.sha == sha || self.source_sha == sha self.sha == sha || self.source_sha == sha
end end
......
...@@ -1131,6 +1131,10 @@ class MergeRequest < ApplicationRecord ...@@ -1131,6 +1131,10 @@ class MergeRequest < ApplicationRecord
"refs/#{Repository::REF_MERGE_REQUEST}/#{iid}/merge" "refs/#{Repository::REF_MERGE_REQUEST}/#{iid}/merge"
end end
def self.merge_request_ref?(ref)
ref.start_with?("refs/#{Repository::REF_MERGE_REQUEST}/")
end
def in_locked_state def in_locked_state
begin begin
lock_mr lock_mr
......
...@@ -4,6 +4,7 @@ module Ci ...@@ -4,6 +4,7 @@ module Ci
class BuildRunnerPresenter < SimpleDelegator class BuildRunnerPresenter < SimpleDelegator
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
DEFAULT_GIT_DEPTH_MERGE_REQUEST = 10
RUNNER_REMOTE_TAG_PREFIX = 'refs/tags/'.freeze RUNNER_REMOTE_TAG_PREFIX = 'refs/tags/'.freeze
RUNNER_REMOTE_BRANCH_PREFIX = 'refs/remotes/origin/'.freeze RUNNER_REMOTE_BRANCH_PREFIX = 'refs/remotes/origin/'.freeze
...@@ -27,6 +28,7 @@ module Ci ...@@ -27,6 +28,7 @@ module Ci
def git_depth def git_depth
strong_memoize(:git_depth) do strong_memoize(:git_depth) do
git_depth = variables&.find { |variable| variable[:key] == 'GIT_DEPTH' }&.dig(:value) git_depth = variables&.find { |variable| variable[:key] == 'GIT_DEPTH' }&.dig(:value)
git_depth ||= DEFAULT_GIT_DEPTH_MERGE_REQUEST if merge_request_ref?
git_depth.to_i git_depth.to_i
end end
end end
...@@ -35,8 +37,9 @@ module Ci ...@@ -35,8 +37,9 @@ module Ci
specs = [] specs = []
if git_depth > 0 if git_depth > 0
specs << refspec_for_branch(ref) if branch? || merge_request_event? specs << refspec_for_branch(ref) if branch? || legacy_detached_merge_request_pipeline?
specs << refspec_for_tag(ref) if tag? specs << refspec_for_tag(ref) if tag?
specs << refspec_for_merge_request_ref if merge_request_ref?
else else
specs << refspec_for_branch specs << refspec_for_branch
specs << refspec_for_tag specs << refspec_for_tag
...@@ -83,5 +86,9 @@ module Ci ...@@ -83,5 +86,9 @@ module Ci
def refspec_for_tag(ref = '*') def refspec_for_tag(ref = '*')
"+#{Gitlab::Git::TAG_REF_PREFIX}#{ref}:#{RUNNER_REMOTE_TAG_PREFIX}#{ref}" "+#{Gitlab::Git::TAG_REF_PREFIX}#{ref}:#{RUNNER_REMOTE_TAG_PREFIX}#{ref}"
end end
def refspec_for_merge_request_ref
"+#{ref}:#{ref}"
end
end end
end end
...@@ -54,7 +54,7 @@ module MergeRequests ...@@ -54,7 +54,7 @@ module MergeRequests
merge_request, merge_request.project, current_user, merge_request.assignee) merge_request, merge_request.project, current_user, merge_request.assignee)
end end
def create_merge_request_pipeline(merge_request, user) def create_pipeline_for(merge_request, user)
return unless Feature.enabled?(:ci_merge_request_pipeline, return unless Feature.enabled?(:ci_merge_request_pipeline,
merge_request.source_project, merge_request.source_project,
default_enabled: true) default_enabled: true)
...@@ -65,12 +65,24 @@ module MergeRequests ...@@ -65,12 +65,24 @@ module MergeRequests
return if merge_request.merge_request_pipeline_exists? return if merge_request.merge_request_pipeline_exists?
return if merge_request.has_no_commits? return if merge_request.has_no_commits?
Ci::CreatePipelineService create_detached_merge_request_pipeline(merge_request, user)
.new(merge_request.source_project, user, ref: merge_request.source_branch) end
.execute(:merge_request_event,
ignore_skip_ci: true, def create_detached_merge_request_pipeline(merge_request, user)
save_on_errors: false, if can_use_merge_request_ref?(merge_request)
merge_request: merge_request) Ci::CreatePipelineService.new(merge_request.source_project, user,
ref: merge_request.ref_path)
.execute(:merge_request_event, merge_request: merge_request)
else
Ci::CreatePipelineService.new(merge_request.source_project, user,
ref: merge_request.source_branch)
.execute(:merge_request_event, merge_request: merge_request)
end
end
def can_use_merge_request_ref?(merge_request)
Feature.enabled?(:ci_use_merge_request_ref, project, default_enabled: true) &&
!merge_request.for_fork?
end end
# Returns all origin and fork merge requests from `@project` satisfying passed arguments. # Returns all origin and fork merge requests from `@project` satisfying passed arguments.
......
...@@ -25,7 +25,7 @@ module MergeRequests ...@@ -25,7 +25,7 @@ module MergeRequests
def after_create(issuable) def after_create(issuable)
todo_service.new_merge_request(issuable, current_user) todo_service.new_merge_request(issuable, current_user)
issuable.cache_merge_request_closes_issues!(current_user) issuable.cache_merge_request_closes_issues!(current_user)
create_merge_request_pipeline(issuable, current_user) create_pipeline_for(issuable, current_user)
issuable.update_head_pipeline issuable.update_head_pipeline
super super
......
...@@ -107,7 +107,7 @@ module MergeRequests ...@@ -107,7 +107,7 @@ module MergeRequests
end end
merge_request.mark_as_unchecked merge_request.mark_as_unchecked
create_merge_request_pipeline(merge_request, current_user) create_pipeline_for(merge_request, current_user)
UpdateHeadPipelineForMergeRequestWorker.perform_async(merge_request.id) UpdateHeadPipelineForMergeRequestWorker.perform_async(merge_request.id)
end end
......
---
title: Create MR pipelines with `refs/merge-requests/:iid/head`
merge_request: 25504
author:
type: changed
...@@ -33,6 +33,13 @@ module Gitlab ...@@ -33,6 +33,13 @@ module Gitlab
end end
end end
def merge_request_ref_exists?
strong_memoize(:merge_request_ref_exists) do
MergeRequest.merge_request_ref?(origin_ref) &&
project.repository.ref_exists?(origin_ref)
end
end
def ref def ref
strong_memoize(:ref) do strong_memoize(:ref) do
Gitlab::Git.ref_name(origin_ref) Gitlab::Git.ref_name(origin_ref)
......
...@@ -44,6 +44,8 @@ module Gitlab ...@@ -44,6 +44,8 @@ module Gitlab
access.can_update_branch?(@command.ref) access.can_update_branch?(@command.ref)
elsif @command.tag_exists? elsif @command.tag_exists?
access.can_create_tag?(@command.ref) access.can_create_tag?(@command.ref)
elsif @command.merge_request_ref_exists?
access.can_update_branch?(@command.merge_request.source_branch)
else else
true # Allow it for now and we'll reject when we check ref existence true # Allow it for now and we'll reject when we check ref existence
end end
......
...@@ -9,7 +9,7 @@ module Gitlab ...@@ -9,7 +9,7 @@ module Gitlab
include Chain::Helpers include Chain::Helpers
def perform! def perform!
unless @command.branch_exists? || @command.tag_exists? unless @command.branch_exists? || @command.tag_exists? || @command.merge_request_ref_exists?
return error('Reference not found') return error('Reference not found')
end end
......
...@@ -117,9 +117,20 @@ FactoryBot.define do ...@@ -117,9 +117,20 @@ FactoryBot.define do
end end
end end
trait :with_legacy_detached_merge_request_pipeline do
after(:create) do |merge_request|
merge_request.merge_request_pipelines << create(:ci_pipeline,
source: :merge_request_event,
merge_request: merge_request,
project: merge_request.source_project,
ref: merge_request.source_branch,
sha: merge_request.source_branch_sha)
end
end
trait :with_detached_merge_request_pipeline do trait :with_detached_merge_request_pipeline do
after(:build) do |merge_request| after(:create) do |merge_request|
merge_request.merge_request_pipelines << build(:ci_pipeline, merge_request.merge_request_pipelines << create(:ci_pipeline,
source: :merge_request_event, source: :merge_request_event,
merge_request: merge_request, merge_request: merge_request,
project: merge_request.source_project, project: merge_request.source_project,
...@@ -135,7 +146,7 @@ FactoryBot.define do ...@@ -135,7 +146,7 @@ FactoryBot.define do
target_sha { target_branch_sha } target_sha { target_branch_sha }
end end
after(:build) do |merge_request, evaluator| after(:create) do |merge_request, evaluator|
merge_request.merge_request_pipelines << create(:ci_pipeline, merge_request.merge_request_pipelines << create(:ci_pipeline,
source: :merge_request_event, source: :merge_request_event,
merge_request: merge_request, merge_request: merge_request,
......
...@@ -48,6 +48,24 @@ describe Gitlab::Ci::Pipeline::Chain::Command do ...@@ -48,6 +48,24 @@ describe Gitlab::Ci::Pipeline::Chain::Command do
end end
end end
describe '#merge_request_ref_exists?' do
subject { command.merge_request_ref_exists? }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
context 'for existing merge request ref' do
let(:origin_ref) { merge_request.ref_path }
it { is_expected.to eq(true) }
end
context 'for branch ref' do
let(:origin_ref) { merge_request.source_branch }
it { is_expected.to eq(false) }
end
end
describe '#ref' do describe '#ref' do
subject { command.ref } subject { command.ref }
......
...@@ -10,12 +10,33 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do ...@@ -10,12 +10,33 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
let(:command) do let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new( Gitlab::Ci::Pipeline::Chain::Command.new(
project: project, current_user: user, origin_ref: ref) project: project, current_user: user, origin_ref: origin_ref, merge_request: merge_request)
end end
let(:step) { described_class.new(pipeline, command) } let(:step) { described_class.new(pipeline, command) }
let(:ref) { 'master' } let(:ref) { 'master' }
let(:origin_ref) { ref }
let(:merge_request) { nil }
shared_context 'detached merge request pipeline' do
let(:merge_request) do
create(:merge_request,
source_project: project,
source_branch: ref,
target_project: project,
target_branch: 'feature')
end
let(:pipeline) do
build(:ci_pipeline,
source: :merge_request_event,
merge_request: merge_request,
project: project)
end
let(:origin_ref) { merge_request.ref_path }
end
context 'when users has no ability to run a pipeline' do context 'when users has no ability to run a pipeline' do
before do before do
...@@ -58,6 +79,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do ...@@ -58,6 +79,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
context 'when pipeline is a detached merge request pipeline' do
include_context 'detached merge request pipeline'
it { is_expected.to be_truthy }
end
context 'when the branch is protected' do context 'when the branch is protected' do
let!(:protected_branch) do let!(:protected_branch) do
create(:protected_branch, project: project, name: ref) create(:protected_branch, project: project, name: ref)
...@@ -65,6 +92,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do ...@@ -65,6 +92,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
context 'when pipeline is a detached merge request pipeline' do
include_context 'detached merge request pipeline'
it { is_expected.to be_falsey }
end
context 'when developers are allowed to merge' do context 'when developers are allowed to merge' do
let!(:protected_branch) do let!(:protected_branch) do
create(:protected_branch, create(:protected_branch,
...@@ -74,6 +107,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do ...@@ -74,6 +107,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
end end
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
context 'when pipeline is a detached merge request pipeline' do
include_context 'detached merge request pipeline'
it { is_expected.to be_truthy }
end
end end
end end
...@@ -112,6 +151,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do ...@@ -112,6 +151,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do
end end
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
context 'when pipeline is a detached merge request pipeline' do
include_context 'detached merge request pipeline'
it { is_expected.to be_truthy }
end
end end
context 'when the tag is protected' do context 'when the tag is protected' do
......
...@@ -42,6 +42,25 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Repository do ...@@ -42,6 +42,25 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Repository do
end end
end end
context 'when origin ref is a merge request ref' do
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
project: project, current_user: user, origin_ref: origin_ref, checkout_sha: checkout_sha)
end
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:origin_ref) { merge_request.ref_path }
let(:checkout_sha) { project.repository.commit(merge_request.ref_path).id }
it 'does not break the chain' do
expect(step.break?).to be false
end
it 'does not append pipeline errors' do
expect(pipeline.errors).to be_empty
end
end
context 'when ref is ambiguous' do context 'when ref is ambiguous' do
let(:project) do let(:project) do
create(:project, :repository).tap do |proj| create(:project, :repository).tap do |proj|
......
...@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20181219145520_migrate_cluster_co ...@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20181219145520_migrate_cluster_co
describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queue' do context 'when there are jobs in the queue' do
it 'correctly migrates queue when migrating up' do it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: 'gcp_cluster:cluster_platform_configure').perform_async('Something', [1]) stub_worker(queue: 'gcp_cluster:cluster_platform_configure').perform_async('Something', [1])
stubbed_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1]) stub_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1])
described_class.new.up described_class.new.up
...@@ -19,12 +20,12 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do ...@@ -19,12 +20,12 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do
it 'does not affect other queues under the same namespace' do it 'does not affect other queues under the same namespace' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: 'gcp_cluster:cluster_install_app').perform_async('Something', [1]) stub_worker(queue: 'gcp_cluster:cluster_install_app').perform_async('Something', [1])
stubbed_worker(queue: 'gcp_cluster:cluster_provision').perform_async('Something', [1]) stub_worker(queue: 'gcp_cluster:cluster_provision').perform_async('Something', [1])
stubbed_worker(queue: 'gcp_cluster:cluster_wait_for_app_installation').perform_async('Something', [1]) stub_worker(queue: 'gcp_cluster:cluster_wait_for_app_installation').perform_async('Something', [1])
stubbed_worker(queue: 'gcp_cluster:wait_for_cluster_creation').perform_async('Something', [1]) stub_worker(queue: 'gcp_cluster:wait_for_cluster_creation').perform_async('Something', [1])
stubbed_worker(queue: 'gcp_cluster:cluster_wait_for_ingress_ip_address').perform_async('Something', [1]) stub_worker(queue: 'gcp_cluster:cluster_wait_for_ingress_ip_address').perform_async('Something', [1])
stubbed_worker(queue: 'gcp_cluster:cluster_project_configure').perform_async('Something', [1]) stub_worker(queue: 'gcp_cluster:cluster_project_configure').perform_async('Something', [1])
described_class.new.up described_class.new.up
...@@ -39,7 +40,7 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do ...@@ -39,7 +40,7 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do
it 'correctly migrates queue when migrating down' do it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1]) stub_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1])
described_class.new.down described_class.new.down
...@@ -58,11 +59,4 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do ...@@ -58,11 +59,4 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do
expect { described_class.new.down }.not_to raise_error expect { described_class.new.down }.not_to raise_error
end end
end end
def stubbed_worker(queue:)
Class.new do
include Sidekiq::Worker
sidekiq_options queue: queue
end
end
end end
...@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180306074045_migrate_create_tra ...@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180306074045_migrate_create_tra
describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queues' do context 'when there are jobs in the queues' do
it 'correctly migrates queue when migrating up' do it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: 'pipeline_default:create_trace_artifact').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:create_trace_artifact').perform_async('Something', [1])
stubbed_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1]) stub_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1])
described_class.new.up described_class.new.up
...@@ -19,11 +20,11 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do ...@@ -19,11 +20,11 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do
it 'does not affect other queues under the same namespace' do it 'does not affect other queues under the same namespace' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1])
stubbed_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1])
stubbed_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1])
stubbed_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1])
stubbed_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1])
described_class.new.up described_class.new.up
...@@ -37,7 +38,7 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do ...@@ -37,7 +38,7 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do
it 'correctly migrates queue when migrating down' do it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1]) stub_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1])
described_class.new.down described_class.new.down
...@@ -56,11 +57,4 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do ...@@ -56,11 +57,4 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do
expect { described_class.new.down }.not_to raise_error expect { described_class.new.down }.not_to raise_error
end end
end end
def stubbed_worker(queue:)
Class.new do
include Sidekiq::Worker
sidekiq_options queue: queue
end
end
end end
...@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180603190921_migrate_object_sto ...@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180603190921_migrate_object_sto
describe MigrateObjectStorageUploadSidekiqQueue, :sidekiq, :redis do describe MigrateObjectStorageUploadSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queue' do context 'when there are jobs in the queue' do
it 'correctly migrates queue when migrating up' do it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: 'object_storage_upload').perform_async('Something', [1]) stub_worker(queue: 'object_storage_upload').perform_async('Something', [1])
stubbed_worker(queue: 'object_storage:object_storage_background_move').perform_async('Something', [1]) stub_worker(queue: 'object_storage:object_storage_background_move').perform_async('Something', [1])
described_class.new.up described_class.new.up
...@@ -23,11 +24,4 @@ describe MigrateObjectStorageUploadSidekiqQueue, :sidekiq, :redis do ...@@ -23,11 +24,4 @@ describe MigrateObjectStorageUploadSidekiqQueue, :sidekiq, :redis do
expect { described_class.new.up }.not_to raise_error expect { described_class.new.up }.not_to raise_error
end end
end end
def stubbed_worker(queue:)
Class.new do
include Sidekiq::Worker
sidekiq_options queue: queue
end
end
end end
...@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20170822101017_migrate_pipeline_s ...@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20170822101017_migrate_pipeline_s
describe MigratePipelineSidekiqQueues, :sidekiq, :redis do describe MigratePipelineSidekiqQueues, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queues' do context 'when there are jobs in the queues' do
it 'correctly migrates queue when migrating up' do it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: :pipeline).perform_async('Something', [1]) stub_worker(queue: :pipeline).perform_async('Something', [1])
stubbed_worker(queue: :build).perform_async('Something', [1]) stub_worker(queue: :build).perform_async('Something', [1])
described_class.new.up described_class.new.up
...@@ -20,10 +21,10 @@ describe MigratePipelineSidekiqQueues, :sidekiq, :redis do ...@@ -20,10 +21,10 @@ describe MigratePipelineSidekiqQueues, :sidekiq, :redis do
it 'correctly migrates queue when migrating down' do it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: :pipeline_default).perform_async('Class', [1]) stub_worker(queue: :pipeline_default).perform_async('Class', [1])
stubbed_worker(queue: :pipeline_processing).perform_async('Class', [2]) stub_worker(queue: :pipeline_processing).perform_async('Class', [2])
stubbed_worker(queue: :pipeline_hooks).perform_async('Class', [3]) stub_worker(queue: :pipeline_hooks).perform_async('Class', [3])
stubbed_worker(queue: :pipeline_cache).perform_async('Class', [4]) stub_worker(queue: :pipeline_cache).perform_async('Class', [4])
described_class.new.down described_class.new.down
...@@ -45,11 +46,4 @@ describe MigratePipelineSidekiqQueues, :sidekiq, :redis do ...@@ -45,11 +46,4 @@ describe MigratePipelineSidekiqQueues, :sidekiq, :redis do
expect { described_class.new.down }.not_to raise_error expect { described_class.new.down }.not_to raise_error
end end
end end
def stubbed_worker(queue:)
Class.new do
include Sidekiq::Worker
sidekiq_options queue: queue
end
end
end end
...@@ -3,11 +3,12 @@ require Rails.root.join('db', 'post_migrate', '20190124200344_migrate_storage_mi ...@@ -3,11 +3,12 @@ require Rails.root.join('db', 'post_migrate', '20190124200344_migrate_storage_mi
describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queues' do context 'when there are jobs in the queues' do
it 'correctly migrates queue when migrating up' do it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: :storage_migrator).perform_async(1, 5) stub_worker(queue: :storage_migrator).perform_async(1, 5)
described_class.new.up described_class.new.up
...@@ -18,7 +19,7 @@ describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do ...@@ -18,7 +19,7 @@ describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do
it 'correctly migrates queue when migrating down' do it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: :'hashed_storage:hashed_storage_migrator').perform_async(1, 5) stub_worker(queue: :'hashed_storage:hashed_storage_migrator').perform_async(1, 5)
described_class.new.down described_class.new.down
...@@ -37,11 +38,4 @@ describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do ...@@ -37,11 +38,4 @@ describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do
expect { described_class.new.down }.not_to raise_error expect { described_class.new.down }.not_to raise_error
end end
end end
def stubbed_worker(queue:)
Class.new do
include Sidekiq::Worker
sidekiq_options queue: queue
end
end
end end
...@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180307012445_migrate_update_hea ...@@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180307012445_migrate_update_hea
describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis do describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queues' do context 'when there are jobs in the queues' do
it 'correctly migrates queue when migrating up' do it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1])
stubbed_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1]) stub_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1])
described_class.new.up described_class.new.up
...@@ -19,10 +20,10 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis ...@@ -19,10 +20,10 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis
it 'does not affect other queues under the same namespace' do it 'does not affect other queues under the same namespace' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1])
stubbed_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1])
stubbed_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1])
stubbed_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1]) stub_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1])
described_class.new.up described_class.new.up
...@@ -35,7 +36,7 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis ...@@ -35,7 +36,7 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis
it 'correctly migrates queue when migrating down' do it 'correctly migrates queue when migrating down' do
Sidekiq::Testing.disable! do Sidekiq::Testing.disable! do
stubbed_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1]) stub_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1])
described_class.new.down described_class.new.down
...@@ -54,11 +55,4 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis ...@@ -54,11 +55,4 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis
expect { described_class.new.down }.not_to raise_error expect { described_class.new.down }.not_to raise_error
end end
end end
def stubbed_worker(queue:)
Class.new do
include Sidekiq::Worker
sidekiq_options queue: queue
end
end
end end
...@@ -25,6 +25,8 @@ describe Ci::Build do ...@@ -25,6 +25,8 @@ describe Ci::Build do
it { is_expected.to respond_to(:has_trace?) } it { is_expected.to respond_to(:has_trace?) }
it { is_expected.to respond_to(:trace) } it { is_expected.to respond_to(:trace) }
it { is_expected.to delegate_method(:merge_request_event?).to(:pipeline) } it { is_expected.to delegate_method(:merge_request_event?).to(:pipeline) }
it { is_expected.to delegate_method(:merge_request_ref?).to(:pipeline) }
it { is_expected.to delegate_method(:legacy_detached_merge_request_pipeline?).to(:pipeline) }
it { is_expected.to be_a(ArtifactMigratable) } it { is_expected.to be_a(ArtifactMigratable) }
...@@ -3627,6 +3629,24 @@ describe Ci::Build do ...@@ -3627,6 +3629,24 @@ describe Ci::Build do
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
end end
end end
context 'when refspecs feature is required by build' do
before do
allow(build).to receive(:merge_request_ref?) { true }
end
context 'when runner provides given feature' do
let(:runner_features) { { refspecs: true } }
it { is_expected.to be_truthy }
end
context 'when runner does not provide given feature' do
let(:runner_features) { {} }
it { is_expected.to be_falsey }
end
end
end end
describe '#deployment_status' do describe '#deployment_status' do
......
...@@ -366,6 +366,42 @@ describe Ci::Pipeline, :mailer do ...@@ -366,6 +366,42 @@ describe Ci::Pipeline, :mailer do
end end
end end
describe '#merge_request_ref?' do
subject { pipeline.merge_request_ref? }
it 'calls MergeRequest#merge_request_ref?' do
expect(MergeRequest).to receive(:merge_request_ref?).with(pipeline.ref)
subject
end
end
describe '#legacy_detached_merge_request_pipeline?' do
subject { pipeline.legacy_detached_merge_request_pipeline? }
set(:merge_request) { create(:merge_request) }
let(:ref) { 'feature' }
let(:target_sha) { nil }
let(:pipeline) do
build(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, ref: ref, target_sha: target_sha)
end
it { is_expected.to be_truthy }
context 'when pipeline ref is a merge request ref' do
let(:ref) { 'refs/merge-requests/1/head' }
it { is_expected.to be_falsy }
end
context 'when target sha is set' do
let(:target_sha) { 'target-sha' }
it { is_expected.to be_falsy }
end
end
describe '#matches_sha_or_source_sha?' do describe '#matches_sha_or_source_sha?' do
subject { pipeline.matches_sha_or_source_sha?(sample_sha) } subject { pipeline.matches_sha_or_source_sha?(sample_sha) }
......
...@@ -3114,4 +3114,32 @@ describe MergeRequest do ...@@ -3114,4 +3114,32 @@ describe MergeRequest do
end end
end end
end end
describe '.merge_request_ref?' do
subject { described_class.merge_request_ref?(ref) }
context 'when ref is ref name of a branch' do
let(:ref) { 'feature' }
it { is_expected.to be_falsey }
end
context 'when ref is HEAD ref path of a branch' do
let(:ref) { 'refs/heads/feature' }
it { is_expected.to be_falsey }
end
context 'when ref is HEAD ref path of a merge request' do
let(:ref) { 'refs/merge-requests/1/head' }
it { is_expected.to be_truthy }
end
context 'when ref is merge ref path of a merge request' do
let(:ref) { 'refs/merge-requests/1/merge' }
it { is_expected.to be_truthy }
end
end
end end
...@@ -136,6 +136,24 @@ describe Ci::BuildRunnerPresenter do ...@@ -136,6 +136,24 @@ describe Ci::BuildRunnerPresenter do
is_expected.to eq(1) is_expected.to eq(1)
end end
end end
context 'when pipeline is detached merge request pipeline' do
let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
let(:pipeline) { merge_request.all_pipelines.first }
let(:build) { create(:ci_build, ref: pipeline.ref, pipeline: pipeline) }
it 'returns the default git depth for pipelines for merge requests' do
is_expected.to eq(described_class::DEFAULT_GIT_DEPTH_MERGE_REQUEST)
end
context 'when pipeline is legacy detached merge request pipeline' do
let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) }
it 'behaves as branch pipeline' do
is_expected.to eq(0)
end
end
end
end end
describe '#refspecs' do describe '#refspecs' do
...@@ -165,5 +183,25 @@ describe Ci::BuildRunnerPresenter do ...@@ -165,5 +183,25 @@ describe Ci::BuildRunnerPresenter do
end end
end end
end end
context 'when pipeline is detached merge request pipeline' do
let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
let(:pipeline) { merge_request.all_pipelines.first }
let(:build) { create(:ci_build, ref: pipeline.ref, pipeline: pipeline) }
it 'returns the correct refspecs' do
is_expected
.to contain_exactly('+refs/merge-requests/1/head:refs/merge-requests/1/head')
end
context 'when pipeline is legacy detached merge request pipeline' do
let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) }
it 'returns the correct refspecs' do
is_expected.to contain_exactly('+refs/tags/*:refs/tags/*',
'+refs/heads/*:refs/remotes/origin/*')
end
end
end
end end
end end
...@@ -173,7 +173,7 @@ describe MergeRequests::CreateService do ...@@ -173,7 +173,7 @@ describe MergeRequests::CreateService do
end end
end end
describe 'Merge request pipelines' do describe 'Pipelines for merge requests' do
before do before do
stub_ci_pipeline_yaml_file(YAML.dump(config)) stub_ci_pipeline_yaml_file(YAML.dump(config))
end end
...@@ -189,12 +189,46 @@ describe MergeRequests::CreateService do ...@@ -189,12 +189,46 @@ describe MergeRequests::CreateService do
} }
end end
it 'creates a merge request pipeline and sets it as a head pipeline' do it 'creates a detached merge request pipeline and sets it as a head pipeline' do
expect(merge_request).to be_persisted expect(merge_request).to be_persisted
merge_request.reload merge_request.reload
expect(merge_request.merge_request_pipelines.count).to eq(1) expect(merge_request.merge_request_pipelines.count).to eq(1)
expect(merge_request.actual_head_pipeline).to be_merge_request_event expect(merge_request.actual_head_pipeline).to be_detached_merge_request_pipeline
end
context 'when merge request is submitted from forked project' do
let(:target_project) { fork_project(project, nil, repository: true) }
let(:opts) do
{
title: 'Awesome merge_request',
source_branch: 'feature',
target_branch: 'master',
target_project_id: target_project.id
}
end
before do
target_project.add_developer(assignee)
target_project.add_maintainer(user)
end
it 'create legacy detached merge request pipeline for fork merge request' do
expect(merge_request.actual_head_pipeline)
.to be_legacy_detached_merge_request_pipeline
end
end
context 'when ci_use_merge_request_ref feature flag is false' do
before do
stub_feature_flags(ci_use_merge_request_ref: false)
end
it 'create legacy detached merge request pipeline for non-fork merge request' do
expect(merge_request.actual_head_pipeline)
.to be_legacy_detached_merge_request_pipeline
end
end end
context 'when there are no commits between source branch and target branch' do context 'when there are no commits between source branch and target branch' do
...@@ -207,7 +241,7 @@ describe MergeRequests::CreateService do ...@@ -207,7 +241,7 @@ describe MergeRequests::CreateService do
} }
end end
it 'does not create a merge request pipeline' do it 'does not create a detached merge request pipeline' do
expect(merge_request).to be_persisted expect(merge_request).to be_persisted
merge_request.reload merge_request.reload
...@@ -225,7 +259,7 @@ describe MergeRequests::CreateService do ...@@ -225,7 +259,7 @@ describe MergeRequests::CreateService do
merge_request merge_request
end end
it 'sets the latest merge request pipeline as the head pipeline' do it 'sets the latest detached merge request pipeline as the head pipeline' do
expect(merge_request.actual_head_pipeline).to be_merge_request_event expect(merge_request.actual_head_pipeline).to be_merge_request_event
end end
end end
...@@ -235,7 +269,7 @@ describe MergeRequests::CreateService do ...@@ -235,7 +269,7 @@ describe MergeRequests::CreateService do
stub_feature_flags(ci_merge_request_pipeline: false) stub_feature_flags(ci_merge_request_pipeline: false)
end end
it 'does not create a merge request pipeline' do it 'does not create a detached merge request pipeline' do
expect(merge_request).to be_persisted expect(merge_request).to be_persisted
merge_request.reload merge_request.reload
...@@ -254,7 +288,7 @@ describe MergeRequests::CreateService do ...@@ -254,7 +288,7 @@ describe MergeRequests::CreateService do
} }
end end
it 'does not create a merge request pipeline' do it 'does not create a detached merge request pipeline' do
expect(merge_request).to be_persisted expect(merge_request).to be_persisted
merge_request.reload merge_request.reload
......
...@@ -147,7 +147,7 @@ describe MergeRequests::RefreshService do ...@@ -147,7 +147,7 @@ describe MergeRequests::RefreshService do
end end
end end
describe 'Merge request pipelines' do describe 'Pipelines for merge requests' do
before do before do
stub_ci_pipeline_yaml_file(YAML.dump(config)) stub_ci_pipeline_yaml_file(YAML.dump(config))
end end
...@@ -165,7 +165,7 @@ describe MergeRequests::RefreshService do ...@@ -165,7 +165,7 @@ describe MergeRequests::RefreshService do
} }
end end
it 'create merge request pipeline with commits' do it 'create detached merge request pipeline with commits' do
expect { subject } expect { subject }
.to change { @merge_request.merge_request_pipelines.count }.by(1) .to change { @merge_request.merge_request_pipelines.count }.by(1)
.and change { @fork_merge_request.merge_request_pipelines.count }.by(1) .and change { @fork_merge_request.merge_request_pipelines.count }.by(1)
...@@ -176,7 +176,34 @@ describe MergeRequests::RefreshService do ...@@ -176,7 +176,34 @@ describe MergeRequests::RefreshService do
expect(@another_merge_request.has_commits?).to be_falsy expect(@another_merge_request.has_commits?).to be_falsy
end end
context "when branch pipeline was created before a merge request pipline has been created" do it 'create detached merge request pipeline for non-fork merge request' do
subject
expect(@merge_request.merge_request_pipelines.first)
.to be_detached_merge_request_pipeline
end
it 'create legacy detached merge request pipeline for fork merge request' do
subject
expect(@fork_merge_request.merge_request_pipelines.first)
.to be_legacy_detached_merge_request_pipeline
end
context 'when ci_use_merge_request_ref feature flag is false' do
before do
stub_feature_flags(ci_use_merge_request_ref: false)
end
it 'create legacy detached merge request pipeline for non-fork merge request' do
subject
expect(@merge_request.merge_request_pipelines.first)
.to be_legacy_detached_merge_request_pipeline
end
end
context "when branch pipeline was created before a detaced merge request pipeline has been created" do
before do before do
create(:ci_pipeline, project: @merge_request.source_project, create(:ci_pipeline, project: @merge_request.source_project,
sha: @merge_request.diff_head_sha, sha: @merge_request.diff_head_sha,
...@@ -186,7 +213,7 @@ describe MergeRequests::RefreshService do ...@@ -186,7 +213,7 @@ describe MergeRequests::RefreshService do
subject subject
end end
it 'sets the latest merge request pipeline as a head pipeline' do it 'sets the latest detached merge request pipeline as a head pipeline' do
@merge_request.reload @merge_request.reload
expect(@merge_request.actual_head_pipeline).to be_merge_request_event expect(@merge_request.actual_head_pipeline).to be_merge_request_event
end end
...@@ -199,7 +226,7 @@ describe MergeRequests::RefreshService do ...@@ -199,7 +226,7 @@ describe MergeRequests::RefreshService do
end end
context "when MergeRequestUpdateWorker is retried by an exception" do context "when MergeRequestUpdateWorker is retried by an exception" do
it 'does not re-create a duplicate merge request pipeline' do it 'does not re-create a duplicate detached merge request pipeline' do
expect do expect do
service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/master') service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/master')
end.to change { @merge_request.merge_request_pipelines.count }.by(1) end.to change { @merge_request.merge_request_pipelines.count }.by(1)
...@@ -215,7 +242,7 @@ describe MergeRequests::RefreshService do ...@@ -215,7 +242,7 @@ describe MergeRequests::RefreshService do
stub_feature_flags(ci_merge_request_pipeline: false) stub_feature_flags(ci_merge_request_pipeline: false)
end end
it 'does not create a merge request pipeline' do it 'does not create a detached merge request pipeline' do
expect { subject } expect { subject }
.not_to change { @merge_request.merge_request_pipelines.count } .not_to change { @merge_request.merge_request_pipelines.count }
end end
...@@ -232,7 +259,7 @@ describe MergeRequests::RefreshService do ...@@ -232,7 +259,7 @@ describe MergeRequests::RefreshService do
} }
end end
it 'does not create a merge request pipeline' do it 'does not create a detached merge request pipeline' do
expect { subject } expect { subject }
.not_to change { @merge_request.merge_request_pipelines.count } .not_to change { @merge_request.merge_request_pipelines.count }
end end
......
# Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb
module StubWorker
def stub_worker(queue:)
Class.new do
include Sidekiq::Worker
sidekiq_options queue: queue
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment