File: components_project.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (91 lines) | stat: -rw-r--r-- 2,974 bytes parent folder | download
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
# frozen_string_literal: true

module Ci
  module Catalog
    # This class represents a project that contains one or more CI/CD components.
    # It is responsible for retrieving the data of a component file.
    class ComponentsProject
      TEMPLATE_FILE = 'template.yml'
      TEMPLATES_DIR = 'templates'
      TEMPLATE_PATH_REGEX = '^templates\/[\w-]+(?:\/template)?\.yml$'
      COMPONENTS_LIMIT = 30

      ComponentData = Struct.new(:content, :path, keyword_init: true)

      def initialize(project, sha = project&.commit&.sha)
        @project = project
        @sha = sha
      end

      def fetch_component_paths(ref, limit: COMPONENTS_LIMIT)
        project.repository.search_files_by_regexp(TEMPLATE_PATH_REGEX, ref, limit: limit)
      end

      def extract_component_name(path)
        return unless path.match?(TEMPLATE_PATH_REGEX)

        dirname = File.dirname(path)
        filename = File.basename(path, '.*')

        if dirname == TEMPLATES_DIR
          filename
        else
          File.basename(dirname)
        end
      end

      def extract_spec(blob)
        result = Gitlab::Ci::Config::Yaml::Loader.new(blob).load_uninterpolated_yaml

        raise result.error_class, result.error unless result.valid?

        result.spec
      end

      def fetch_component(component_name)
        return ComponentData.new unless component_name.index('/').nil?

        path = simple_template_path(component_name)
        content = fetch_content(path)

        if content.nil?
          path = complex_template_path(component_name)
          content = fetch_content(path)
        end

        ComponentData.new(content: content, path: path)
      end

      # TODO: This may retrieve the wrong component object if a simple and a complex component
      # have the same name for the given catalog resource version. We should complete
      # https://gitlab.com/gitlab-org/gitlab/-/issues/450737 to ensure unique component names.
      def find_catalog_component(component_name)
        # Multiple versions of a project can have the same sha, so we return the latest one.
        version = project.catalog_resource_versions.by_sha(sha).latest
        return unless version

        version.components.template.find_by_name(component_name)
      end

      private

      attr_reader :project, :sha

      def fetch_content(component_path)
        project.repository.blob_data_at(sha, component_path)
      end

      # A simple template consists of a single file
      def simple_template_path(component_name)
        File.join(TEMPLATES_DIR, "#{component_name}.yml")
      end

      # A complex template is directory-based and may consist of multiple files.
      # Given a path like "my-org/sub-group/the-project/templates/component"
      # returns the entry point path: "templates/component/template.yml".
      def complex_template_path(component_name)
        File.join(TEMPLATES_DIR, component_name, TEMPLATE_FILE)
      end
    end
  end
end