Support plugin and Theme compatibility version manifests (#9995)
Adds a new rake task `plugin:checkout_compatible_all` and `plugin:checkout_compatible[plugin-name]` that check out compatible plugin versions. Supports a .discourse-compatibility file in the root of plugins and themes that list out a plugin's compatibility with certain discourse versions: eg: .discourse-compatibility ``` 2.5.0.beta6: some-git-hash 2.4.4.beta4: some-git-tag 2.2.0: git-reference ``` This ensures older Discourse installs are able to find and install older versions of plugins without intervention, through the manifest only. It iterates through the versions in descending order. If the current Discourse version matches an item in the manifest, it checks out the listed plugin target. If the Discourse version is greater than an item in the manifest, it checks out the next highest version listed in the manifest. If no versions match, it makes no change.
This commit is contained in:
parent
2e13ed061d
commit
339549d14a
|
@ -88,6 +88,45 @@ task 'plugin:update', :plugin do |t, args|
|
|||
abort('Unable to pull latest version of plugin') unless update_status
|
||||
end
|
||||
|
||||
desc 'pull compatible plugin versions for all plugins'
|
||||
task 'plugin:pull_compatible_all' do |t|
|
||||
# Loop through each directory
|
||||
plugins = Dir.glob(File.expand_path('plugins/*')).select { |f| File.directory? f }
|
||||
# run plugin:pull_compatible
|
||||
plugins.each do |plugin|
|
||||
next unless File.directory?(plugin + "/.git")
|
||||
Rake::Task['plugin:pull_compatible'].invoke(plugin)
|
||||
Rake::Task['plugin:pull_compatible'].reenable
|
||||
end
|
||||
end
|
||||
|
||||
desc 'pull a compatible plugin version'
|
||||
task 'plugin:pull_compatible', :plugin do |t, args|
|
||||
|
||||
plugin = ENV['PLUGIN'] || ENV['plugin'] || args[:plugin]
|
||||
plugin_path = plugin
|
||||
plugin = File.basename(plugin)
|
||||
|
||||
unless File.directory?(plugin_path)
|
||||
if File.directory?('plugins/' + plugin)
|
||||
plugin_path = File.expand_path('plugins/' + plugin)
|
||||
else
|
||||
abort('Plugin ' + plugin + ' not found')
|
||||
end
|
||||
end
|
||||
|
||||
checkout_version = Discourse.find_compatible_git_resource(plugin_path)
|
||||
|
||||
# Checkout value of the version compat
|
||||
if checkout_version
|
||||
puts "checking out compatible #{plugin} version: #{checkout_version}"
|
||||
update_status = system("git -C '#{plugin_path}' reset --hard #{checkout_version}")
|
||||
abort('Unable to checkout a compatible plugin version') unless update_status
|
||||
else
|
||||
puts "#{plugin} is already at latest compatible version"
|
||||
end
|
||||
end
|
||||
|
||||
desc 'install all plugin gems'
|
||||
task 'plugin:install_all_gems' do |t|
|
||||
plugins = Dir.glob(File.expand_path('plugins/*')).select { |f| File.directory? f }
|
||||
|
|
|
@ -23,6 +23,12 @@ class ThemeStore::GitImporter
|
|||
else
|
||||
import_public!
|
||||
end
|
||||
if version = Discourse.find_compatible_git_resource(@temp_folder)
|
||||
Discourse::Utils.execute_command(chdir: @temp_folder) do |runner|
|
||||
Rails.logger.warn "git reset --hard #{version}"
|
||||
return runner.exec("git", "reset", "--hard", version)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def diff_local_changes(remote_theme_id)
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
module Discourse
|
||||
VERSION_REGEXP = /\A\d+\.\d+\.\d+(\.beta\d+)?\z/ unless defined? ::Discourse::VERSION_REGEXP
|
||||
|
||||
VERSION_COMPATIBILITY_FILENAME = ".discourse-compatibility"
|
||||
|
||||
# work around reloader
|
||||
unless defined? ::Discourse::VERSION
|
||||
module VERSION #:nodoc:
|
||||
|
@ -18,4 +20,40 @@ module Discourse
|
|||
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)
|
||||
|
||||
return unless version_list
|
||||
|
||||
version_list = YAML.load(version_list).sort_by { |version, pin| Gem::Version.new(version) }.reverse
|
||||
|
||||
# If plugin compat version is listed as less than current Discourse version, take the version/hash listed before.
|
||||
checkout_version = nil
|
||||
version_list.each do |core_compat, target|
|
||||
if Gem::Version.new(core_compat) == Gem::Version.new(::Discourse::VERSION::STRING) # Exact version match - return it
|
||||
checkout_version = target
|
||||
break
|
||||
elsif Gem::Version.new(core_compat) < Gem::Version.new(::Discourse::VERSION::STRING) # Core is on a higher version than listed, use a later version
|
||||
break
|
||||
end
|
||||
checkout_version = target
|
||||
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}")
|
||||
Discourse.find_compatible_resource(compat_resource) if s.success?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,4 +46,61 @@ describe Discourse::VERSION do
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
context "compatible_resource" do
|
||||
after do
|
||||
# Cleanup versions
|
||||
::Discourse::VERSION::STRING = [::Discourse::VERSION::MAJOR, ::Discourse::VERSION::MINOR, ::Discourse::VERSION::TINY, ::Discourse::VERSION::PRE].compact.join('.')
|
||||
end
|
||||
|
||||
shared_examples "test compatible resource" do
|
||||
it "returns nil when the current version is above all pinned versions" do
|
||||
::Discourse::VERSION::STRING = "2.6.0"
|
||||
expect(Discourse.find_compatible_resource(version_list)).to be_nil
|
||||
end
|
||||
|
||||
it "returns the correct version if matches exactly" do
|
||||
::Discourse::VERSION::STRING = "2.5.0.beta4"
|
||||
expect(Discourse.find_compatible_resource(version_list)).to eq("twofivebetafour")
|
||||
end
|
||||
|
||||
it "returns the closest matching version" do
|
||||
::Discourse::VERSION::STRING = "2.4.6.beta12"
|
||||
expect(Discourse.find_compatible_resource(version_list)).to eq("twofivebetatwo")
|
||||
end
|
||||
|
||||
it "returns the lowest version possible when using an older version" do
|
||||
::Discourse::VERSION::STRING = "1.4.6.beta12"
|
||||
expect(Discourse.find_compatible_resource(version_list)).to eq("twofourtwobetaone")
|
||||
end
|
||||
end
|
||||
|
||||
it "returns nil when nil" do
|
||||
expect(Discourse.find_compatible_resource(nil)).to be_nil
|
||||
end
|
||||
|
||||
context "with a regular compatible list" do
|
||||
let(:version_list) { <<~VERSION_LIST
|
||||
2.5.0.beta6: twofivebetasix
|
||||
2.5.0.beta4: twofivebetafour
|
||||
2.5.0.beta2: twofivebetatwo
|
||||
2.4.4.beta6: twofourfourbetasix
|
||||
2.4.2.beta1: twofourtwobetaone
|
||||
VERSION_LIST
|
||||
}
|
||||
include_examples "test compatible resource"
|
||||
end
|
||||
|
||||
context "handle a compatible resource out of order" do
|
||||
let(:version_list) { <<~VERSION_LIST
|
||||
2.4.2.beta1: twofourtwobetaone
|
||||
2.5.0.beta4: twofivebetafour
|
||||
2.5.0.beta6: twofivebetasix
|
||||
2.5.0.beta2: twofivebetatwo
|
||||
2.4.4.beta6: twofourfourbetasix
|
||||
VERSION_LIST
|
||||
}
|
||||
include_examples "test compatible resource"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue