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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
# frozen_string_literal: true
class ReleaseHighlight
CACHE_DURATION = 1.hour
FREE_PACKAGE = 'Free'
PREMIUM_PACKAGE = 'Premium'
ULTIMATE_PACKAGE = 'Ultimate'
def self.paginated(page: 1)
result = self.paginated_query(page: page)
result = self.paginated_query(page: result.next_page) while next_page?(result)
result
end
def self.paginated_query(page:)
key = self.cache_key("items:page-#{page}")
Rails.cache.fetch(key, expires_in: CACHE_DURATION) do
items = self.load_items(page: page)
next if items.nil?
QueryResult.new(items: items, next_page: next_page(current_page: page))
end
end
def self.load_items(page:)
index = page - 1
file_path = file_paths[index]
return if file_path.nil?
file = File.read(file_path)
items = YAML.safe_load(file, permitted_classes: [Date])
items&.map! do |item|
next unless include_item?(item)
begin
item.tap { |i| i['description'] = Banzai.render(i['description'], { project: nil }) }
rescue StandardError => e
Gitlab::ErrorTracking.track_exception(e, file_path: file_path)
next
end
end
items&.compact
rescue Psych::Exception => e
Gitlab::ErrorTracking.track_exception(e, file_path: file_path)
[]
end
def self.whats_new_path
Rails.root.join('data/whats_new/*.yml')
end
def self.file_paths
@file_paths ||= self.relative_file_paths.map { |path| path.prepend(Rails.root.to_s) }
end
def self.relative_file_paths
Rails.cache.fetch(self.cache_key('file_paths'), expires_in: CACHE_DURATION) do
Dir.glob(whats_new_path).reverse.map { |path| path.delete_prefix(Rails.root.to_s) }
end
end
def self.cache_key(key)
variant = Gitlab::CurrentSettings.current_application_settings.whats_new_variant
['release_highlight', variant, key, Gitlab.revision].join(':')
end
def self.next_page(current_page: 1)
next_page = current_page + 1
next_index = next_page - 1
next_page if self.file_paths[next_index]
end
def self.most_recent_item_count
key = self.cache_key('recent_item_count')
Gitlab::ProcessMemoryCache.cache_backend.fetch(key, expires_in: CACHE_DURATION) do
self.paginated&.items&.count
end
end
def self.most_recent_version_digest
key = self.cache_key('most_recent_version_digest')
Gitlab::ProcessMemoryCache.cache_backend.fetch(key, expires_in: CACHE_DURATION) do
version = self.paginated&.items&.first&.[]('release')&.to_s
next if version.nil?
Digest::SHA256.hexdigest(version)
end
end
QueryResult = Struct.new(:items, :next_page, keyword_init: true) do
include Enumerable
delegate :each, to: :items
end
def self.current_package
return FREE_PACKAGE unless defined?(License)
case License.current&.plan&.downcase
when License::PREMIUM_PLAN
PREMIUM_PACKAGE
when License::ULTIMATE_PLAN
ULTIMATE_PACKAGE
else
FREE_PACKAGE
end
end
def self.include_item?(item)
platform = Gitlab.com? ? 'gitlab-com' : 'self-managed'
return false unless item[platform]
return true unless Gitlab::CurrentSettings.current_application_settings.whats_new_variant_current_tier?
item['available_in']&.include?(current_package)
end
def self.next_page?(result)
return false unless result
# if all items for the current page doesn't belong to the current tier
# or failed to parse current YAML, loading next page
result.items == [] && result.next_page.present?
end
end
ReleaseHighlight.prepend_mod
|