Class: Ci::Build

Inherits:
CommitStatus show all
Defined in:
app/models/ci/build.rb

Constant Summary

Constants included from Statuseable

Statuseable::AVAILABLE_STATUSES

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from CommitStatus

#before_sha, #duration, #ignored?, stages, stages_status

Methods included from Statuseable

#active?, #complete?, #started?

Class Method Details

.create_from(build) ⇒ Object


70
71
72
73
74
75
76
# File 'app/models/ci/build.rb', line 70

def create_from(build)
  new_build = build.dup
  new_build.status = 'pending'
  new_build.runner_id = nil
  new_build.trigger_request_id = nil
  new_build.save
end

.first_pendingObject


66
67
68
# File 'app/models/ci/build.rb', line 66

def first_pending
  pending.unstarted.order('created_at ASC').first
end

.last_monthObject


62
63
64
# File 'app/models/ci/build.rb', line 62

def last_month
  where('created_at > ?', Date.today - 1.month)
end

.retry(build) ⇒ Object


78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'app/models/ci/build.rb', line 78

def retry(build)
  new_build = Ci::Build.new(status: 'pending')
  new_build.ref = build.ref
  new_build.tag = build.tag
  new_build.options = build.options
  new_build.commands = build.commands
  new_build.tag_list = build.tag_list
  new_build.gl_project_id = build.gl_project_id
  new_build.commit_id = build.commit_id
  new_build.name = build.name
  new_build.allow_failure = build.allow_failure
  new_build.stage = build.stage
  new_build.stage_idx = build.stage_idx
  new_build.trigger_request = build.trigger_request
  new_build.save
  new_build
end

Instance Method Details

#allow_git_fetchObject


172
173
174
# File 'app/models/ci/build.rb', line 172

def allow_git_fetch
  project.build_allow_git_fetch
end

#any_runners_online?Boolean

Returns:

  • (Boolean)

329
330
331
# File 'app/models/ci/build.rb', line 329

def any_runners_online?
  project.any_runners? { |runner| runner.active? && runner.online? && can_be_served?(runner) }
end

#append_trace(trace_part, offset) ⇒ Object


247
248
249
250
251
252
253
254
# File 'app/models/ci/build.rb', line 247

def append_trace(trace_part, offset)
  recreate_trace_dir

  File.truncate(path_to_trace, offset) if File.exist?(path_to_trace)
  File.open(path_to_trace, 'a') do |f|
    f.write(trace_part)
  end
end

#artifacts?Boolean

Returns:

  • (Boolean)

344
345
346
# File 'app/models/ci/build.rb', line 344

def artifacts?
  artifacts_file.exists?
end

#artifacts_metadata?Boolean

Returns:

  • (Boolean)

348
349
350
# File 'app/models/ci/build.rb', line 348

def artifacts_metadata?
  artifacts? && .exists?
end

#artifacts_metadata_entry(path, **options) ⇒ Object


352
353
354
# File 'app/models/ci/build.rb', line 352

def (path, **options)
  Gitlab::Ci::Build::Artifacts::Metadata.new(.path, path, **options).to_entry
end

#artifacts_pathObject

Deprecated

This contains a hotfix for CI build data integrity, see #4246

This method is used by `ArtifactUploader` to create a store_dir. Warning: Uploader uses it after AND before file has been stored.

This method returns old path to artifacts only if it already exists.


302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'app/models/ci/build.rb', line 302

def artifacts_path
  old = File.join(created_at.utc.strftime('%Y_%m'),
                  project.ci_id.to_s,
                  id.to_s)

  old_store = File.join(ArtifactUploader.artifacts_path, old)
  return old if project.ci_id && File.directory?(old_store)

  File.join(
    created_at.utc.strftime('%Y_%m'),
    project.id.to_s,
    id.to_s
  )
end

#can_be_served?(runner) ⇒ Boolean

Returns:

  • (Boolean)

325
326
327
# File 'app/models/ci/build.rb', line 325

def can_be_served?(runner)
  (tag_list - runner.tag_list).empty?
end

#depends_on_buildsObject


126
127
128
129
130
131
132
# File 'app/models/ci/build.rb', line 126

def depends_on_builds
  # Get builds of the same type
  latest_builds = self.commit.builds.latest

  # Return builds from previous stages
  latest_builds.where('stage_idx < ?', stage_idx)
end

#dir_to_traceObject


256
257
258
259
260
261
262
# File 'app/models/ci/build.rb', line 256

def dir_to_trace
  File.join(
    Settings.gitlab_ci.builds_path,
    created_at.utc.strftime("%Y_%m"),
    project.id.to_s
  )
end

#erasable?Boolean

Returns:

  • (Boolean)

365
366
367
# File 'app/models/ci/build.rb', line 365

def erasable?
  complete? && (artifacts? || has_trace?)
end

#erase(opts = {}) ⇒ Object


356
357
358
359
360
361
362
363
# File 'app/models/ci/build.rb', line 356

def erase(opts = {})
  return false unless erasable?

  remove_artifacts_file!
  remove_artifacts_metadata!
  erase_trace!
  update_erased!(opts[:erased_by])
end

#erased?Boolean

Returns:

  • (Boolean)

369
370
371
# File 'app/models/ci/build.rb', line 369

def erased?
  !self.erased_at.nil?
end

#execute_hooksObject


337
338
339
340
341
342
# File 'app/models/ci/build.rb', line 337

def execute_hooks
  return unless project
  build_data = Gitlab::BuildDataBuilder.build(self)
  project.execute_hooks(build_data.dup, :build_hooks)
  project.execute_services(build_data.dup, :build_hooks)
