summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShinya Maeda <shinya@gitlab.com>2019-04-25 15:23:39 +0700
committerShinya Maeda <shinya@gitlab.com>2019-04-29 18:52:51 +0700
commited3a2fc8d7fef157706859dd009e1662fdc3d4b5 (patch)
tree6468ddc17f339ce41b7c00648020b75a615f9bef
parentddee4426c4bd3df8bde7936a6ffb0a1973a4d5a1 (diff)
downloadgitlab-ce-ed3a2fc8d7fef157706859dd009e1662fdc3d4b5.tar.gz
Fix CI_COMMIT_REF_NAME and SLUG variable
With Pipelines for Merge Requests feature, users cannout keep using $CI_COMMIT_REF_NAME and _SLUG predefined variables for dynamic environments. We fix this problem by explicitly looking at the source ref.
-rw-r--r--app/models/ci/bridge.rb3
-rw-r--r--app/models/ci/build.rb3
-rw-r--r--app/models/ci/pipeline.rb12
-rw-r--r--app/models/concerns/ci/contextable.rb8
-rw-r--r--app/models/concerns/ci/pipeline_delegator.rb21
-rw-r--r--app/models/concerns/has_ref.rb3
-rw-r--r--changelogs/unreleased/fix-ci-commit-ref-name-and-slug.yml5
-rw-r--r--spec/models/ci/bridge_spec.rb2
-rw-r--r--spec/models/ci/build_spec.rb18
-rw-r--r--spec/models/ci/pipeline_spec.rb48
10 files changed, 115 insertions, 8 deletions
diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb
index 0d8d7d95791..644716ba8e7 100644
--- a/app/models/ci/bridge.rb
+++ b/app/models/ci/bridge.rb
@@ -4,6 +4,7 @@ module Ci
class Bridge < CommitStatus
include Ci::Processable
include Ci::Contextable
+ include Ci::PipelineDelegator
include Importable
include AfterCommitQueue
include HasRef
@@ -13,8 +14,6 @@ module Ci
belongs_to :trigger_request
validates :ref, presence: true
- delegate :merge_request_event?, to: :pipeline
-
def self.retry(bridge, current_user)
raise NotImplementedError
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index e5236051118..5a2ead41578 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -6,6 +6,7 @@ module Ci
include Ci::Processable
include Ci::Metadatable
include Ci::Contextable
+ include Ci::PipelineDelegator
include TokenAuthenticatable
include AfterCommitQueue
include ObjectStorage::BackgroundMove
@@ -49,8 +50,6 @@ 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_event?, :merge_request_ref?,
- :legacy_detached_merge_request_pipeline?, to: :pipeline
##
# Since Gitlab 11.5, deployments records started being created right after
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index bbd21eb0e78..2b7835d7fab 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -759,6 +759,18 @@ module Ci
user == current_user
end
+ def source_ref
+ if triggered_by_merge_request?
+ merge_request.source_branch
+ else
+ ref
+ end
+ end
+
+ def source_ref_slug
+ Gitlab::Utils.slugify(source_ref.to_s)
+ end
+
private
def ci_yaml_from_repo
diff --git a/app/models/concerns/ci/contextable.rb b/app/models/concerns/ci/contextable.rb
index 4986a42dbd2..e1d5ce7f7d4 100644
--- a/app/models/concerns/ci/contextable.rb
+++ b/app/models/concerns/ci/contextable.rb
@@ -70,8 +70,8 @@ module Ci
variables.append(key: 'CI_COMMIT_SHA', value: sha)
variables.append(key: 'CI_COMMIT_SHORT_SHA', value: short_sha)
variables.append(key: 'CI_COMMIT_BEFORE_SHA', value: before_sha)
- variables.append(key: 'CI_COMMIT_REF_NAME', value: ref)
- variables.append(key: 'CI_COMMIT_REF_SLUG', value: ref_slug)
+ variables.append(key: 'CI_COMMIT_REF_NAME', value: source_ref)
+ variables.append(key: 'CI_COMMIT_REF_SLUG', value: source_ref_slug)
variables.append(key: "CI_COMMIT_TAG", value: ref) if tag?
variables.append(key: "CI_PIPELINE_TRIGGERED", value: 'true') if trigger_request
variables.append(key: "CI_JOB_MANUAL", value: 'true') if action?
@@ -85,8 +85,8 @@ module Ci
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'CI_BUILD_REF', value: sha)
variables.append(key: 'CI_BUILD_BEFORE_SHA', value: before_sha)
- variables.append(key: 'CI_BUILD_REF_NAME', value: ref)
- variables.append(key: 'CI_BUILD_REF_SLUG', value: ref_slug)
+ variables.append(key: 'CI_BUILD_REF_NAME', value: source_ref)
+ variables.append(key: 'CI_BUILD_REF_SLUG', value: source_ref_slug)
variables.append(key: 'CI_BUILD_NAME', value: name)
variables.append(key: 'CI_BUILD_STAGE', value: stage)
variables.append(key: "CI_BUILD_TAG", value: ref) if tag?
diff --git a/app/models/concerns/ci/pipeline_delegator.rb b/app/models/concerns/ci/pipeline_delegator.rb
new file mode 100644
index 00000000000..dbc5ed1bc9a
--- /dev/null
+++ b/app/models/concerns/ci/pipeline_delegator.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+##
+# This module is mainly used by child associations of `Ci::Pipeline` that needs to look up
+# single source of truth. For example, `Ci::Build` has `git_ref` method, which behaves
+# slightly different from `Ci::Pipeline`'s `git_ref`. This is very confusing as
+# the system could behave differently time to time.
+# We should have a single interface in `Ci::Pipeline` and access the method always.
+module Ci
+ module PipelineDelegator
+ extend ActiveSupport::Concern
+
+ included do
+ delegate :merge_request_event?,
+ :merge_request_ref?,
+ :source_ref,
+ :source_ref_slug,
+ :legacy_detached_merge_request_pipeline?, to: :pipeline
+ end
+ end
+end
diff --git a/app/models/concerns/has_ref.rb b/app/models/concerns/has_ref.rb
index 413cd36dcaa..fa0cf5ddfd2 100644
--- a/app/models/concerns/has_ref.rb
+++ b/app/models/concerns/has_ref.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+##
+# We will disable `ref` and `sha` attributes in `Ci::Build` in the future
+# and remove this module in favor of Ci::PipelineDelegator.
module HasRef
extend ActiveSupport::Concern
diff --git a/changelogs/unreleased/fix-ci-commit-ref-name-and-slug.yml b/changelogs/unreleased/fix-ci-commit-ref-name-and-slug.yml
new file mode 100644
index 00000000000..c34bc6d8b52
--- /dev/null
+++ b/changelogs/unreleased/fix-ci-commit-ref-name-and-slug.yml
@@ -0,0 +1,5 @@
+---
+title: Make `CI_COMMIT_REF_NAME` and `SLUG` variable idempotent
+merge_request: 27663
+author:
+type: fixed
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index 44b5af5e5aa..eb32198265b 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -10,6 +10,8 @@ describe Ci::Bridge do
create(:ci_bridge, pipeline: pipeline)
end
+ it { is_expected.to include_module(Ci::PipelineDelegator) }
+
describe '#tags' do
it 'only has a bridge tag' do
expect(bridge.tags).to eq [:bridge]
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 339483d4f7d..59ec7310391 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -28,6 +28,7 @@ describe Ci::Build do
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 include_module(Ci::PipelineDelegator) }
it { is_expected.to be_a(ArtifactMigratable) }
@@ -2273,6 +2274,19 @@ describe Ci::Build do
it { user_variables.each { |v| is_expected.to include(v) } }
end
+ context 'when build belongs to a pipeline for merge request' do
+ let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline, source_branch: 'improve/awesome') }
+ let(:pipeline) { merge_request.all_pipelines.first }
+ let(:build) { create(:ci_build, ref: pipeline.ref, pipeline: pipeline) }
+
+ it 'returns values based on source ref' do
+ is_expected.to include(
+ { key: 'CI_COMMIT_REF_NAME', value: 'improve/awesome', public: true, masked: false },
+ { key: 'CI_COMMIT_REF_SLUG', value: 'improve-awesome', public: true, masked: false }
+ )
+ end
+ end
+
context 'when build has an environment' do
let(:environment_variables) do
[
@@ -2664,6 +2678,8 @@ describe Ci::Build do
)
end
+ let(:pipeline) { create(:ci_pipeline, project: project, ref: 'feature') }
+
it 'returns static predefined variables' do
expect(build.variables.size).to be >= 28
expect(build.variables)
@@ -2713,6 +2729,8 @@ describe Ci::Build do
)
end
+ let(:pipeline) { create(:ci_pipeline, project: project, ref: 'feature') }
+
it 'does not persist the build' do
expect(build).to be_valid
expect(build).not_to be_persisted
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 3c823b78be7..9d0cd654f13 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -382,6 +382,54 @@ describe Ci::Pipeline, :mailer do
end
end
+ describe '#source_ref' do
+ subject { pipeline.source_ref }
+
+ let(:pipeline) { create(:ci_pipeline, ref: 'feature') }
+
+ it 'returns source ref' do
+ is_expected.to eq('feature')
+ end
+
+ context 'when the pipeline is a detached merge request pipeline' do
+ let(:merge_request) { create(:merge_request) }
+
+ let(:pipeline) do
+ create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, ref: merge_request.ref_path)
+ end
+
+ it 'returns source ref' do
+ is_expected.to eq(merge_request.source_branch)
+ end
+ end
+ end
+
+ describe '#source_ref_slug' do
+ subject { pipeline.source_ref_slug }
+
+ let(:pipeline) { create(:ci_pipeline, ref: 'feature') }
+
+ it 'slugifies with the source ref' do
+ expect(Gitlab::Utils).to receive(:slugify).with('feature')
+
+ subject
+ end
+
+ context 'when the pipeline is a detached merge request pipeline' do
+ let(:merge_request) { create(:merge_request) }
+
+ let(:pipeline) do
+ create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, ref: merge_request.ref_path)
+ end
+
+ it 'slugifies with the source ref of the merge request' do
+ expect(Gitlab::Utils).to receive(:slugify).with(merge_request.source_branch)
+
+ subject
+ end
+ end
+ end
+
describe '.triggered_for_branch' do
subject { described_class.triggered_for_branch(ref) }