1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
# frozen_string_literal: true
class Deployment < ActiveRecord::Base
include AtomicInternalId
include IidRoutes
belongs_to :project, required: true
belongs_to :environment, required: true
belongs_to :user
belongs_to :deployable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.deployments&.maximum(:iid) }
validates :sha, presence: true
validates :ref, presence: true
delegate :name, to: :environment, prefix: true
after_create :create_ref
after_create :invalidate_cache
scope :for_environment, -> (environment) { where(environment_id: environment) }
def self.last_for_environment(environment)
ids = self
.for_environment(environment)
.select('MAX(id) AS id')
.group(:environment_id)
.map(&:id)
find(ids)
end
def commit
project.commit(sha)
end
def commit_title
commit.try(:title)
end
def short_sha
Commit.truncate_sha(sha)
end
def last?
self == environment.last_deployment
end
def create_ref
project.repository.create_ref(ref, ref_path)
end
def invalidate_cache
environment.expire_etag_cache
end
def manual_actions
@manual_actions ||= deployable.try(:other_manual_actions)
end
def scheduled_actions
@scheduled_actions ||= deployable.try(:other_scheduled_actions)
end
def includes_commit?(commit)
return false unless commit
project.repository.ancestor?(commit.id, sha)
end
def update_merge_request_metrics!
return unless environment.update_merge_request_metrics?
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)
if previous_deployment
merge_requests = merge_requests.where("merge_request_metrics.merged_at >= ?", previous_deployment.created_at)
end
# 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
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)
end
def previous_deployment
@previous_deployment ||=
project.deployments.joins(:environment)
.where(environments: { name: self.environment.name }, ref: self.ref)
.where.not(id: self.id)
.take
end
def stop_action
return unless on_stop.present?
return unless manual_actions
@stop_action ||= manual_actions.find_by(name: on_stop)
end
def formatted_deployment_time
created_at.to_time.in_time_zone.to_s(:medium)
end
def has_metrics?
prometheus_adapter&.can_query?
end
def metrics
return {} unless has_metrics?
metrics = prometheus_adapter.query(:deployment, self)
metrics&.merge(deployment_time: created_at.to_i) || {}
end
def additional_metrics
return {} unless has_metrics?
metrics = prometheus_adapter.query(:additional_metrics_deployment, self)
metrics&.merge(deployment_time: created_at.to_i) || {}
end
def status
'success'
end
private
def prometheus_adapter
environment.prometheus_adapter
end
def ref_path
File.join(environment.ref_path, 'deployments', iid.to_s)
end
end
|