end

#extract_coverage(text, regex) ⇒ Object


187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'app/models/ci/build.rb', line 187

def extract_coverage(text, regex)
  begin
    matches = text.scan(Regexp.new(regex)).last
    matches = matches.last if matches.kind_of?(Array)
    coverage = matches.gsub(/\d+(\.\d+)?/).first

    if coverage.present?
      coverage.to_f
    end
  rescue
    # if bad regex or something goes wrong we dont want to interrupt transition
    # so we just silentrly ignore error for now
  end
end

#has_trace?Boolean

Returns:

  • (Boolean)

202
203
204
# File 'app/models/ci/build.rb', line 202

def has_trace?
  raw_trace.present?
end

#merge_requestObject


147
148
149
150
151
152
153
154
155
# File 'app/models/ci/build.rb', line 147

def merge_request
  merge_requests = MergeRequest.includes(:merge_request_diff)
                               .where(source_branch: ref, source_project_id: commit.gl_project_id)
                               .reorder(iid: :asc)

  merge_requests.find do |merge_request|
    merge_request.commits.any? { |ci| ci.id == commit.sha }
  end
end

#old_dir_to_traceObject

Deprecated

This is a hotfix for CI build data integrity, see #4246 Should be removed in 8.4, after CI files migration has been done.


274
275
276
277
278
279
280
# File 'app/models/ci/build.rb', line 274

def old_dir_to_trace
  File.join(
    Settings.gitlab_ci.builds_path,
    created_at.utc.strftime("%Y_%m"),
    project.ci_id.to_s
  )
end

#old_path_to_traceObject

Deprecated

This is a hotfix for CI build data integrity, see #4246 Should be removed in 8.4, after CI files migration has been done.


288
289
290
# File 'app/models/ci/build.rb', line 288

def old_path_to_trace
  "#{old_dir_to_trace}/#{id}.log"
end

#path_to_traceObject


264
265
266
# File 'app/models/ci/build.rb', line 264

def path_to_trace
  "#{dir_to_trace}/#{id}.log"
end

#project_idObject


157
158
159
# File 'app/models/ci/build.rb', line 157

def project_id
  commit.project.id
end

#project_nameObject


161
162
163
# File 'app/models/ci/build.rb', line 161

def project_name
  project.name
end

#raw_traceObject


206
207
208
209
210
211
212
213
214
215
216
# File 'app/models/ci/build.rb', line 206

def raw_trace
  if File.file?(path_to_trace)
    File.read(path_to_trace)
  elsif project.ci_id && File.file?(old_path_to_trace)
    # Temporary fix for build trace data integrity
    File.read(old_path_to_trace)
  else
    # backward compatibility
    read_attribute :trace
  end
end

#repo_urlObject


165
166
167
168
169
170
# File 'app/models/ci/build.rb', line 165

def repo_url
  auth = "gitlab-ci-token:#{token}@"
  project.http_url_to_repo.sub(/^https?:\/\//) do |prefix|
    prefix + auth
  end
end

#retried?Boolean

Returns:

  • (Boolean)

118
119
120
# File 'app/models/ci/build.rb', line 118

def retried?
  !self.commit.statuses.latest.include?(self)
end

#retryObject


122
123
124
# File 'app/models/ci/build.rb', line 122

def retry
  Ci::Build.retry(self)
end

#retryable?Boolean

Returns:

  • (Boolean)

114
115
116
# File 'app/models/ci/build.rb', line 114

def retryable?
  project.builds_enabled? && commands.present?
end

#stuck?Boolean

Returns:

  • (Boolean)

333
334
335
# File 'app/models/ci/build.rb', line 333

def stuck?
  pending? && !any_runners_online?
end

#timeoutObject


139
140
141
# File 'app/models/ci/build.rb', line 139

def timeout
  project.build_timeout
end

#tokenObject


317
318
319
# File 'app/models/ci/build.rb', line 317

def token
  project.runners_token
end

#traceObject


218
219
220
221
222
223
224
225
# File 'app/models/ci/build.rb', line 218

def trace
  trace = raw_trace
  if project && trace.present? && project.runners_token.present?
    trace.gsub(project.runners_token, 'xxxxxx')
  else
    trace
  end
end

#trace=(trace) ⇒ Object


235
236
237
238
# File 'app/models/ci/build.rb', line 235

def trace=(trace)
  recreate_trace_dir
  File.write(path_to_trace, trace)
end

#trace_htmlObject


134
135
136
137
# File 'app/models/ci/build.rb', line 134

def trace_html
  html = Ci::Ansi2html::convert(trace) if trace.present?
  html || ''
end

#trace_lengthObject


227
228
229
230
231
232
233
# File 'app/models/ci/build.rb', line 227

def trace_length
  if raw_trace
    raw_trace.length
  else
    0
  end
end

#update_coverageObject


176
177
178
179
180
181
182
183
184
185
# File 'app/models/ci/build.rb', line 176

def update_coverage
  return unless project
  coverage_regex = project.build_coverage_regex
  return unless coverage_regex
  coverage = extract_coverage(trace, coverage_regex)

  if coverage.is_a? Numeric
    update_attributes(coverage: coverage)
  end
end

#valid_token?(token) ⇒ Boolean

Returns:

  • (Boolean)

321
322
323
# File 'app/models/ci/build.rb', line 321

def valid_token? token
  project.valid_runners_token? token
end

#variablesObject


143
144
145
# File 'app/models/ci/build.rb', line 143

def variables
  predefined_variables + yaml_variables + project_variables + trigger_variables
end