diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 6b2b7e77180..c902e49ee6d 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -46,6 +46,7 @@ module Ci delegate :terminal_specification, to: :runner_session, allow_nil: true delegate :gitlab_deploy_token, to: :project delegate :trigger_short_token, to: :trigger_request, allow_nil: true + delegate :merge_request?, to: :pipeline ## # Since Gitlab 11.5, deployments records started being created right after @@ -441,11 +442,13 @@ module Ci # All variables, including persisted environment variables. # def variables - Gitlab::Ci::Variables::Collection.new - .concat(persisted_variables) - .concat(scoped_variables) - .concat(persisted_environment_variables) - .to_runner_variables + strong_memoize(:variables) do + Gitlab::Ci::Variables::Collection.new + .concat(persisted_variables) + .concat(scoped_variables) + .concat(persisted_environment_variables) + .to_runner_variables + end end ## diff --git a/app/presenters/ci/build_runner_presenter.rb b/app/presenters/ci/build_runner_presenter.rb index 300f85e1e9d..d60281c8a0b 100644 --- a/app/presenters/ci/build_runner_presenter.rb +++ b/app/presenters/ci/build_runner_presenter.rb @@ -2,6 +2,11 @@ module Ci class BuildRunnerPresenter < SimpleDelegator + include Gitlab::Utils::StrongMemoize + + RUNNER_REMOTE_TAG_PREFIX = 'refs/tags/'.freeze + RUNNER_REMOTE_BRANCH_PREFIX = 'refs/remotes/origin/'.freeze + def artifacts return unless options[:artifacts] @@ -11,6 +16,35 @@ module Ci list.flatten.compact end + def ref_type + if tag + 'tag' + else + 'branch' + end + end + + def git_depth + strong_memoize(:git_depth) do + git_depth = variables&.find { |variable| variable[:key] == 'GIT_DEPTH' }&.dig(:value) + git_depth.to_i + end + end + + def refspecs + specs = [] + + if git_depth > 0 + specs << refspec_for_branch(ref) if branch? || merge_request? + specs << refspec_for_tag(ref) if tag? + else + specs << refspec_for_branch + specs << refspec_for_tag + end + + specs + end + private def create_archive(artifacts) @@ -41,5 +75,13 @@ module Ci } end end + + def refspec_for_branch(ref = '*') + "+#{Gitlab::Git::BRANCH_REF_PREFIX}#{ref}:#{RUNNER_REMOTE_BRANCH_PREFIX}#{ref}" + end + + def refspec_for_tag(ref = '*') + "+#{Gitlab::Git::TAG_REF_PREFIX}#{ref}:#{RUNNER_REMOTE_TAG_PREFIX}#{ref}" + end end end diff --git a/changelogs/unreleased/expose-merge-ref-to-runner.yml b/changelogs/unreleased/expose-merge-ref-to-runner.yml new file mode 100644 index 00000000000..945f4f6e05a --- /dev/null +++ b/changelogs/unreleased/expose-merge-ref-to-runner.yml @@ -0,0 +1,5 @@ +--- +title: Expose refspecs and depth to runner +merge_request: 25233 +author: +type: added diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 9199f898ea0..7c035990fb0 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1385,13 +1385,9 @@ module API class GitInfo < Grape::Entity expose :repo_url, :ref, :sha, :before_sha - expose :ref_type do |model| - if model.tag - 'tag' - else - 'branch' - end - end + expose :ref_type + expose :refspecs + expose :git_depth, as: :depth end class RunnerInfo < Grape::Entity diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 47865e4d08f..17540443688 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -23,6 +23,7 @@ describe Ci::Build do it { is_expected.to validate_presence_of(:ref) } it { is_expected.to respond_to(:has_trace?) } it { is_expected.to respond_to(:trace) } + it { is_expected.to delegate_method(:merge_request?).to(:pipeline) } it { is_expected.to be_a(ArtifactMigratable) } diff --git a/spec/presenters/ci/build_runner_presenter_spec.rb b/spec/presenters/ci/build_runner_presenter_spec.rb index 170e0ac5717..f50bcf54b46 100644 --- a/spec/presenters/ci/build_runner_presenter_spec.rb +++ b/spec/presenters/ci/build_runner_presenter_spec.rb @@ -98,4 +98,72 @@ describe Ci::BuildRunnerPresenter do end end end + + describe '#ref_type' do + subject { presenter.ref_type } + + let(:build) { create(:ci_build, tag: tag) } + let(:tag) { true } + + it 'returns the correct ref type' do + is_expected.to eq('tag') + end + + context 'when tag is false' do + let(:tag) { false } + + it 'returns the correct ref type' do + is_expected.to eq('branch') + end + end + end + + describe '#git_depth' do + subject { presenter.git_depth } + + let(:build) { create(:ci_build) } + + it 'returns the correct git depth' do + is_expected.to eq(0) + end + + context 'when GIT_DEPTH variable is specified' do + before do + create(:ci_pipeline_variable, key: 'GIT_DEPTH', value: 1, pipeline: build.pipeline) + end + + it 'returns the correct git depth' do + is_expected.to eq(1) + end + end + end + + describe '#refspecs' do + subject { presenter.refspecs } + + let(:build) { create(:ci_build) } + + it 'returns the correct refspecs' do + is_expected.to contain_exactly('+refs/tags/*:refs/tags/*', + '+refs/heads/*:refs/remotes/origin/*') + end + + context 'when GIT_DEPTH variable is specified' do + before do + create(:ci_pipeline_variable, key: 'GIT_DEPTH', value: 1, pipeline: build.pipeline) + end + + it 'returns the correct refspecs' do + is_expected.to contain_exactly("+refs/heads/#{build.ref}:refs/remotes/origin/#{build.ref}") + end + + context 'when ref is tag' do + let(:build) { create(:ci_build, :tag) } + + it 'returns the correct refspecs' do + is_expected.to contain_exactly("+refs/tags/#{build.ref}:refs/tags/#{build.ref}") + end + end + end + end end diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb index d7ddd97e8c8..42e9e28406c 100644 --- a/spec/requests/api/runner_spec.rb +++ b/spec/requests/api/runner_spec.rb @@ -417,7 +417,9 @@ describe API::Runner, :clean_gitlab_redis_shared_state do 'ref' => job.ref, 'sha' => job.sha, 'before_sha' => job.before_sha, - 'ref_type' => 'branch' } + 'ref_type' => 'branch', + 'refspecs' => %w[+refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/*], + 'depth' => 0 } end let(:expected_steps) do @@ -489,6 +491,29 @@ describe API::Runner, :clean_gitlab_redis_shared_state do expect(response).to have_gitlab_http_status(201) expect(json_response['git_info']['ref_type']).to eq('tag') end + + context 'when GIT_DEPTH is specified' do + before do + create(:ci_pipeline_variable, key: 'GIT_DEPTH', value: 1, pipeline: pipeline) + end + + it 'specifies refspecs' do + request_job + + expect(response).to have_gitlab_http_status(201) + expect(json_response['git_info']['refspecs']).to include("+refs/tags/#{job.ref}:refs/tags/#{job.ref}") + end + end + + context 'when GIT_DEPTH is not specified' do + it 'specifies refspecs' do + request_job + + expect(response).to have_gitlab_http_status(201) + expect(json_response['git_info']['refspecs']) + .to contain_exactly('+refs/tags/*:refs/tags/*', '+refs/heads/*:refs/remotes/origin/*') + end + end end context 'when job is made for branch' do @@ -498,6 +523,55 @@ describe API::Runner, :clean_gitlab_redis_shared_state do expect(response).to have_gitlab_http_status(201) expect(json_response['git_info']['ref_type']).to eq('branch') end + + context 'when GIT_DEPTH is specified' do + before do + create(:ci_pipeline_variable, key: 'GIT_DEPTH', value: 1, pipeline: pipeline) + end + + it 'specifies refspecs' do + request_job + + expect(response).to have_gitlab_http_status(201) + expect(json_response['git_info']['refspecs']).to include("+refs/heads/#{job.ref}:refs/remotes/origin/#{job.ref}") + end + end + + context 'when GIT_DEPTH is not specified' do + it 'specifies refspecs' do + request_job + + expect(response).to have_gitlab_http_status(201) + expect(json_response['git_info']['refspecs']) + .to contain_exactly('+refs/tags/*:refs/tags/*', '+refs/heads/*:refs/remotes/origin/*') + end + end + end + + context 'when job is made for merge request' do + let(:pipeline) { create(:ci_pipeline_without_jobs, source: :merge_request, project: project, ref: 'feature', merge_request: merge_request) } + let!(:job) { create(:ci_build, pipeline: pipeline, name: 'spinach', ref: 'feature', stage: 'test', stage_idx: 0) } + let(:merge_request) { create(:merge_request) } + + it 'sets branch as ref_type' do + request_job + + expect(response).to have_gitlab_http_status(201) + expect(json_response['git_info']['ref_type']).to eq('branch') + end + + context 'when GIT_DEPTH is specified' do + before do + create(:ci_pipeline_variable, key: 'GIT_DEPTH', value: 1, pipeline: pipeline) + end + + it 'returns the overwritten git depth for merge request refspecs' do + request_job + + expect(response).to have_gitlab_http_status(201) + expect(json_response['git_info']['depth']).to eq(1) + end + end end it 'updates runner info' do