build_metadata.rb 2.55 KB
Newer Older
1 2
# frozen_string_literal: true

3
module Ci
4 5
  # The purpose of this class is to store Build related data that can be disposed.
  # Data that should be persisted forever, should be stored with Ci::Build model.
6
  class BuildMetadata < ApplicationRecord
7 8
    BuildTimeout = Struct.new(:value, :source)

9 10 11
    extend Gitlab::Ci::Model
    include Presentable
    include ChronicDurationAttribute
12
    include Gitlab::Utils::StrongMemoize
13
    include IgnorableColumns
14 15 16

    self.table_name = 'ci_builds_metadata'

17
    belongs_to :build, class_name: 'CommitStatus'
18
    belongs_to :project
19

20 21
    before_create :set_build_project

22
    validates :build, presence: true
23
    validates :secrets, json_schema: { filename: 'build_metadata_secrets' }
24 25 26

    serialize :config_options, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
    serialize :config_variables, Serializers::JSON # rubocop:disable Cop/ActiveRecordSerialize
27

Tomasz Maczukin's avatar
Tomasz Maczukin committed
28
    chronic_duration_attr_reader :timeout_human_readable, :timeout
29

30 31
    scope :scoped_build, -> { where('ci_builds_metadata.build_id = ci_builds.id') }
    scope :with_interruptible, -> { where(interruptible: true) }
32
    scope :with_exposed_artifacts, -> { where(has_exposed_artifacts: true) }
33

34
    enum timeout_source: {
35 36
        unknown_timeout_source: 1,
        project_timeout_source: 2,
37 38
        runner_timeout_source: 3,
        job_timeout_source: 4
39 40
    }

41 42
    ignore_column :build_id_convert_to_bigint, remove_with: '14.2', remove_after: '2021-08-22'

43
    def update_timeout_state
44
      timeout = timeout_with_highest_precedence
45

46
      return unless timeout
47

48
      update(timeout: timeout.value, timeout_source: timeout.source)
49
    end
50 51 52 53 54 55

    private

    def set_build_project
      self.project_id ||= self.build.project_id
    end
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

    def timeout_with_highest_precedence
      [(job_timeout || project_timeout), runner_timeout].compact.min_by { |timeout| timeout.value }
    end

    def project_timeout
      strong_memoize(:project_timeout) do
        BuildTimeout.new(project&.build_timeout, :project_timeout_source)
      end
    end

    def job_timeout
      return unless build.options

      strong_memoize(:job_timeout) do
        if timeout_from_options = build.options[:job_timeout]
          BuildTimeout.new(timeout_from_options, :job_timeout_source)
        end
      end
    end

    def runner_timeout
      return unless runner_timeout_set?

      strong_memoize(:runner_timeout) do
        BuildTimeout.new(build.runner.maximum_timeout, :runner_timeout_source)
      end
    end

    def runner_timeout_set?
      build.runner&.maximum_timeout.to_i > 0
    end
88 89
  end
end