lib/helpers/generic.rb (137 lines of code) (raw):
# frozen_string_literal: true
module Nanoc::Helpers
module Generic
#
# Check if NANOC_ENV is set to production
#
def production?
ENV['NANOC_ENV'] == 'production'
end
#
# Check if NANOC_ENV is set to production and the branch is the default one.
# For things that should only be built in production of the default branch.
# Sometimes we don't want things to be deployed into the stable branches,
# which they are considered production.
#
def production_and_default_branch?
ENV['NANOC_ENV'] == 'production' && ENV['CI_DEFAULT_BRANCH'] == ENV['CI_COMMIT_REF_NAME']
end
#
# Find the current branch. If CI_COMMIT_BRANCH is not defined, that means
# we're working locally, and Git is used to find the branch.
#
def current_branch
if ENV['CI_COMMIT_REF_NAME'].nil?
`git branch --show-current`.tr("\n", '')
else
ENV['CI_COMMIT_REF_NAME']
end
end
#
# Check if CI_PROJECT_NAME is 'gitlab-docs', or nil which implies
# local development. This can be used to skip portions that we
# don't want to render in one of the upstream products.
#
def gitlab_docs_or_local?
ENV['CI_PROJECT_NAME'] == 'gitlab-docs' || ENV['CI_PROJECT_NAME'].nil?
end
#
# Control display of survey banner. See README.md#survey-banner
#
def show_banner?
@items['/_data/banner.yaml'][:show_banner]
end
#
# Returns global nav sections.
#
def get_nav_sections
@items['/_data/navigation.yaml'][:sections]
end
#
# Get the top-level section for a page, based on title and menu placement.
#
# This function temporarily serves a dual purpose in the migration from
# Google Programmable Search to Elasticsearch:
#
# 1. It returns a human-readable string for use in the "gitlab-docs-section" metatag,
# which is used for Google search results.
#
# 2. When the 'machine' parameter is set to true, it returns a machine-readable string
# for use in the "gitlab_docs_section" metatag, which is used for Elasticsearch indexing.
#
# @param title [String] The title of the page
# @param path [String] The path of the page
# @param machine [Boolean] Whether to return a machine-readable string (default: false)
#
# @return [String] The section name in either human-readable or machine-readable format,
# or "none" if no section is found
#
def docs_section(title, path, machine_readable = false)
section = find_section(title, path) || "none"
machine_readable ? machine_friendly(section) : section
end
def find_section(title, path)
return "Tutorials" if title.start_with?("Tutorial:")
path = path[1..] # remove the leading slash
get_nav_sections.each do |section|
section_title = section[:section_title]
return section_title if section[:section_url] == path
section.fetch(:section_categories, []).each do |category|
return section_title if category[:category_url] == path
next unless category[:docs]
return section_title if section_exists?(category[:docs], path)
end
end
"none"
end
def machine_friendly(section)
return "none" if section == "none"
section.downcase.gsub(%r{[^a-z0-9]+}, '_').gsub(%r{^_|_$}, '')
end
def section_exists?(docs, path)
docs.each do |doc|
return true if doc[:doc_url] == path
sub_docs = doc[:docs]
next unless sub_docs
return true if section_exists?(sub_docs, path)
end
false
end
#
# Generate a breadcrumb trail for a page, based on the global nav.
#
# Returns an array structured to fit the schema.org breadcrumbList spec.
# See https://schema.org/BreadcrumbList
#
def build_breadcrumb_list(path)
breadcrumb_list = []
data = get_nav_sections
crumbs = breadcrumb_trail(data, path[1..]) # remove the leading slash
return nil if crumbs.empty?
crumbs.each_with_index do |crumb, index|
structured_crumb = {
:@type => "ListItem",
:position => index + 1,
:name => crumb[:name]
}
structured_crumb[:item] = "https://docs.gitlab.com/#{crumb[:item]}" if crumb[:item] && index < crumbs.length - 1
breadcrumb_list << structured_crumb
end
return nil if breadcrumb_list.empty?
{
'@context': "https://schema.org",
'@type': "BreadcrumbList",
itemListElement: breadcrumb_list
}
end
#
# Traverse the menu and return an array of breadcrumbs for a given item.
#
# This is used to fill in the itemListElement property in the
# BreadcrumbList JSON-LD object, which is included in the head of each page.
#
def breadcrumb_trail(data, path)
return [] if data.empty?
data.each do |item|
# 1st level items
if item[:section_url] == path
return [{ name: item[:section_title], item: item[:section_url] }]
# 2nd level items
elsif item.key?(:section_categories)
result = breadcrumb_trail(item[:section_categories], path)
next if result.empty?
return [{ name: item[:section_title], item: item[:section_url] }] + result
# 3rd level items
elsif item.key?(:category_url) && item[:category_url] == path
return [{ name: item[:category_title], item: item[:category_url] }]
# 4th-6th level items
elsif item.key?(:docs)
result = breadcrumb_trail_docs(item[:docs], path)
next if result.empty?
return [{ name: item[:category_title], item: item[:category_url] }] + result
end
end
[]
end
#
# Builds a breadcrumb trail for 4th-6th level menu items.
#
# We can use a recursive method for these since they use the same
# property names at each level.
#
def breadcrumb_trail_docs(docs, path)
return [] if docs.empty?
docs.each do |doc|
if doc[:doc_url] == path
return [{ name: doc[:doc_title], item: doc[:doc_url] }]
elsif doc.key?(:docs)
result = breadcrumb_trail_docs(doc[:docs], path)
next if result.empty?
return [{ name: doc[:doc_title], item: doc[:doc_url] }] + result
end
end
[]
end
#
# Return the breadcrumb trail in string format.
#
# This is set in a metatag and then used for
# search results on the site.
#
# The Google Programmable Search JSON API does not
# include the JSON-LD breadcrumbList schema in the
# response, but it does include metatag content.
#
def docs_breadcrumb_list(path)
data = get_nav_sections
list = breadcrumb_trail(data, path[1..])
list.map { |item| item[:name] }.join(" › ")
end
#
# Fetch information about GitLab releases.
#
def get_release_dates
uri = URI('https://gitlab.com/gitlab-com/www-gitlab-com/-/raw/master/data/releases.yml')
response = Net::HTTP.get_response(uri)
return "[]" unless response.is_a?(Net::HTTPSuccess)
parsed_yaml = YAML.safe_load(response.body) || []
JSON.generate(parsed_yaml)
rescue StandardError => e
warn("Error getting release dates - #{e}")
"[]"
end
# This method will check whether gitlab product analytics is
# enabled or not based on env variables
#
def gitlab_analytics_enabled?
!ENV.fetch('GITLAB_ANALYTICS_HOST', '').empty? &&
!ENV.fetch('GITLAB_ANALYTICS_ID', '').empty?
end
#
# This method will return configuration object
# when gitlab product analytics is enabled.
#
def gitlab_analytics_json
return unless gitlab_analytics_enabled?
{
'appId' => ENV.fetch('GITLAB_ANALYTICS_ID', nil),
'host' => ENV.fetch('GITLAB_ANALYTICS_HOST', nil),
'hasCookieConsent' => true
}.to_json
end
end
end