mirror of
https://gitlab.com/gitlab-org/gitlab-foss.git
synced 2025-07-29 12:00:32 +00:00
172 lines
4.9 KiB
Ruby
172 lines
4.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
module Pages
|
|
class UrlBuilder
|
|
attr_reader :project_namespace
|
|
|
|
ALLOWED_ARTIFACT_EXTENSIONS = %w[.html .htm .txt .json .xml .log].freeze
|
|
ARTIFACT_URL = "%{host}/-/%{project_path}/-/jobs/%{job_id}/artifacts/%{artifact_path}"
|
|
|
|
def initialize(project, options = nil)
|
|
@project = project
|
|
namespace, _, @project_path = project.full_path.partition('/')
|
|
@project_namespace = namespace.downcase
|
|
@options = options || {}
|
|
end
|
|
|
|
def pages_url
|
|
default_url
|
|
.to_s
|
|
end
|
|
|
|
def unique_host
|
|
return unless unique_domain_enabled?
|
|
return if namespace_in_path?
|
|
|
|
hostname
|
|
end
|
|
|
|
# If the project path is the same as host, we serve it as group/user page.
|
|
#
|
|
# e.g. For Pages external url `example.io`,
|
|
# `acmecorp/acmecorp.example.io` project will publish to `http(s)://acmecorp.example.io`
|
|
# See https://docs.gitlab.com/ee/user/project/pages/getting_started_part_one.html#user-and-group-website-examples.
|
|
def is_namespace_homepage? # rubocop:disable Naming/PredicateName -- namespace_homepage is not an
|
|
# adjective, so adding "is_" improves understandability
|
|
project_path.downcase == "#{project_namespace}.#{instance_pages_domain}"
|
|
end
|
|
|
|
def artifact_url(artifact, job)
|
|
return unless artifact_url_available?(artifact, job)
|
|
|
|
format(
|
|
ARTIFACT_URL,
|
|
host: namespace_url,
|
|
project_path: project_path,
|
|
job_id: job.id,
|
|
artifact_path: artifact.path)
|
|
end
|
|
|
|
def artifact_url_available?(artifact, job)
|
|
config.enabled &&
|
|
config.artifacts_server &&
|
|
ALLOWED_ARTIFACT_EXTENSIONS.include?(File.extname(artifact.name)) &&
|
|
(config.access_control || job.project.public?)
|
|
end
|
|
|
|
# Defines the full hostname, eg. group.gitlab.io
|
|
def hostname
|
|
return instance_pages_domain if namespace_in_path?
|
|
return project_path if is_namespace_homepage?
|
|
return instance_pages_domain.prepend("#{subdomain}.") if subdomain.present?
|
|
|
|
instance_pages_domain
|
|
end
|
|
|
|
def path_prefix
|
|
return unless @options[:path_prefix].present?
|
|
|
|
::Gitlab::Utils.slugify(@options[:path_prefix], allow_dots: true).presence
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :project, :project_path
|
|
|
|
# Defines whether the Pages site is published on a unique subdomain
|
|
# instead of a single subdomain for the entire namespace and a path
|
|
# segment for each project.
|
|
#
|
|
# Examples:
|
|
# unique_domain_enabled? is true: "https://my-project-12345.example.com
|
|
# unique_domain_enabled? is false: "https://my-group.example.com/my-project
|
|
def unique_domain_enabled?
|
|
project.project_setting.pages_unique_domain_enabled?
|
|
end
|
|
|
|
# Defines whether the namespace should be included as part of the path
|
|
# instead of using a subdomain. Useful for self-hosted instances where
|
|
# auto-generated subdomains don't work.
|
|
#
|
|
# Examples:
|
|
# namespace_in_path? is false: "https://my-group.example.com/my-project
|
|
# namespace_in_path? is true: "https://example.com/my-group/my-project
|
|
def namespace_in_path?
|
|
config.namespace_in_path
|
|
end
|
|
|
|
def config
|
|
Gitlab.config.pages
|
|
end
|
|
|
|
def config_url
|
|
URI(config.url)
|
|
end
|
|
|
|
def protocol
|
|
config.protocol
|
|
end
|
|
|
|
def subdomain
|
|
return if namespace_in_path?
|
|
return project.project_setting.pages_unique_domain if unique_domain_enabled?
|
|
|
|
project_namespace
|
|
end
|
|
|
|
# Defines the top-most domain that is not autogenerated. For gitlab.com
|
|
# this is `gitlab.io`. If you need the fully qualified domain for the
|
|
# project, use `hostname` instead.
|
|
def instance_pages_domain
|
|
config_url.host
|
|
end
|
|
|
|
def port
|
|
config.port
|
|
end
|
|
|
|
def path
|
|
[
|
|
namespace_path_segment,
|
|
project_path_segment,
|
|
path_prefix
|
|
].compact.join('/')
|
|
end
|
|
|
|
def namespace_path_segment
|
|
return unless namespace_in_path?
|
|
return project_namespace unless unique_domain_enabled?
|
|
|
|
project.project_setting.pages_unique_domain
|
|
end
|
|
|
|
def project_path_segment
|
|
return if is_namespace_homepage? || unique_domain_enabled?
|
|
|
|
project_path
|
|
end
|
|
|
|
def default_url
|
|
config_url.tap do |url|
|
|
url.scheme = protocol
|
|
url.host = hostname
|
|
url.port = port
|
|
url.path = "/#{path}" if path.present?
|
|
end
|
|
end
|
|
|
|
def namespace_url
|
|
config_url.tap do |url|
|
|
url.port = port
|
|
if namespace_in_path?
|
|
url.path = "/#{project_namespace}"
|
|
else
|
|
url.host.prepend("#{project_namespace}.")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|