summaryrefslogtreecommitdiff
path: root/lib/gitlab/ci/pipeline/seed/build/cache.rb
blob: 409b6658cc08934c495a1bf9d75975c79deea17f (plain)
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
# frozen_string_literal: true

module Gitlab
  module Ci
    module Pipeline
      module Seed
        class Build
          class Cache
            def initialize(pipeline, cache, custom_key_prefix)
              @pipeline = pipeline
              local_cache = cache.to_h.deep_dup
              @key = local_cache.delete(:key)
              @paths = local_cache.delete(:paths)
              @policy = local_cache.delete(:policy)
              @untracked = local_cache.delete(:untracked)
              @when = local_cache.delete(:when)
              @unprotect = local_cache.delete(:unprotect)
              @custom_key_prefix = custom_key_prefix

              raise ArgumentError, "unknown cache keys: #{local_cache.keys}" if local_cache.any?
            end

            def attributes
              {
                key: key_string,
                paths: @paths,
                policy: @policy,
                untracked: @untracked,
                when: @when,
                unprotect: @unprotect
              }.compact
            end

            def build_attributes
              { options: { cache: attributes.presence }.compact }
            end

            private

            def key_string
              key_from_string || key_from_files
            end

            def key_from_string
              @key.to_s if @key.is_a?(String) || @key.is_a?(Symbol)
            end

            def key_from_files
              return unless @key.is_a?(Hash)

              @key[:prefix] ||= @custom_key_prefix.to_s
              [@key[:prefix], files_digest].select(&:present?).join('-')
            end

            def files_digest
              hash_of_the_latest_changes || 'default'
            end

            def hash_of_the_latest_changes
              ids = files.map { |path| last_commit_id_for_path(path) }
              ids = ids.compact.sort.uniq

              Digest::SHA1.hexdigest(ids.join('-')) if ids.any?
            end

            def files
              @key[:files]
                .to_a
                .select(&:present?)
                .uniq
            end

            def last_commit_id_for_path(path)
              @pipeline.project.repository.last_commit_id_for_path(@pipeline.sha, path)
            end
          end
        end
      end
    end
  end
end