summaryrefslogtreecommitdiff
path: root/lib/gitlab/ci/components/instance_path.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/ci/components/instance_path.rb')
-rw-r--r--lib/gitlab/ci/components/instance_path.rb75
1 files changed, 75 insertions, 0 deletions
diff --git a/lib/gitlab/ci/components/instance_path.rb b/lib/gitlab/ci/components/instance_path.rb
new file mode 100644
index 00000000000..010ce57d2a0
--- /dev/null
+++ b/lib/gitlab/ci/components/instance_path.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Components
+ class InstancePath
+ include Gitlab::Utils::StrongMemoize
+
+ def self.match?(address)
+ address.include?('@') && address.start_with?(Settings.gitlab_ci['component_fqdn'])
+ end
+
+ attr_reader :host
+
+ def initialize(address:, content_filename:)
+ @full_path, @version = address.to_s.split('@', 2)
+ @content_filename = content_filename
+ @host = Settings.gitlab_ci['component_fqdn']
+ end
+
+ def fetch_content!(current_user:)
+ return unless project
+ return unless sha
+
+ raise Gitlab::Access::AccessDeniedError unless Ability.allowed?(current_user, :download_code, project)
+
+ project.repository.blob_data_at(sha, project_file_path)
+ end
+
+ def project
+ find_project_by_component_path(instance_path)
+ end
+ strong_memoize_attr :project
+
+ def project_file_path
+ return unless project
+
+ component_dir = instance_path.delete_prefix(project.full_path)
+ File.join(component_dir, @content_filename).delete_prefix('/')
+ end
+
+ # TODO: Add support when version is a released tag and "~latest" moving target
+ def sha
+ return unless project
+
+ project.commit(version)&.id
+ end
+ strong_memoize_attr :sha
+
+ private
+
+ attr_reader :version, :path
+
+ def instance_path
+ @full_path.delete_prefix(host)
+ end
+
+ # Given a path like "my-org/sub-group/the-project/path/to/component"
+ # find the project "my-org/sub-group/the-project" by looking at all possible paths.
+ def find_project_by_component_path(path)
+ possible_paths = [path]
+
+ while index = path.rindex('/') # find index of last `/` in a path
+ possible_paths << (path = path[0..index - 1])
+ end
+
+ # remove shortest path as it is group
+ possible_paths.pop
+
+ ::Project.where_full_path_in(possible_paths).take # rubocop: disable CodeReuse/ActiveRecord
+ end
+ end
+ end
+ end
+end