diff --git a/lib/tasks/compatibility.rake b/lib/tasks/compatibility.rake new file mode 100644 index 00000000000..94f37c16c24 --- /dev/null +++ b/lib/tasks/compatibility.rake @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +desc "validate a discourse-compatibility file" +task "compatibility:validate", %i[path] => :environment do |t, args| + path = args[:path] + + class CoreTooRecentError < StandardError + end + + def fail!(msg, error) + puts <<~MSG + --- FAILURE --- + #{msg.strip} + --------------- + MSG + raise error + end + + puts "Current Discourse Version: #{::Discourse::VERSION::STRING}" + puts "Checking validity of #{path}" + + content = File.read(path) + begin + result = Discourse.find_compatible_resource(content) + + puts "File parsed successfully" + + fail! <<~MSG, CoreTooRecentError if result + Compatibility file has an entry which matches the current version of Discourse core. + This is not allowed - compatibility files should only be used for older core versions + MSG + rescue Discourse::InvalidVersionListError => e + fail! "Invalid version list", e + end + + puts "Compatibility file is valid" +end diff --git a/spec/tasks/compatibility_spec.rb b/spec/tasks/compatibility_spec.rb new file mode 100644 index 00000000000..1d08b50457f --- /dev/null +++ b/spec/tasks/compatibility_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +RSpec.describe "compatibility:validate" do + before do + Rake::Task.clear + Discourse::Application.load_tasks + end + + def invoke(content) + file = Tempfile.new("discourse-compat-validate") + file.write content + file.close + error = nil + stdout = + capture_stdout do + Rake::Task["compatibility:validate"].invoke(file.path) + rescue => e + error = e + end + [error, stdout] + ensure + file.unlink + end + + it "passes for a valid .discourse-compatibility file" do + error, stdout = invoke <<~CONTENT + 2.5.0.beta6: c4a6c17 + 2.5.0.beta4: d1d2d3f + CONTENT + expect(error).to eq(nil) + expect(stdout).to include("Compatibility file is valid") + end + + it "passes for empty file" do + error, stdout = invoke "" + expect(error).to eq(nil) + expect(stdout).to include("Compatibility file is valid") + end + + it "fails for invalid YAML" do + error, stdout = invoke <<~CONTENT + 2.5.0.beta6 c4a6c17 + CONTENT + expect(error).to be_a(Discourse::InvalidVersionListError) + expect(stdout).to include("Invalid version list") + end + + it "fails for invalid version specifier" do + error, stdout = invoke <<~CONTENT + > 2.5.0.beta6: c4a6c17 + CONTENT + expect(error).to be_a(Discourse::InvalidVersionListError) + expect(stdout).to include("Invalid version list") + end + + it "fails when matching current core version" do + error, stdout = invoke <<~CONTENT + #{Discourse::VERSION::STRING}: c4a6c17 + CONTENT + expect(error).to be_a(CoreTooRecentError) + expect(stdout).to include( + "Compatibility file has an entry which matches the current version of Discourse core", + ) + end +end