2015-08-25 21:42:46 -04:00
|
|
|
module Ci
|
2015-10-06 06:01:16 -04:00
|
|
|
class Build < CommitStatus
|
2017-09-19 03:14:06 -04:00
|
|
|
prepend ArtifactMigratable
|
2016-08-08 06:01:25 -04:00
|
|
|
include TokenAuthenticatable
|
2016-10-13 06:45:16 -04:00
|
|
|
include AfterCommitQueue
|
2018-02-26 14:14:00 -05:00
|
|
|
include ObjectStorage::BackgroundMove
|
2017-01-09 15:47:15 -05:00
|
|
|
include Presentable
|
2017-09-01 04:54:07 -04:00
|
|
|
include Importable
|
2018-03-29 08:46:27 -04:00
|
|
|
include Gitlab::Utils::StrongMemoize
|
2016-08-08 06:01:25 -04:00
|
|
|
|
2018-01-14 02:18:50 -05:00
|
|
|
belongs_to :project, inverse_of: :builds
|
2016-10-18 17:20:36 -04:00
|
|
|
belongs_to :runner
|
|
|
|
belongs_to :trigger_request
|
2016-02-16 02:39:20 -05:00
|
|
|
belongs_to :erased_by, class_name: 'User'
|
2015-08-25 21:42:46 -04:00
|
|
|
|
2016-11-04 11:35:22 -04:00
|
|
|
has_many :deployments, as: :deployable
|
2017-09-21 04:34:12 -04:00
|
|
|
|
2018-07-30 11:26:56 -04:00
|
|
|
RUNNER_FEATURES = {
|
|
|
|
upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? }
|
|
|
|
}.freeze
|
|
|
|
|
2017-01-30 19:26:40 -05:00
|
|
|
has_one :last_deployment, -> { order('deployments.id DESC') }, as: :deployable, class_name: 'Deployment'
|
2017-09-25 12:54:08 -04:00
|
|
|
has_many :trace_sections, class_name: 'Ci::BuildTraceSection'
|
2018-04-26 04:25:20 -04:00
|
|
|
has_many :trace_chunks, class_name: 'Ci::BuildTraceChunk', foreign_key: :build_id
|
2016-11-04 11:35:22 -04:00
|
|
|
|
2018-03-20 19:03:50 -04:00
|
|
|
has_many :job_artifacts, class_name: 'Ci::JobArtifact', foreign_key: :job_id, dependent: :destroy, inverse_of: :job # rubocop:disable Cop/ActiveRecordDependent
|
2018-07-27 01:04:35 -04:00
|
|
|
|
|
|
|
Ci::JobArtifact.file_types.each do |key, value|
|
|
|
|
has_one :"job_artifacts_#{key}", -> { where(file_type: value) }, class_name: 'Ci::JobArtifact', inverse_of: :job, foreign_key: :job_id
|
|
|
|
end
|
2017-09-21 04:34:12 -04:00
|
|
|
|
2018-03-20 18:21:17 -04:00
|
|
|
has_one :metadata, class_name: 'Ci::BuildMetadata'
|
2018-07-05 09:55:10 -04:00
|
|
|
has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, inverse_of: :build
|
|
|
|
|
|
|
|
accepts_nested_attributes_for :runner_session
|
|
|
|
|
2018-03-26 13:26:52 -04:00
|
|
|
delegate :timeout, to: :metadata, prefix: true, allow_nil: true
|
2018-07-05 09:55:10 -04:00
|
|
|
delegate :url, to: :runner_session, prefix: true, allow_nil: true
|
|
|
|
delegate :terminal_specification, to: :runner_session, allow_nil: true
|
2018-04-19 11:31:46 -04:00
|
|
|
delegate :gitlab_deploy_token, to: :project
|
2018-03-26 13:26:52 -04:00
|
|
|
|
2018-03-27 07:05:29 -04:00
|
|
|
##
|
|
|
|
# The "environment" field for builds is a String, and is the unexpanded name!
|
|
|
|
#
|
2016-12-08 11:21:16 -05:00
|
|
|
def persisted_environment
|
2018-03-29 08:46:27 -04:00
|
|
|
return unless has_environment?
|
|
|
|
|
|
|
|
strong_memoize(:persisted_environment) do
|
|
|
|
Environment.find_by(name: expanded_environment_name, project: project)
|
|
|
|
end
|
2016-12-08 11:21:16 -05:00
|
|
|
end
|
|
|
|
|
2017-07-03 10:01:41 -04:00
|
|
|
serialize :options # rubocop:disable Cop/ActiveRecordSerialize
|
|
|
|
serialize :yaml_variables, Gitlab::Serializer::Ci::Variables # rubocop:disable Cop/ActiveRecordSerialize
|
2015-08-25 21:42:46 -04:00
|
|
|
|
2017-02-22 17:35:08 -05:00
|
|
|
delegate :name, to: :project, prefix: true
|
|
|
|
|
2015-08-25 21:42:46 -04:00
|
|
|
validates :coverage, numericality: true, allow_blank: true
|
2017-02-21 19:40:04 -05:00
|
|
|
validates :ref, presence: true
|
2015-08-25 21:42:46 -04:00
|
|
|
|
|
|
|
scope :unstarted, ->() { where(runner_id: nil) }
|
2015-10-02 07:46:38 -04:00
|
|
|
scope :ignore_failures, ->() { where(allow_failure: false) }
|
2018-03-15 05:03:37 -04:00
|
|
|
scope :with_artifacts_archive, ->() do
|
2018-02-16 17:19:22 -05:00
|
|
|
where('(artifacts_file IS NOT NULL AND artifacts_file <> ?) OR EXISTS (?)',
|
2018-03-15 05:03:37 -04:00
|
|
|
'', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').archive)
|
2017-09-21 04:34:12 -04:00
|
|
|
end
|
2018-06-03 01:21:50 -04:00
|
|
|
|
|
|
|
scope :without_archived_trace, ->() do
|
|
|
|
where('NOT EXISTS (?)', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').trace)
|
|
|
|
end
|
|
|
|
|
2018-03-22 09:06:10 -04:00
|
|
|
scope :with_artifacts_stored_locally, -> { with_artifacts_archive.where(artifacts_file_store: [nil, LegacyArtifactUploader::Store::LOCAL]) }
|
2018-03-15 05:03:37 -04:00
|
|
|
scope :with_artifacts_not_expired, ->() { with_artifacts_archive.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) }
|
|
|
|
scope :with_expired_artifacts, ->() { with_artifacts_archive.where('artifacts_expire_at < ?', Time.now) }
|
2016-07-07 06:56:02 -04:00
|
|
|
scope :last_month, ->() { where('created_at > ?', Date.today - 1.month) }
|
2017-06-13 04:17:11 -04:00
|
|
|
scope :manual_actions, ->() { where(when: :manual, status: COMPLETED_STATUSES + [:manual]) }
|
2017-08-29 02:56:03 -04:00
|
|
|
scope :ref_protected, -> { where(protected: true) }
|
2018-06-02 00:08:34 -04:00
|
|
|
scope :with_live_trace, -> { where('EXISTS (?)', Ci::BuildTraceChunk.where('ci_builds.id = ci_build_trace_chunks.build_id').select(1)) }
|
2017-07-31 10:25:11 -04:00
|
|
|
|
2017-11-30 17:17:41 -05:00
|
|
|
scope :matches_tag_ids, -> (tag_ids) do
|
|
|
|
matcher = ::ActsAsTaggableOn::Tagging
|
|
|
|
.where(taggable_type: CommitStatus)
|
|
|
|
.where(context: 'tags')
|
|
|
|
.where('taggable_id = ci_builds.id')
|
|
|
|
.where.not(tag_id: tag_ids).select('1')
|
|
|
|
|
|
|
|
where("NOT EXISTS (?)", matcher)
|
|
|
|
end
|
|
|
|
|
|
|
|
scope :with_any_tags, -> do
|
|
|
|
matcher = ::ActsAsTaggableOn::Tagging
|
|
|
|
.where(taggable_type: CommitStatus)
|
|
|
|
.where(context: 'tags')
|
|
|
|
.where('taggable_id = ci_builds.id').select('1')
|
|
|
|
|
|
|
|
where("EXISTS (?)", matcher)
|
|
|
|
end
|
|
|
|
|
2017-11-23 10:57:27 -05:00
|
|
|
mount_uploader :legacy_artifacts_file, LegacyArtifactUploader, mount_on: :artifacts_file
|
|
|
|
mount_uploader :legacy_artifacts_metadata, LegacyArtifactUploader, mount_on: :artifacts_metadata
|
2015-10-12 17:47:32 -04:00
|
|
|
|
2015-08-25 21:42:46 -04:00
|
|
|
acts_as_taggable
|
|
|
|
|
2016-08-08 06:01:25 -04:00
|
|
|
add_authentication_token_field :token
|
|
|
|
|
2016-06-29 05:44:39 -04:00
|
|
|
before_save :update_artifacts_size, if: :artifacts_file_changed?
|
2016-08-08 06:01:25 -04:00
|
|
|
before_save :ensure_token
|
2017-02-03 10:21:10 -05:00
|
|
|
before_destroy { unscoped_project }
|
2016-01-05 14:38:35 -05:00
|
|
|
|
2018-04-03 10:58:27 -04:00
|
|
|
before_create :ensure_metadata
|
2018-01-05 08:48:50 -05:00
|
|
|
after_create unless: :importing? do |build|
|
2017-08-23 02:32:44 -04:00
|
|
|
run_after_commit { BuildHooksWorker.perform_async(build.id) }
|
2017-08-22 04:57:52 -04:00
|
|
|
end
|
|
|
|
|
2018-03-20 19:03:50 -04:00
|
|
|
after_save :update_project_statistics_after_save, if: :artifacts_size_changed?
|
|
|
|
after_destroy :update_project_statistics_after_destroy, unless: :project_destroyed?
|
2015-08-25 21:42:46 -04:00
|
|
|
|
|
|
|
class << self
|
2017-05-16 07:41:15 -04:00
|
|
|
# This is needed for url_for to work,
|
|
|
|
# as the controller is JobsController
|
|
|
|
def model_name
|
|
|
|
ActiveModel::Name.new(self, nil, 'job')
|
|
|
|
end
|
|
|
|
|
2015-08-25 21:42:46 -04:00
|
|
|
def first_pending
|
|
|
|
pending.unstarted.order('created_at ASC').first
|
|
|
|
end
|
|
|
|
|
2017-02-13 07:01:52 -05:00
|
|
|
def retry(build, current_user)
|
2017-02-14 04:38:17 -05:00
|
|
|
Ci::RetryBuildService
|
|
|
|
.new(build.project, current_user)
|
|
|
|
.execute(build)
|
2015-08-25 21:42:46 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-08-11 09:22:35 -04:00
|
|
|
state_machine :status do
|
2017-03-03 08:35:19 -05:00
|
|
|
event :actionize do
|
|
|
|
transition created: :manual
|
2017-02-28 10:48:39 -05:00
|
|
|
end
|
|
|
|
|
2016-12-14 10:06:50 -05:00
|
|
|
after_transition any => [:pending] do |build|
|
|
|
|
build.run_after_commit do
|
2016-12-15 16:29:47 -05:00
|
|
|
BuildQueueWorker.perform_async(id)
|
2016-12-14 10:06:50 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-02-19 11:38:47 -05:00
|
|
|
after_transition pending: :running do |build|
|
2016-10-13 06:58:25 -04:00
|
|
|
build.run_after_commit do
|
|
|
|
BuildHooksWorker.perform_async(id)
|
|
|
|
end
|
2015-12-07 07:23:23 -05:00
|
|
|
end
|
|
|
|
|
2016-02-19 11:38:47 -05:00
|
|
|
after_transition any => [:success, :failed, :canceled] do |build|
|
2016-10-13 06:58:25 -04:00
|
|
|
build.run_after_commit do
|
2016-10-14 06:53:51 -04:00
|
|
|
BuildFinishedWorker.perform_async(id)
|
2016-10-13 06:58:25 -04:00
|
|
|
end
|
2015-08-25 21:42:46 -04:00
|
|
|
end
|
2016-06-10 17:36:54 -04:00
|
|
|
|
2016-06-14 08:44:09 -04:00
|
|
|
after_transition any => [:success] do |build|
|
2016-10-13 06:58:25 -04:00
|
|
|
build.run_after_commit do
|
|
|
|
BuildSuccessWorker.perform_async(id)
|
2018-06-04 15:49:39 -04:00
|
|
|
PagesWorker.perform_async(:deploy, id) if build.pages_generator?
|
2016-06-10 17:36:54 -04:00
|
|
|
end
|
|
|
|
end
|
2017-07-17 07:00:32 -04:00
|
|
|
|
2017-07-17 07:30:49 -04:00
|
|
|
before_transition any => [:failed] do |build|
|
2017-11-24 10:30:08 -05:00
|
|
|
next unless build.project
|
2017-07-17 07:30:49 -04:00
|
|
|
next if build.retries_max.zero?
|
2017-07-17 07:00:32 -04:00
|
|
|
|
2017-07-17 07:30:49 -04:00
|
|
|
if build.retries_count < build.retries_max
|
2018-03-19 09:17:46 -04:00
|
|
|
begin
|
|
|
|
Ci::Build.retry(build, build.user)
|
|
|
|
rescue Gitlab::Access::AccessDeniedError => ex
|
|
|
|
Rails.logger.error "Unable to auto-retry job #{build.id}: #{ex}"
|
|
|
|
end
|
2017-07-17 07:00:32 -04:00
|
|
|
end
|
|
|
|
end
|
2017-09-03 10:35:37 -04:00
|
|
|
|
2018-04-17 09:51:53 -04:00
|
|
|
after_transition pending: :running do |build|
|
2018-03-26 11:47:46 -04:00
|
|
|
build.ensure_metadata.update_timeout_state
|
2018-02-28 15:36:01 -05:00
|
|
|
end
|
2018-07-05 09:55:10 -04:00
|
|
|
|
|
|
|
after_transition running: any do |build|
|
|
|
|
Ci::BuildRunnerSession.where(build: build).delete_all
|
|
|
|
end
|
2015-08-25 21:42:46 -04:00
|
|
|
end
|
|
|
|
|
2018-03-20 18:21:17 -04:00
|
|
|
def ensure_metadata
|
2018-03-22 12:52:28 -04:00
|
|
|
metadata || build_metadata(project: project)
|
2015-08-25 21:42:46 -04:00
|
|
|
end
|
|
|
|
|
2016-12-08 11:52:24 -05:00
|
|
|
def detailed_status(current_user)
|
2016-12-13 07:24:25 -05:00
|
|
|
Gitlab::Ci::Status::Build::Factory
|
|
|
|
.new(self, current_user)
|
|
|
|
.fabricate!
|
2016-12-08 03:51:36 -05:00
|
|
|
end
|
|
|
|
|
2016-07-16 19:48:51 -04:00
|
|
|
def other_actions
|
2016-07-20 10:38:38 -04:00
|
|
|
pipeline.manual_actions.where.not(name: name)
|
2016-07-16 19:48:51 -04:00
|
|
|
end
|
|
|
|
|
2018-06-04 15:49:39 -04:00
|
|
|
def pages_generator?
|
|
|
|
Gitlab.config.pages.enabled &&
|
|
|
|
self.name == 'pages'
|
|
|
|
end
|
|
|
|
|
2016-07-16 12:39:58 -04:00
|
|
|
def playable?
|
2018-05-16 08:02:04 -04:00
|
|
|
action? && (manual? || retryable?)
|
2017-02-28 10:48:39 -05:00
|
|
|
end
|
|
|
|
|
2017-03-03 08:35:19 -05:00
|
|
|
def action?
|
2017-03-02 07:45:01 -05:00
|
|
|
self.when == 'manual'
|
|
|
|
end
|
|
|
|
|
2017-02-13 07:01:52 -05:00
|
|
|
def play(current_user)
|
2017-04-12 05:46:24 -04:00
|
|
|
Ci::PlayBuildService
|
|
|
|
.new(project, current_user)
|
|
|
|
.execute(self)
|
2016-07-16 12:39:58 -04:00
|
|
|
end
|
|
|
|
|
2016-12-08 04:40:56 -05:00
|
|
|
def cancelable?
|
|
|
|
active?
|
|
|
|
end
|
|
|
|
|
2015-11-03 05:44:07 -05:00
|
|
|
def retryable?
|
2017-04-06 08:31:38 -04:00
|
|
|
success? || failed? || canceled?
|
2015-11-03 05:44:07 -05:00
|
|
|
end
|
2017-07-17 06:38:21 -04:00
|
|
|
|
|
|
|
def retries_count
|
|
|
|
pipeline.builds.retried.where(name: self.name).count
|
|
|
|
end
|
|
|
|
|
|
|
|
def retries_max
|
|
|
|
self.options.fetch(:retry, 0).to_i
|
|
|
|
end
|
2015-11-03 05:44:07 -05:00
|
|
|
|
2017-04-16 07:14:39 -04:00
|
|
|
def latest?
|
|
|
|
!retried?
|
2016-03-31 13:51:28 -04:00
|
|
|
end
|
|
|
|
|
2016-11-16 18:23:05 -05:00
|
|
|
def expanded_environment_name
|
2018-03-29 08:46:27 -04:00
|
|
|
return unless has_environment?
|
|
|
|
|
|
|
|
strong_memoize(:expanded_environment_name) do
|
2018-03-27 07:05:29 -04:00
|
|
|
ExpandVariables.expand(environment, simple_variables)
|
|
|
|
end
|
2016-11-16 18:23:05 -05:00
|
|
|
end
|
|
|
|
|
2016-11-17 06:08:28 -05:00
|
|
|
def has_environment?
|
2016-12-16 07:24:03 -05:00
|
|
|
environment.present?
|
2016-11-17 06:08:28 -05:00
|
|
|
end
|
|
|
|
|
2016-11-16 18:23:05 -05:00
|
|
|
def starts_environment?
|
2016-11-17 06:08:28 -05:00
|
|
|
has_environment? && self.environment_action == 'start'
|
2016-11-16 18:23:05 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def stops_environment?
|
2016-11-17 06:08:28 -05:00
|
|
|
has_environment? && self.environment_action == 'stop'
|
2016-11-16 18:23:05 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def environment_action
|
2016-12-08 11:52:24 -05:00
|
|
|
self.options.fetch(:environment, {}).fetch(:action, 'start') if self.options
|
2016-11-16 18:23:05 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def outdated_deployment?
|
|
|
|
success? && !last_deployment.try(:last?)
|
2016-11-04 11:35:22 -04:00
|
|
|
end
|
2016-11-02 18:25:19 -04:00
|
|
|
|
2016-01-14 13:45:43 -05:00
|
|
|
def depends_on_builds
|
|
|
|
# Get builds of the same type
|
2016-06-02 10:19:18 -04:00
|
|
|
latest_builds = self.pipeline.builds.latest
|
2016-01-14 13:45:43 -05:00
|
|
|
|
|
|
|
# Return builds from previous stages
|
|
|
|
latest_builds.where('stage_idx < ?', stage_idx)
|
|
|
|
end
|
|
|
|
|
2017-11-06 12:47:05 -05:00
|
|
|
def triggered_by?(current_user)
|
2017-11-06 08:20:44 -05:00
|
|
|
user == current_user
|
|
|
|
end
|
|
|
|
|
2016-12-13 14:21:30 -05:00
|
|
|
# A slugified version of the build ref, suitable for inclusion in URLs and
|
|
|
|
# domain names. Rules:
|
|
|
|
#
|
|
|
|
# * Lowercased
|
|
|
|
# * Anything not matching [a-z0-9-] is replaced with a -
|
|
|
|
# * Maximum length is 63 bytes
|
2017-07-05 08:00:22 -04:00
|
|
|
# * First/Last Character is not a hyphen
|
2016-12-13 14:21:30 -05:00
|
|
|
def ref_slug
|
2017-08-07 14:00:11 -04:00
|
|
|
Gitlab::Utils.slugify(ref.to_s)
|
2016-12-13 14:21:30 -05:00
|
|
|
end
|
|
|
|
|
2018-03-23 10:21:31 -04:00
|
|
|
##
|
2018-03-27 07:05:29 -04:00
|
|
|
# Variables in the environment name scope.
|
2018-03-23 10:21:31 -04:00
|
|
|
#
|
2018-03-27 07:05:29 -04:00
|
|
|
def scoped_variables(environment: expanded_environment_name)
|
|
|
|
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
2018-03-12 10:07:05 -04:00
|
|
|
variables.concat(predefined_variables)
|
|
|
|
variables.concat(project.predefined_variables)
|
|
|
|
variables.concat(pipeline.predefined_variables)
|
|
|
|
variables.concat(runner.predefined_variables) if runner
|
2018-03-27 07:05:29 -04:00
|
|
|
variables.concat(project.deployment_variables(environment: environment)) if environment
|
2018-03-12 10:07:05 -04:00
|
|
|
variables.concat(yaml_variables)
|
|
|
|
variables.concat(user_variables)
|
2018-03-27 07:05:29 -04:00
|
|
|
variables.concat(secret_group_variables)
|
|
|
|
variables.concat(secret_project_variables(environment: environment))
|
2018-03-12 10:07:05 -04:00
|
|
|
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
|
2018-03-27 07:05:29 -04:00
|
|
|
end
|
2018-03-12 10:07:05 -04:00
|
|
|
|
2018-03-27 07:05:29 -04:00
|
|
|
##
|
|
|
|
# Variables that do not depend on the environment name.
|
|
|
|
#
|
|
|
|
def simple_variables
|
2018-03-30 04:32:28 -04:00
|
|
|
strong_memoize(:simple_variables) do
|
|
|
|
scoped_variables(environment: nil).to_runner_variables
|
|
|
|
end
|
2018-03-27 07:05:29 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
##
|
|
|
|
# All variables, including persisted environment variables.
|
|
|
|
#
|
|
|
|
def variables
|
2018-03-29 08:42:23 -04:00
|
|
|
Gitlab::Ci::Variables::Collection.new
|
|
|
|
.concat(persisted_variables)
|
|
|
|
.concat(scoped_variables)
|
2018-03-27 07:05:29 -04:00
|
|
|
.concat(persisted_environment_variables)
|
|
|
|
.to_runner_variables
|
|
|
|
end
|
|
|
|
|
2018-03-30 04:32:28 -04:00
|
|
|
##
|
|
|
|
# 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
|
2018-03-27 07:05:29 -04:00
|
|
|
scoped_variables.to_hash
|
2016-12-08 11:21:16 -05:00
|
|
|
end
|
|
|
|
|
2017-09-27 10:01:33 -04:00
|
|
|
def features
|
|
|
|
{ trace_sections: true }
|
|
|
|
end
|
|
|
|
|
2015-12-08 00:10:17 -05:00
|
|
|
def merge_request
|
2017-05-26 04:31:42 -04:00
|
|
|
return @merge_request if defined?(@merge_request)
|
2017-05-29 03:58:20 -04:00
|
|
|
|
2017-05-23 11:10:07 -04:00
|
|
|
@merge_request ||=
|
|
|
|
begin
|
Use latest_merge_request_diff association
Compared to the merge_request_diff association:
1. It's simpler to query. The query uses a foreign key to the
merge_request_diffs table, so no ordering is necessary.
2. It's faster for preloading. The merge_request_diff association has to load
every diff for the MRs in the set, then discard all but the most recent for
each. This association means that Rails can just query for N diffs from N
MRs.
3. It's more complicated to update. This is a bidirectional foreign key, so we
need to update two tables when adding a diff record. This also means we need
to handle this as a special case when importing a GitLab project.
There is some juggling with this association in the merge request model:
* `MergeRequest#latest_merge_request_diff` is _always_ the latest diff.
* `MergeRequest#merge_request_diff` reuses
`MergeRequest#latest_merge_request_diff` unless:
* Arguments are passed. These are typically to force-reload the association.
* It doesn't exist. That means we might be trying to implicitly create a
diff. This only seems to happen in specs.
* The association is already loaded. This is important for the reasons
explained in the comment, which I'll reiterate here: if we a) load a
non-latest diff, then b) get its `merge_request`, then c) get that MR's
`merge_request_diff`, we should get the diff we loaded in c), even though
that's not the latest diff.
Basically, `MergeRequest#merge_request_diff` is the latest diff in most cases,
but not quite all.
2017-11-15 12:22:18 -05:00
|
|
|
merge_requests = MergeRequest.includes(:latest_merge_request_diff)
|
2017-05-23 11:10:07 -04:00
|
|
|
.where(source_branch: ref,
|
|
|
|
source_project: pipeline.project)
|
2017-05-29 03:58:20 -04:00
|
|
|
.reorder(iid: :desc)
|
2017-05-23 11:10:07 -04:00
|
|
|
|
|
|
|
merge_requests.find do |merge_request|
|
2017-06-16 10:00:58 -04:00
|
|
|
merge_request.commit_shas.include?(pipeline.sha)
|
2017-05-23 11:10:07 -04:00
|
|
|
end
|
|
|
|
end
|
2015-12-08 00:10:17 -05:00
|
|
|
end
|
|
|
|
|
2015-08-25 21:42:46 -04:00
|
|
|
def repo_url
|
2016-09-16 06:46:33 -04:00
|
|
|
auth = "gitlab-ci-token:#{ensure_token!}@"
|
2018-01-27 00:35:53 -05:00
|
|
|
project.http_url_to_repo.sub(%r{^https?://}) do |prefix|
|
2015-12-04 06:55:23 -05:00
|
|
|
prefix + auth
|
|
|
|
end
|
2015-08-25 21:42:46 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def allow_git_fetch
|
2015-12-04 06:55:23 -05:00
|
|
|
project.build_allow_git_fetch
|
2015-08-25 21:42:46 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def update_coverage
|
2017-04-06 12:20:27 -04:00
|
|
|
coverage = trace.extract_coverage(coverage_regex)
|
2018-07-02 06:43:06 -04:00
|
|
|
update(coverage: coverage) if coverage.present?
|
2015-08-25 21:42:46 -04:00
|
|
|
end
|
|
|
|
|
2017-09-25 12:54:08 -04:00
|
|
|
def parse_trace_sections!
|
2017-10-06 06:33:10 -04:00
|
|
|
ExtractSectionsFromBuildTraceService.new(project, user).execute(self)
|
2017-09-25 12:54:08 -04:00
|
|
|
end
|
|
|
|
|
2017-04-06 12:20:27 -04:00
|
|
|
def trace
|
|
|
|
Gitlab::Ci::Trace.new(self)
|
2016-06-21 07:12:02 -04:00
|
|
|
end
|
|
|
|
|
2016-02-02 06:12:03 -05:00
|
|
|
def has_trace?
|
2017-04-06 12:20:27 -04:00
|
|
|
trace.exist?
|
2016-08-25 07:53:20 -04:00
|
|
|
end
|
|
|
|
|
2018-07-27 01:04:35 -04:00
|
|
|
def has_test_reports?
|
|
|
|
job_artifacts.test_reports.any?
|
|
|
|
end
|
|
|
|
|
2018-07-03 01:00:25 -04:00
|
|
|
def has_old_trace?
|
|
|
|
old_trace.present?
|
|
|
|
end
|
|
|
|
|
2017-04-06 12:20:27 -04:00
|
|
|
def trace=(data)
|
|
|
|
raise NotImplementedError
|
2016-03-31 07:24:14 -04:00
|
|
|
end
|
|
|
|
|
2017-04-06 12:20:27 -04:00
|
|
|
def old_trace
|
|
|
|
read_attribute(:trace)
|
2016-03-29 09:34:18 -04:00
|
|
|
end
|
|
|
|
|
2017-04-06 12:20:27 -04:00
|
|
|
def erase_old_trace!
|
2018-07-06 02:25:59 -04:00
|
|
|
return unless has_old_trace?
|
2018-07-03 01:00:25 -04:00
|
|
|
|
2018-03-19 09:48:09 -04:00
|
|
|
update_column(:trace, nil)
|
2015-08-25 21:42:46 -04:00
|
|
|
end
|
|
|
|
|
2016-10-27 11:05:02 -04:00
|
|
|
def needs_touch?
|
|
|
|
Time.now - updated_at > 15.minutes.to_i
|
|
|
|
end
|
|
|
|
|
2016-05-18 18:43:00 -04:00
|
|
|
def valid_token?(token)
|
2016-08-08 06:01:25 -04:00
|
|
|
self.token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.token)
|
2015-10-12 17:47:32 -04:00
|
|
|
end
|
|
|
|
|
2016-05-06 03:17:27 -04:00
|
|
|
def has_tags?
|
|
|
|
tag_list.any?
|
|
|
|
end
|
|
|
|
|
2015-10-12 15:12:31 -04:00
|
|
|
def any_runners_online?
|
2016-06-08 03:19:49 -04:00
|
|
|
project.any_runners? { |runner| runner.active? && runner.online? && runner.can_pick?(self) }
|
2015-10-12 15:12:31 -04:00
|
|
|
end
|
|
|
|
|
2016-03-09 10:24:02 -05:00
|
|
|
def stuck?
|
2015-10-12 15:12:31 -04:00
|
|
|
pending? && !any_runners_online?
|
|
|
|
end
|
|
|
|
|
2015-12-07 07:23:23 -05:00
|
|
|
def execute_hooks
|
2016-02-19 11:38:47 -05:00
|
|
|
return unless project
|
2017-11-14 04:02:39 -05:00
|
|
|
|
2016-08-12 04:09:29 -04:00
|
|
|
build_data = Gitlab::DataBuilder::Build.build(self)
|
2017-05-15 11:11:45 -04:00
|
|
|
project.execute_hooks(build_data.dup, :job_hooks)
|
|
|
|
project.execute_services(build_data.dup, :job_hooks)
|
2015-12-07 07:23:23 -05:00
|
|
|
end
|
|
|
|
|
2017-06-08 01:29:35 -04:00
|
|
|
def browsable_artifacts?
|
|
|
|
artifacts_metadata?
|
|
|
|
end
|
|
|
|
|
2016-01-20 15:48:22 -05:00
|
|
|
def artifacts_metadata_entry(path, **options)
|
2018-07-09 07:34:18 -04:00
|
|
|
artifacts_metadata.open do |metadata_stream|
|
2017-06-08 01:29:35 -04:00
|
|
|
metadata = Gitlab::Ci::Build::Artifacts::Metadata.new(
|
2018-07-09 07:34:18 -04:00
|
|
|
metadata_stream,
|
2017-06-08 01:29:35 -04:00
|
|
|
path,
|
|
|
|
**options)
|
2016-06-28 07:16:48 -04:00
|
|
|
|
2017-06-08 01:29:35 -04:00
|
|
|
metadata.to_entry
|
|
|
|
end
|
2015-12-28 04:35:51 -05:00
|
|
|
end
|
|
|
|
|
2016-05-18 16:21:51 -04:00
|
|
|
def erase_artifacts!
|
|
|
|
remove_artifacts_file!
|
|
|
|
remove_artifacts_metadata!
|
2016-06-17 06:58:26 -04:00
|
|
|
save
|
2016-05-18 16:21:51 -04:00
|
|
|
end
|
|
|
|
|
2018-07-27 01:04:35 -04:00
|
|
|
def erase_test_reports!
|
2018-07-27 01:32:24 -04:00
|
|
|
# TODO: Use fast_destroy_all in the context of https://gitlab.com/gitlab-org/gitlab-ce/issues/35240
|
|
|
|
job_artifacts_junit&.destroy
|
2018-07-27 01:04:35 -04:00
|
|
|
end
|
|
|
|
|
2016-02-16 02:39:20 -05:00
|
|
|
def erase(opts = {})
|
|
|
|
return false unless erasable?
|
|
|
|
|
2016-05-18 16:21:51 -04:00
|
|
|
erase_artifacts!
|
2018-07-27 01:04:35 -04:00
|
|
|
erase_test_reports!
|
2016-02-16 02:39:20 -05:00
|
|
|
erase_trace!
|
|
|
|
update_erased!(opts[:erased_by])
|
|
|
|
end
|
|
|
|
|
|
|
|
def erasable?
|
2018-07-27 01:04:35 -04:00
|
|
|
complete? && (artifacts? || has_test_reports? || has_trace?)
|
2016-02-16 02:39:20 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def erased?
|
|
|
|
!self.erased_at.nil?
|
|
|
|
end
|
|
|
|
|
2016-05-18 16:21:51 -04:00
|
|
|
def artifacts_expired?
|
2016-06-10 08:40:25 -04:00
|
|
|
artifacts_expire_at && artifacts_expire_at < Time.now
|
2016-05-18 16:21:51 -04:00
|
|
|
end
|
|
|
|
|
2016-06-10 08:25:54 -04:00
|
|
|
def artifacts_expire_in
|
|
|
|
artifacts_expire_at - Time.now if artifacts_expire_at
|
|
|
|
end
|
|
|
|
|
|
|
|
def artifacts_expire_in=(value)
|
2016-06-10 15:45:06 -04:00
|
|
|
self.artifacts_expire_at =
|
|
|
|
if value
|
2017-02-16 10:40:13 -05:00
|
|
|
ChronicDuration.parse(value)&.seconds&.from_now
|
2016-06-10 15:45:06 -04:00
|
|
|
end
|
2016-06-10 08:25:54 -04:00
|
|
|
end
|
|
|
|
|
2017-01-09 04:58:45 -05:00
|
|
|
def has_expiring_artifacts?
|
2017-05-29 03:58:20 -04:00
|
|
|
artifacts_expire_at.present? && artifacts_expire_at > Time.now
|
2017-01-09 04:58:45 -05:00
|
|
|
end
|
|
|
|
|
2016-06-08 11:18:54 -04:00
|
|
|
def keep_artifacts!
|
2016-05-18 16:21:51 -04:00
|
|
|
self.update(artifacts_expire_at: nil)
|
2017-12-03 06:02:11 -05:00
|
|
|
self.job_artifacts.update_all(expire_at: nil)
|
2016-05-18 16:21:51 -04:00
|
|
|
end
|
|
|
|
|
2016-11-13 22:56:39 -05:00
|
|
|
def coverage_regex
|
2016-12-12 23:53:12 -05:00
|
|
|
super || project.try(:build_coverage_regex)
|
2016-11-13 22:56:39 -05:00
|
|
|
end
|
|
|
|
|
2016-07-19 07:23:14 -04:00
|
|
|
def when
|
|
|
|
read_attribute(:when) || build_attributes_from_config[:when] || 'on_success'
|
2016-02-16 02:39:20 -05:00
|
|
|
end
|
|
|
|
|
2016-07-19 07:23:14 -04:00
|
|
|
def yaml_variables
|
|
|
|
read_attribute(:yaml_variables) || build_attributes_from_config[:yaml_variables] || []
|
2016-02-16 02:39:20 -05:00
|
|
|
end
|
|
|
|
|
2016-09-05 05:42:59 -04:00
|
|
|
def user_variables
|
2018-03-13 10:38:49 -04:00
|
|
|
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
2018-04-18 05:19:40 -04:00
|
|
|
break variables if user.blank?
|
2016-09-05 05:42:59 -04:00
|
|
|
|
2018-03-13 10:38:49 -04:00
|
|
|
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
|
2016-09-05 05:42:59 -04:00
|
|
|
end
|
|
|
|
|
2018-03-27 07:05:29 -04:00
|
|
|
def secret_group_variables
|
|
|
|
return [] unless project.group
|
|
|
|
|
|
|
|
project.group.secret_variables_for(ref, project)
|
|
|
|
end
|
|
|
|
|
|
|
|
def secret_project_variables(environment: persisted_environment)
|
2017-07-06 03:45:38 -04:00
|
|
|
project.secret_variables_for(ref: ref, environment: environment)
|
|
|
|
end
|
|
|
|
|
2017-02-15 19:05:44 -05:00
|
|
|
def steps
|
2017-03-07 06:30:34 -05:00
|
|
|
[Gitlab::Ci::Build::Step.from_commands(self),
|
|
|
|
Gitlab::Ci::Build::Step.from_after_script(self)].compact
|
2017-02-15 19:05:44 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def image
|
2017-03-02 11:44:15 -05:00
|
|
|
Gitlab::Ci::Build::Image.from_image(self)
|
2017-02-15 19:05:44 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def services
|
2017-03-02 11:44:15 -05:00
|
|
|
Gitlab::Ci::Build::Image.from_services(self)
|
2017-02-15 19:05:44 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def cache
|
2018-01-04 13:43:31 -05:00
|
|
|
cache = options[:cache]
|
|
|
|
|
|
|
|
if cache && project.jobs_cache_index
|
|
|
|
cache = cache.merge(
|
2018-02-21 08:01:02 -05:00
|
|
|
key: "#{cache[:key]}-#{project.jobs_cache_index}")
|
2017-12-22 17:06:15 -05:00
|
|
|
end
|
2018-01-04 13:43:31 -05:00
|
|
|
|
|
|
|
[cache]
|
2017-02-15 19:05:44 -05:00
|
|
|
end
|
|
|
|
|
2016-11-20 14:43:50 -05:00
|
|
|
def credentials
|
2016-11-21 10:02:08 -05:00
|
|
|
Gitlab::Ci::Build::Credentials::Factory.new(self).create!
|
2016-11-20 14:43:50 -05:00
|
|
|
end
|
|
|
|
|
2017-03-16 09:45:05 -04:00
|
|
|
def dependencies
|
2017-04-05 08:07:10 -04:00
|
|
|
return [] if empty_dependencies?
|
|
|
|
|
2017-03-16 09:45:05 -04:00
|
|
|
depended_jobs = depends_on_builds
|
|
|
|
|
2017-03-18 19:35:17 -04:00
|
|
|
return depended_jobs unless options[:dependencies].present?
|
2017-03-16 09:45:05 -04:00
|
|
|
|
2017-03-18 19:35:17 -04:00
|
|
|
depended_jobs.select do |job|
|
|
|
|
options[:dependencies].include?(job.name)
|
2017-03-16 09:45:05 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-04-05 08:07:10 -04:00
|
|
|
def empty_dependencies?
|
|
|
|
options[:dependencies]&.empty?
|
|
|
|
end
|
|
|
|
|
2018-07-30 10:31:02 -04:00
|
|
|
def has_valid_build_dependencies?
|
|
|
|
return true unless Feature.enabled?('ci_disable_validates_dependencies')
|
2018-07-17 06:58:57 -04:00
|
|
|
|
2018-07-30 10:31:02 -04:00
|
|
|
dependencies.all?(&:is_valid_dependency?)
|
2017-09-04 04:56:49 -04:00
|
|
|
end
|
|
|
|
|
2018-07-30 10:31:02 -04:00
|
|
|
def is_valid_dependency?
|
2017-12-02 02:23:19 -05:00
|
|
|
return false if artifacts_expired?
|
|
|
|
return false if erased?
|
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2018-07-30 11:26:56 -04:00
|
|
|
def runner_required_feature_names
|
|
|
|
strong_memoize(:runner_required_feature_names) do
|
|
|
|
RUNNER_FEATURES.select do |feature, method|
|
|
|
|
method.call(self)
|
|
|
|
end.keys
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-07-17 06:58:57 -04:00
|
|
|
def supported_runner?(features)
|
2018-07-30 11:26:56 -04:00
|
|
|
runner_required_feature_names.all? do |feature_name|
|
2018-07-17 08:00:54 -04:00
|
|
|
features&.dig(feature_name)
|
2018-07-17 06:58:57 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-07-30 11:18:28 -04:00
|
|
|
def publishes_artifacts_reports?
|
2018-07-30 11:26:56 -04:00
|
|
|
options&.dig(:artifacts, :reports)&.any?
|
2018-07-30 11:18:28 -04:00
|
|
|
end
|
|
|
|
|
2017-04-06 12:20:27 -04:00
|
|
|
def hide_secrets(trace)
|
|
|
|
return unless trace
|
|
|
|
|
|
|
|
trace = trace.dup
|
2017-09-06 07:26:15 -04:00
|
|
|
Gitlab::Ci::MaskSecret.mask!(trace, project.runners_token) if project
|
|
|
|
Gitlab::Ci::MaskSecret.mask!(trace, token)
|
2017-04-06 12:20:27 -04:00
|
|
|
trace
|
|
|
|
end
|
|
|
|
|
2017-09-05 11:10:57 -04:00
|
|
|
def serializable_hash(options = {})
|
2017-09-06 04:16:11 -04:00
|
|
|
super(options).merge(when: read_attribute(:when))
|
2017-09-05 11:10:57 -04:00
|
|
|
end
|
|
|
|
|
2018-07-05 09:55:10 -04:00
|
|
|
def has_terminal?
|
|
|
|
running? && runner_session_url.present?
|
|
|
|
end
|
|
|
|
|
2016-02-16 02:39:20 -05:00
|
|
|
private
|
|
|
|
|
2016-06-29 05:44:39 -04:00
|
|
|
def update_artifacts_size
|
2017-12-03 10:21:59 -05:00
|
|
|
self.artifacts_size = legacy_artifacts_file&.size
|
2016-06-29 05:44:39 -04:00
|
|
|
end
|
|
|
|
|
2016-02-16 02:39:20 -05:00
|
|
|
def erase_trace!
|
2017-04-06 12:20:27 -04:00
|
|
|
trace.erase!
|
2016-02-16 02:39:20 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def update_erased!(user = nil)
|
2016-06-08 11:18:54 -04:00
|
|
|
self.update(erased_by: user, erased_at: Time.now, artifacts_expire_at: nil)
|
2016-02-16 02:39:20 -05:00
|
|
|
end
|
|
|
|
|
2017-02-03 10:21:10 -05:00
|
|
|
def unscoped_project
|
2017-03-17 19:06:11 -04:00
|
|
|
@unscoped_project ||= Project.unscoped.find_by(id: project_id)
|
2017-02-03 10:21:10 -05:00
|
|
|
end
|
|
|
|
|
2017-03-07 04:06:53 -05:00
|
|
|
CI_REGISTRY_USER = 'gitlab-ci-token'.freeze
|
|
|
|
|
2018-03-29 08:42:23 -04:00
|
|
|
def persisted_variables
|
|
|
|
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
2018-04-18 05:19:40 -04:00
|
|
|
break variables unless persisted?
|
2018-03-29 08:42:23 -04:00
|
|
|
|
|
|
|
variables
|
2018-05-18 08:05:29 -04:00
|
|
|
.concat(pipeline.persisted_variables)
|
2018-03-29 08:42:23 -04:00
|
|
|
.append(key: 'CI_JOB_ID', value: id.to_s)
|
2018-05-20 08:18:50 -04:00
|
|
|
.append(key: 'CI_JOB_URL', value: Gitlab::Routing.url_helpers.project_job_url(project, self))
|
2018-03-29 08:42:23 -04:00
|
|
|
.append(key: 'CI_JOB_TOKEN', value: token, public: false)
|
|
|
|
.append(key: 'CI_BUILD_ID', value: id.to_s)
|
|
|
|
.append(key: 'CI_BUILD_TOKEN', value: token, public: false)
|
|
|
|
.append(key: 'CI_REGISTRY_USER', value: CI_REGISTRY_USER)
|
|
|
|
.append(key: 'CI_REGISTRY_PASSWORD', value: token, public: false)
|
|
|
|
.append(key: 'CI_REPOSITORY_URL', value: repo_url, public: false)
|
2018-04-20 11:05:16 -04:00
|
|
|
.concat(deploy_token_variables)
|
2018-03-29 08:42:23 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-10-12 11:06:53 -04:00
|
|
|
def predefined_variables
|
2018-03-13 10:38:49 -04:00
|
|
|
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
|
|
|
variables.append(key: 'CI', value: 'true')
|
|
|
|
variables.append(key: 'GITLAB_CI', value: 'true')
|
2018-04-05 02:39:16 -04:00
|
|
|
variables.append(key: 'GITLAB_FEATURES', value: project.licensed_features.join(','))
|
2018-03-13 10:38:49 -04:00
|
|
|
variables.append(key: 'CI_SERVER_NAME', value: 'GitLab')
|
|
|
|
variables.append(key: 'CI_SERVER_VERSION', value: Gitlab::VERSION)
|
2018-05-24 03:57:54 -04:00
|
|
|
variables.append(key: 'CI_SERVER_REVISION', value: Gitlab.revision)
|
2018-03-13 10:38:49 -04:00
|
|
|
variables.append(key: 'CI_JOB_NAME', value: name)
|
|
|
|
variables.append(key: 'CI_JOB_STAGE', value: stage)
|
|
|
|
variables.append(key: 'CI_COMMIT_SHA', value: sha)
|
2018-07-12 09:41:08 -04:00
|
|
|
variables.append(key: 'CI_COMMIT_BEFORE_SHA', value: before_sha)
|
2018-03-13 10:38:49 -04:00
|
|
|
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.concat(legacy_variables)
|
|
|
|
end
|
2017-03-07 04:06:53 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def legacy_variables
|
2018-03-13 10:38:49 -04:00
|
|
|
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
|
2015-10-12 11:06:53 -04:00
|
|
|
end
|
2016-07-19 07:23:14 -04:00
|
|
|
|
2018-03-29 08:42:23 -04:00
|
|
|
def persisted_environment_variables
|
|
|
|
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
2018-04-18 05:19:40 -04:00
|
|
|
break variables unless persisted? && persisted_environment.present?
|
2018-03-29 08:42:23 -04:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2018-04-16 16:47:35 -04:00
|
|
|
def deploy_token_variables
|
|
|
|
Gitlab::Ci::Variables::Collection.new.tap do |variables|
|
2018-04-20 11:05:16 -04:00
|
|
|
break variables unless gitlab_deploy_token
|
|
|
|
|
2018-05-18 11:29:20 -04:00
|
|
|
variables.append(key: 'CI_DEPLOY_USER', value: gitlab_deploy_token.username)
|
2018-04-20 11:05:16 -04:00
|
|
|
variables.append(key: 'CI_DEPLOY_PASSWORD', value: gitlab_deploy_token.token, public: false)
|
2018-04-16 16:47:35 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-06-21 06:03:42 -04:00
|
|
|
def environment_url
|
2017-06-21 08:22:26 -04:00
|
|
|
options&.dig(:environment, :url) || persisted_environment&.external_url
|
2017-06-21 06:03:42 -04:00
|
|
|
end
|
|
|
|
|
2016-07-19 07:23:14 -04:00
|
|
|
def build_attributes_from_config
|
|
|
|
return {} unless pipeline.config_processor
|
2016-08-04 11:44:27 -04:00
|
|
|
|
2016-07-19 07:23:14 -04:00
|
|
|
pipeline.config_processor.build_attributes(name)
|
|
|
|
end
|
2016-09-19 06:38:03 -04:00
|
|
|
|
2018-03-20 19:03:50 -04:00
|
|
|
def update_project_statistics_after_save
|
|
|
|
update_project_statistics(read_attribute(:artifacts_size).to_i - artifacts_size_was.to_i)
|
|
|
|
end
|
2017-09-21 04:34:12 -04:00
|
|
|
|
2018-03-20 19:03:50 -04:00
|
|
|
def update_project_statistics_after_destroy
|
|
|
|
update_project_statistics(-artifacts_size)
|
2017-09-21 04:34:12 -04:00
|
|
|
end
|
2017-06-01 17:36:04 -04:00
|
|
|
|
2018-03-20 19:03:50 -04:00
|
|
|
def update_project_statistics(difference)
|
|
|
|
ProjectStatistics.increment_statistic(project_id, :build_artifacts_size, difference)
|
|
|
|
end
|
|
|
|
|
|
|
|
def project_destroyed?
|
|
|
|
project.pending_delete?
|
2017-06-01 17:36:04 -04:00
|
|
|
end
|
2015-08-25 21:42:46 -04:00
|
|
|
end
|
|
|
|
end
|