Extract scoped CI/CD variables to a separate concern
This commits extract code responsible for calculating essential CI/CD variables to a separate concern. This makes it possible to share this code between a `Ci::Build` and a `Ci::Bridge`. We might want to refactor this to use composition instead of inheritance.
This commit is contained in:
parent
981c248863
commit
552a32c015
|
@ -3,6 +3,7 @@
|
|||
module Ci
|
||||
class Bridge < CommitStatus
|
||||
include Ci::Processable
|
||||
include Ci::Contextable
|
||||
include Importable
|
||||
include AfterCommitQueue
|
||||
include HasRef
|
||||
|
@ -12,6 +13,8 @@ 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
|
||||
|
@ -38,11 +41,11 @@ module Ci
|
|||
false
|
||||
end
|
||||
|
||||
def expanded_environment_name
|
||||
def runnable?
|
||||
false
|
||||
end
|
||||
|
||||
def predefined_variables
|
||||
raise NotImplementedError
|
||||
def expanded_environment_name
|
||||
end
|
||||
|
||||
def execute_hooks
|
||||
|
|
|
@ -5,6 +5,7 @@ module Ci
|
|||
prepend ArtifactMigratable
|
||||
include Ci::Processable
|
||||
include Ci::Metadatable
|
||||
include Ci::Contextable
|
||||
include TokenAuthenticatable
|
||||
include AfterCommitQueue
|
||||
include ObjectStorage::BackgroundMove
|
||||
|
@ -289,6 +290,10 @@ module Ci
|
|||
self.name == 'pages'
|
||||
end
|
||||
|
||||
def runnable?
|
||||
true
|
||||
end
|
||||
|
||||
def archived?
|
||||
return true if degenerated?
|
||||
|
||||
|
@ -398,35 +403,6 @@ module Ci
|
|||
options&.dig(:environment, :on_stop)
|
||||
end
|
||||
|
||||
##
|
||||
# Variables in the environment name scope.
|
||||
#
|
||||
def scoped_variables(environment: expanded_environment_name)
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
variables.concat(predefined_variables)
|
||||
variables.concat(project.predefined_variables)
|
||||
variables.concat(pipeline.predefined_variables)
|
||||
variables.concat(runner.predefined_variables) if runner
|
||||
variables.concat(project.deployment_variables(environment: environment)) if environment
|
||||
variables.concat(yaml_variables)
|
||||
variables.concat(user_variables)
|
||||
variables.concat(secret_group_variables)
|
||||
variables.concat(secret_project_variables(environment: environment))
|
||||
variables.concat(trigger_request.user_variables) if trigger_request
|
||||
variables.concat(pipeline.variables)
|
||||
variables.concat(pipeline.pipeline_schedule.job_variables) if pipeline.pipeline_schedule
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Variables that do not depend on the environment name.
|
||||
#
|
||||
def simple_variables
|
||||
strong_memoize(:simple_variables) do
|
||||
scoped_variables(environment: nil).to_runner_variables
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# All variables, including persisted environment variables.
|
||||
#
|
||||
|
@ -440,12 +416,46 @@ module Ci
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Regular Ruby hash of scoped variables, without duplicates that are
|
||||
# possible to be present in an array of hashes returned from `variables`.
|
||||
#
|
||||
def scoped_variables_hash
|
||||
scoped_variables.to_hash
|
||||
CI_REGISTRY_USER = 'gitlab-ci-token'.freeze
|
||||
|
||||
def persisted_variables
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
break variables unless persisted?
|
||||
|
||||
variables
|
||||
.concat(pipeline.persisted_variables)
|
||||
.append(key: 'CI_JOB_ID', value: id.to_s)
|
||||
.append(key: 'CI_JOB_URL', value: Gitlab::Routing.url_helpers.project_job_url(project, self))
|
||||
.append(key: 'CI_JOB_TOKEN', value: token.to_s, public: false)
|
||||
.append(key: 'CI_BUILD_ID', value: id.to_s)
|
||||
.append(key: 'CI_BUILD_TOKEN', value: token.to_s, public: false)
|
||||
.append(key: 'CI_REGISTRY_USER', value: CI_REGISTRY_USER)
|
||||
.append(key: 'CI_REGISTRY_PASSWORD', value: token.to_s, public: false)
|
||||
.append(key: 'CI_REPOSITORY_URL', value: repo_url.to_s, public: false)
|
||||
.concat(deploy_token_variables)
|
||||
end
|
||||
end
|
||||
|
||||
def persisted_environment_variables
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
break variables unless persisted? && persisted_environment.present?
|
||||
|
||||
variables.concat(persisted_environment.predefined_variables)
|
||||
|
||||
# Here we're passing unexpanded environment_url for runner to expand,
|
||||
# and we need to make sure that CI_ENVIRONMENT_NAME and
|
||||
# CI_ENVIRONMENT_SLUG so on are available for the URL be expanded.
|
||||
variables.append(key: 'CI_ENVIRONMENT_URL', value: environment_url) if environment_url
|
||||
end
|
||||
end
|
||||
|
||||
def deploy_token_variables
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
break variables unless gitlab_deploy_token
|
||||
|
||||
variables.append(key: 'CI_DEPLOY_USER', value: gitlab_deploy_token.username)
|
||||
variables.append(key: 'CI_DEPLOY_PASSWORD', value: gitlab_deploy_token.token, public: false)
|
||||
end
|
||||
end
|
||||
|
||||
def features
|
||||
|
@ -623,27 +633,6 @@ module Ci
|
|||
super || project.try(:build_coverage_regex)
|
||||
end
|
||||
|
||||
def user_variables
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
break variables if user.blank?
|
||||
|
||||
variables.append(key: 'GITLAB_USER_ID', value: user.id.to_s)
|
||||
variables.append(key: 'GITLAB_USER_EMAIL', value: user.email)
|
||||
variables.append(key: 'GITLAB_USER_LOGIN', value: user.username)
|
||||
variables.append(key: 'GITLAB_USER_NAME', value: user.name)
|
||||
end
|
||||
end
|
||||
|
||||
def secret_group_variables
|
||||
return [] unless project.group
|
||||
|
||||
project.group.ci_variables_for(git_ref, project)
|
||||
end
|
||||
|
||||
def secret_project_variables(environment: persisted_environment)
|
||||
project.ci_variables_for(ref: git_ref, environment: environment)
|
||||
end
|
||||
|
||||
def steps
|
||||
[Gitlab::Ci::Build::Step.from_commands(self),
|
||||
Gitlab::Ci::Build::Step.from_after_script(self)].compact
|
||||
|
@ -803,89 +792,6 @@ module Ci
|
|||
@unscoped_project ||= Project.unscoped.find_by(id: project_id)
|
||||
end
|
||||
|
||||
CI_REGISTRY_USER = 'gitlab-ci-token'.freeze
|
||||
|
||||
def persisted_variables
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
break variables unless persisted?
|
||||
|
||||
variables
|
||||
.concat(pipeline.persisted_variables)
|
||||
.append(key: 'CI_JOB_ID', value: id.to_s)
|
||||
.append(key: 'CI_JOB_URL', value: Gitlab::Routing.url_helpers.project_job_url(project, self))
|
||||
.append(key: 'CI_JOB_TOKEN', value: token.to_s, public: false)
|
||||
.append(key: 'CI_BUILD_ID', value: id.to_s)
|
||||
.append(key: 'CI_BUILD_TOKEN', value: token.to_s, public: false)
|
||||
.append(key: 'CI_REGISTRY_USER', value: CI_REGISTRY_USER)
|
||||
.append(key: 'CI_REGISTRY_PASSWORD', value: token.to_s, public: false)
|
||||
.append(key: 'CI_REPOSITORY_URL', value: repo_url.to_s, public: false)
|
||||
.concat(deploy_token_variables)
|
||||
end
|
||||
end
|
||||
|
||||
def predefined_variables # rubocop:disable Metrics/AbcSize
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
variables.append(key: 'CI', value: 'true')
|
||||
variables.append(key: 'GITLAB_CI', value: 'true')
|
||||
variables.append(key: 'GITLAB_FEATURES', value: project.licensed_features.join(','))
|
||||
variables.append(key: 'CI_SERVER_NAME', value: 'GitLab')
|
||||
variables.append(key: 'CI_SERVER_VERSION', value: Gitlab::VERSION)
|
||||
variables.append(key: 'CI_SERVER_VERSION_MAJOR', value: Gitlab.version_info.major.to_s)
|
||||
variables.append(key: 'CI_SERVER_VERSION_MINOR', value: Gitlab.version_info.minor.to_s)
|
||||
variables.append(key: 'CI_SERVER_VERSION_PATCH', value: Gitlab.version_info.patch.to_s)
|
||||
variables.append(key: 'CI_SERVER_REVISION', value: Gitlab.revision)
|
||||
variables.append(key: 'CI_JOB_NAME', value: name)
|
||||
variables.append(key: 'CI_JOB_STAGE', value: stage)
|
||||
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_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?
|
||||
variables.append(key: "CI_NODE_INDEX", value: self.options[:instance].to_s) if self.options&.include?(:instance)
|
||||
variables.append(key: "CI_NODE_TOTAL", value: (self.options&.dig(:parallel) || 1).to_s)
|
||||
variables.concat(legacy_variables)
|
||||
end
|
||||
end
|
||||
|
||||
def legacy_variables
|
||||
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_NAME', value: name)
|
||||
variables.append(key: 'CI_BUILD_STAGE', value: stage)
|
||||
variables.append(key: "CI_BUILD_TAG", value: ref) if tag?
|
||||
variables.append(key: "CI_BUILD_TRIGGERED", value: 'true') if trigger_request
|
||||
variables.append(key: "CI_BUILD_MANUAL", value: 'true') if action?
|
||||
end
|
||||
end
|
||||
|
||||
def persisted_environment_variables
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
break variables unless persisted? && persisted_environment.present?
|
||||
|
||||
variables.concat(persisted_environment.predefined_variables)
|
||||
|
||||
# Here we're passing unexpanded environment_url for runner to expand,
|
||||
# and we need to make sure that CI_ENVIRONMENT_NAME and
|
||||
# CI_ENVIRONMENT_SLUG so on are available for the URL be expanded.
|
||||
variables.append(key: 'CI_ENVIRONMENT_URL', value: environment_url) if environment_url
|
||||
end
|
||||
end
|
||||
|
||||
def deploy_token_variables
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
break variables unless gitlab_deploy_token
|
||||
|
||||
variables.append(key: 'CI_DEPLOY_USER', value: gitlab_deploy_token.username)
|
||||
variables.append(key: 'CI_DEPLOY_PASSWORD', value: gitlab_deploy_token.token, public: false)
|
||||
end
|
||||
end
|
||||
|
||||
def environment_url
|
||||
options&.dig(:environment, :url) || persisted_environment&.external_url
|
||||
end
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Ci
|
||||
##
|
||||
# This module implements methods that provide context in form of
|
||||
# essential CI/CD variables that can be used by a build / bridge job.
|
||||
#
|
||||
module Contextable
|
||||
##
|
||||
# Variables in the environment name scope.
|
||||
#
|
||||
def scoped_variables(environment: expanded_environment_name)
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
variables.concat(predefined_variables)
|
||||
variables.concat(project.predefined_variables)
|
||||
variables.concat(pipeline.predefined_variables)
|
||||
variables.concat(runner.predefined_variables) if runnable? && runner
|
||||
variables.concat(project.deployment_variables(environment: environment)) if environment
|
||||
variables.concat(yaml_variables)
|
||||
variables.concat(user_variables)
|
||||
variables.concat(secret_group_variables)
|
||||
variables.concat(secret_project_variables(environment: environment))
|
||||
variables.concat(trigger_request.user_variables) if trigger_request
|
||||
variables.concat(pipeline.variables)
|
||||
variables.concat(pipeline.pipeline_schedule.job_variables) if pipeline.pipeline_schedule
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Regular Ruby hash of scoped variables, without duplicates that are
|
||||
# possible to be present in an array of hashes returned from `variables`.
|
||||
#
|
||||
def scoped_variables_hash
|
||||
scoped_variables.to_hash
|
||||
end
|
||||
|
||||
##
|
||||
# Variables that do not depend on the environment name.
|
||||
#
|
||||
def simple_variables
|
||||
strong_memoize(:simple_variables) do
|
||||
scoped_variables(environment: nil).to_runner_variables
|
||||
end
|
||||
end
|
||||
|
||||
def user_variables
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
break variables if user.blank?
|
||||
|
||||
variables.append(key: 'GITLAB_USER_ID', value: user.id.to_s)
|
||||
variables.append(key: 'GITLAB_USER_EMAIL', value: user.email)
|
||||
variables.append(key: 'GITLAB_USER_LOGIN', value: user.username)
|
||||
variables.append(key: 'GITLAB_USER_NAME', value: user.name)
|
||||
end
|
||||
end
|
||||
|
||||
def predefined_variables # rubocop:disable Metrics/AbcSize
|
||||
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
||||
variables.append(key: 'CI', value: 'true')
|
||||
variables.append(key: 'GITLAB_CI', value: 'true')
|
||||
variables.append(key: 'GITLAB_FEATURES', value: project.licensed_features.join(','))
|
||||
variables.append(key: 'CI_SERVER_NAME', value: 'GitLab')
|
||||
variables.append(key: 'CI_SERVER_VERSION', value: Gitlab::VERSION)
|
||||
variables.append(key: 'CI_SERVER_VERSION_MAJOR', value: Gitlab.version_info.major.to_s)
|
||||
variables.append(key: 'CI_SERVER_VERSION_MINOR', value: Gitlab.version_info.minor.to_s)
|
||||
variables.append(key: 'CI_SERVER_VERSION_PATCH', value: Gitlab.version_info.patch.to_s)
|
||||
variables.append(key: 'CI_SERVER_REVISION', value: Gitlab.revision)
|
||||
variables.append(key: 'CI_JOB_NAME', value: name)
|
||||
variables.append(key: 'CI_JOB_STAGE', value: stage)
|
||||
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_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?
|
||||
variables.append(key: "CI_NODE_INDEX", value: self.options[:instance].to_s) if self.options&.include?(:instance)
|
||||
variables.append(key: "CI_NODE_TOTAL", value: (self.options&.dig(:parallel) || 1).to_s)
|
||||
variables.concat(legacy_variables)
|
||||
end
|
||||
end
|
||||
|
||||
def legacy_variables
|
||||
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_NAME', value: name)
|
||||
variables.append(key: 'CI_BUILD_STAGE', value: stage)
|
||||
variables.append(key: "CI_BUILD_TAG", value: ref) if tag?
|
||||
variables.append(key: "CI_BUILD_TRIGGERED", value: 'true') if trigger_request
|
||||
variables.append(key: "CI_BUILD_MANUAL", value: 'true') if action?
|
||||
end
|
||||
end
|
||||
|
||||
def secret_group_variables
|
||||
return [] unless project.group
|
||||
|
||||
project.group.ci_variables_for(git_ref, project)
|
||||
end
|
||||
|
||||
def secret_project_variables(environment: persisted_environment)
|
||||
project.ci_variables_for(ref: git_ref, environment: environment)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,4 +22,25 @@ describe Ci::Bridge do
|
|||
expect(status).to be_a Gitlab::Ci::Status::Success
|
||||
end
|
||||
end
|
||||
|
||||
describe '#scoped_variables_hash' do
|
||||
it 'returns a hash representing variables' do
|
||||
expect(bridge.scoped_variables_hash.keys).to eq %w[
|
||||
CI GITLAB_CI GITLAB_FEATURES CI_SERVER_NAME
|
||||
CI_SERVER_VERSION CI_SERVER_VERSION_MAJOR
|
||||
CI_SERVER_VERSION_MINOR CI_SERVER_VERSION_PATCH
|
||||
CI_SERVER_REVISION CI_JOB_NAME CI_JOB_STAGE
|
||||
CI_COMMIT_SHA CI_COMMIT_SHORT_SHA CI_COMMIT_BEFORE_SHA
|
||||
CI_COMMIT_REF_NAME CI_COMMIT_REF_SLUG CI_NODE_TOTAL
|
||||
CI_BUILD_REF CI_BUILD_BEFORE_SHA CI_BUILD_REF_NAME
|
||||
CI_BUILD_REF_SLUG CI_BUILD_NAME CI_BUILD_STAGE
|
||||
CI_PROJECT_ID CI_PROJECT_NAME CI_PROJECT_PATH
|
||||
CI_PROJECT_PATH_SLUG CI_PROJECT_NAMESPACE CI_PROJECT_URL
|
||||
CI_PROJECT_VISIBILITY CI_PAGES_DOMAIN CI_PAGES_URL
|
||||
CI_REGISTRY CI_REGISTRY_IMAGE CI_API_V4_URL
|
||||
CI_PIPELINE_IID CI_CONFIG_PATH CI_PIPELINE_SOURCE
|
||||
CI_COMMIT_MESSAGE CI_COMMIT_TITLE CI_COMMIT_DESCRIPTION
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue