deployment.rb 3.1 KB
Newer Older
1 2
# frozen_string_literal: true

3
class Deployment < ActiveRecord::Base
4
  include AtomicInternalId
S
Shinya Maeda 已提交
5
  include IidRoutes
6

7 8
  belongs_to :project, required: true
  belongs_to :environment, required: true
9
  belongs_to :user
10
  belongs_to :deployable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
11

12 13
  has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.deployments&.maximum(:iid) }

K
Kamil Trzcinski 已提交
14 15
  validates :sha, presence: true
  validates :ref, presence: true
16 17 18

  delegate :name, to: :environment, prefix: true

19
  after_create :create_ref
20
  after_create :invalidate_cache
21

22 23 24 25 26 27 28 29 30
  def commit
    project.commit(sha)
  end

  def commit_title
    commit.try(:title)
  end

  def short_sha
K
Kamil Trzcinski 已提交
31
    Commit.truncate_sha(sha)
32
  end
33 34 35 36

  def last?
    self == environment.last_deployment
  end
37

Z
Zeger-Jan van de Weg 已提交
38
  def create_ref
39
    project.repository.create_ref(ref, ref_path)
40
  end
41

42 43 44 45
  def invalidate_cache
    environment.expire_etag_cache
  end

46
  def manual_actions
47
    @manual_actions ||= deployable.try(:other_actions)
48
  end
49

50
  def includes_commit?(commit)
51 52
    return false unless commit

53
    project.repository.ancestor?(commit.id, sha)
54
  end
55

56 57 58
  def update_merge_request_metrics!
    return unless environment.update_merge_request_metrics?

59 60 61 62
    merge_requests = project.merge_requests
                     .joins(:metrics)
                     .where(target_branch: self.ref, merge_request_metrics: { first_deployed_to_production_at: nil })
                     .where("merge_request_metrics.merged_at <= ?", self.created_at)
63

64 65
    if previous_deployment
      merge_requests = merge_requests.where("merge_request_metrics.merged_at >= ?", previous_deployment.created_at)
66
    end
67 68 69 70 71 72 73 74 75 76

    # Need to use `map` instead of `select` because MySQL doesn't allow `SELECT`ing from the same table
    # that we're updating.
    merge_request_ids =
      if Gitlab::Database.postgresql?
        merge_requests.select(:id)
      elsif Gitlab::Database.mysql?
        merge_requests.map(&:id)
      end

77 78 79
    MergeRequest::Metrics
      .where(merge_request_id: merge_request_ids, first_deployed_to_production_at: nil)
      .update_all(first_deployed_to_production_at: self.created_at)
80 81 82 83
  end

  def previous_deployment
    @previous_deployment ||=
84 85 86 87
      project.deployments.joins(:environment)
      .where(environments: { name: self.environment.name }, ref: self.ref)
      .where.not(id: self.id)
      .take
88
  end
89

90
  def stop_action
91 92
    return unless on_stop.present?
    return unless manual_actions
93

94
    @stop_action ||= manual_actions.find_by(name: on_stop)
95 96
  end

Z
Z.J. van de Weg 已提交
97 98 99 100
  def formatted_deployment_time
    created_at.to_time.in_time_zone.to_s(:medium)
  end

F
Fatih Acet 已提交
101
  def has_metrics?
102
    prometheus_adapter&.can_query?
F
Fatih Acet 已提交
103 104
  end

P
Pawel Chojnacki 已提交
105
  def metrics
F
Fatih Acet 已提交
106 107
    return {} unless has_metrics?

108 109
    metrics = prometheus_adapter.query(:deployment, self)
    metrics&.merge(deployment_time: created_at.to_i) || {}
110 111
  end

112
  def additional_metrics
113
    return {} unless has_metrics?
114

115
    metrics = prometheus_adapter.query(:additional_metrics_deployment, self)
116 117 118
    metrics&.merge(deployment_time: created_at.to_i) || {}
  end

119 120
  private

121 122 123 124
  def prometheus_adapter
    environment.prometheus_adapter
  end

125
  def ref_path
126
    File.join(environment.ref_path, 'deployments', iid.to_s)
127
  end
128
end