discourse/lib/version.rb
2023-10-16 11:20:22 -04:00

129 lines
3.8 KiB
Ruby

# frozen_string_literal: true
module Discourse
VERSION_REGEXP ||= /\A\d+\.\d+\.\d+(\.beta\d+)?\z/
VERSION_COMPATIBILITY_FILENAME ||= ".discourse-compatibility"
# work around reloader
unless defined?(::Discourse::VERSION)
module VERSION #:nodoc:
STRING = "3.2.0.beta3-dev"
PARTS = STRING.split(".")
private_constant :PARTS
MAJOR = PARTS[0].to_i
MINOR = PARTS[1].to_i
TINY = PARTS[2].to_i
PRE = PARTS[3]&.split("-", 2)&.first
DEV = PARTS[3]&.split("-", 2)&.second
end
end
class InvalidVersionListError < StandardError
end
def self.has_needed_version?(current, needed)
Gem::Version.new(current) >= Gem::Version.new(needed)
end
# lookup an external resource (theme/plugin)'s best compatible version
# compatible resource files are YAML, in the format:
# `discourse_version: plugin/theme git reference.` For example:
# 2.5.0.beta6: c4a6c17
# 2.5.0.beta4: d1d2d3f
# 2.5.0.beta2: bbffee
# 2.4.4.beta6: some-other-branch-ref
# 2.4.2.beta1: v1-tag
def self.find_compatible_resource(version_list, target_version = ::Discourse::VERSION::STRING)
return unless version_list.present?
begin
version_list = YAML.safe_load(version_list)
rescue Psych::SyntaxError, Psych::DisallowedClass => e
end
raise InvalidVersionListError unless version_list.is_a?(Hash)
version_list =
version_list
.transform_keys do |v|
Gem::Requirement.parse(v)
rescue Gem::Requirement::BadRequirementError => e
raise InvalidVersionListError, "Invalid version specifier: #{v}"
end
.sort_by do |parsed_requirement, _|
operator, version = parsed_requirement
[version, operator == "<" ? 0 : 1]
end
parsed_target_version = Gem::Version.new(target_version)
lowest_matching_entry =
version_list.find do |parsed_requirement, target|
req_operator, req_version = parsed_requirement
req_operator = "<=" if req_operator == "="
if !%w[<= <].include?(req_operator)
raise InvalidVersionListError,
"Invalid version specifier operator for '#{req_operator} #{req_version}'. Operator must be one of <= or <"
end
resolved_requirement = Gem::Requirement.new("#{req_operator} #{req_version.to_s}")
resolved_requirement.satisfied_by?(parsed_target_version)
end
return if lowest_matching_entry.nil?
checkout_version = lowest_matching_entry[1]
begin
Discourse::Utils.execute_command "git",
"check-ref-format",
"--allow-onelevel",
checkout_version
rescue RuntimeError
raise InvalidVersionListError, "Invalid ref name: #{checkout_version}"
end
checkout_version
end
# Find a compatible resource from a git repo
def self.find_compatible_git_resource(path)
return unless File.directory?("#{path}/.git")
tree_info =
Discourse::Utils.execute_command(
"git",
"-C",
path,
"ls-tree",
"-l",
"HEAD",
Discourse::VERSION_COMPATIBILITY_FILENAME,
)
blob_size = tree_info.split[3].to_i
if blob_size > Discourse::MAX_METADATA_FILE_SIZE
$stderr.puts "#{Discourse::VERSION_COMPATIBILITY_FILENAME} file in #{path} too big"
return
end
compat_resource =
Discourse::Utils.execute_command(
"git",
"-C",
path,
"show",
"HEAD@{upstream}:#{Discourse::VERSION_COMPATIBILITY_FILENAME}",
)
Discourse.find_compatible_resource(compat_resource)
rescue InvalidVersionListError => e
$stderr.puts "Invalid version list in #{path}"
rescue Discourse::Utils::CommandError => e
nil
end
end