From 6bfb92d2efe1a4b518380084ee93aec47ea3f545 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 25 Jul 2023 14:31:38 +0100 Subject: [PATCH] DEV: Support new discourse-compatibility format on old core (#187) This introduces a fallback compatibility parser, identical to the one introduced in https://github.com/discourse/discourse/pull/22714 This will allow Docker Manager to parse new compatibility files, even when running on older Discourse instances. This is only intended as a temporary solution, and will be removed before the Discourse 3.2 release. --- .../fallback_compatibility_parser.rb | 72 +++++++++++++++++++ lib/docker_manager/git_repo.rb | 13 ++-- 2 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 lib/docker_manager/fallback_compatibility_parser.rb diff --git a/lib/docker_manager/fallback_compatibility_parser.rb b/lib/docker_manager/fallback_compatibility_parser.rb new file mode 100644 index 0000000..5a34636 --- /dev/null +++ b/lib/docker_manager/fallback_compatibility_parser.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +# This is the compatibility parser introduced in https://github.com/discourse/discourse/pull/22714 +# It's copied here to be used as a fallback when docker_manager is running on an older Discourse version. +# Should be removed just before the Discourse 3.2 release. +module DockerManager::FallbackCompatibilityParser + 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 Discourse::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 Discourse::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 Discourse::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 Discourse::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") + compat_resource, std_error, s = + Open3.capture3( + "git -C '#{path}' show HEAD@{upstream}:#{Discourse::VERSION_COMPATIBILITY_FILENAME}", + ) + self.find_compatible_resource(compat_resource) if s.success? + rescue Discourse::InvalidVersionListError => e + $stderr.puts "Invalid version list in #{path}" + end +end diff --git a/lib/docker_manager/git_repo.rb b/lib/docker_manager/git_repo.rb index 2911c96..91b8d01 100644 --- a/lib/docker_manager/git_repo.rb +++ b/lib/docker_manager/git_repo.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require_relative "fallback_compatibility_parser" + # like Grit just very very minimal class DockerManager::GitRepo attr_reader :path, :name, :branch @@ -129,10 +131,13 @@ class DockerManager::GitRepo end def tracking_branch - branch = nil - if defined?(Discourse.find_compatible_git_resource) - branch = Discourse.find_compatible_git_resource(path) - end + branch = + begin + Discourse.find_compatible_git_resource(path) + rescue ArgumentError + DockerManager::FallbackCompatibilityParser.find_compatible_git_resource(path) + end + return branch if branch.present? head = upstream_branch