diff --git a/lib/vagrant/bundler.rb b/lib/vagrant/bundler.rb index 336ac1e05..66af9763c 100644 --- a/lib/vagrant/bundler.rb +++ b/lib/vagrant/bundler.rb @@ -234,6 +234,8 @@ module Vagrant Gem::Specification.reset end + enable_prerelease!(specs: @initial_specifications) + solution_file = load_solution_file(opts) @logger.debug("solution file in use for init: #{solution_file}") @@ -464,6 +466,30 @@ module Vagrant protected + # This will enable prerelease if any of the root dependency constraints + # include prerelease versions + # + # @param [Array] spec_list List of specifications + # @param [Gem::RequestSet] rs Request set of dependencies + def enable_prerelease!(specs: nil, request_set: nil) + pre = specs.detect do |spec| + spec.version.prerelease? + end if specs + if pre + @logger.debug("Enabling prerelease plugin resolution due to dependency: #{pre.full_name}") + ENV["VAGRANT_ALLOW_PRERELEASE"] = "1" + return + end + dep = request_set.dependencies.detect do |d| + d.prerelease? + end if request_set + if dep + @logger.debug("Enabling prerelease plugin resolution due to dependency: #{dep}") + ENV["VAGRANT_ALLOW_PRERELEASE"] = "1" + return + end + end + def internal_install(plugins, update, **extra) update = {} if !update.is_a?(Hash) skips = [] @@ -550,6 +576,7 @@ module Vagrant # Create the request set for the new plugins request_set = Gem::RequestSet.new(*plugin_deps) + enable_prerelease!(request_set: request_set) request_set.prerelease = Vagrant.prerelease? installer_set = Gem::Resolver.compose_sets( @@ -740,7 +767,6 @@ module Vagrant request.name == matcher["gem_name"] end if desired_activation_request && !desired_activation_request.full_spec.activated? - activation_request = desired_activation_request @logger.warn("Found misordered activation request for #{desired_activation_request.full_name}. Moving to solution HEAD.") solution.delete(desired_activation_request) solution.unshift(desired_activation_request) @@ -813,7 +839,8 @@ module Vagrant def find_all(req) @specs.select do |spec| - allow_prerelease = spec.name == "vagrant" && Vagrant.prerelease? + allow_prerelease = Vagrant.allow_prerelease_dependencies? || + spec.name == "vagrant" && Vagrant.prerelease? req.match?(spec, allow_prerelease) end.map do |spec| Gem::Resolver::InstalledSpecification.new(self, spec) @@ -861,7 +888,7 @@ module Vagrant ## # Loads a spec with the given +name+. +version+, +platform+ and +source+ are # ignored. - def load_spec (name, version, platform, source) + def load_spec(name, version, platform, source) version = Gem::Version.new(version) if !version.is_a?(Gem::Version) @specs.fetch(name, []).detect{|s| s.name == name && s.version == version} end diff --git a/lib/vagrant/shared_helpers.rb b/lib/vagrant/shared_helpers.rb index ae45ea305..f14dbe08a 100644 --- a/lib/vagrant/shared_helpers.rb +++ b/lib/vagrant/shared_helpers.rb @@ -122,8 +122,15 @@ module Vagrant # # @return [Boolean] def self.prerelease? - !!ENV["VAGRANT_ALLOW_PRERELEASE"] || - Gem::Version.new(Vagrant::VERSION).prerelease? + Gem::Version.new(Vagrant::VERSION).prerelease? + end + + # This returns true/false if the Vagrant should allow prerelease + # versions when resolving plugin dependency constraints + # + # @return [Boolean] + def self.allow_prerelease_dependencies? + !!ENV["VAGRANT_ALLOW_PRERELEASE"] end # This allows control over dependency resolution when installing diff --git a/test/unit/vagrant/bundler_test.rb b/test/unit/vagrant/bundler_test.rb index 89391c013..8dcae5b14 100644 --- a/test/unit/vagrant/bundler_test.rb +++ b/test/unit/vagrant/bundler_test.rb @@ -618,6 +618,117 @@ describe Vagrant::Bundler do end end end + + describe "#enable_prerelease!" do + before do + @_ev = ENV.delete("VAGRANT_ALLOW_PRERELEASE") + end + + after do + ENV["VAGRANT_ALLOW_PRERELEASE"] = @_ev + end + + context "with specification list" do + let(:specifications) { [] } + + it "should not modify prerelease by default" do + subject.send(:enable_prerelease!, specs: specifications) + expect(ENV["VAGRANT_ALLOW_PRERELEASE"]).to be_falsey + end + + it "should not have enabled allow prerelease dependencies" do + subject.send(:enable_prerelease!, specs: specifications) + expect(Vagrant.allow_prerelease_dependencies?).to be_falsey + end + + context "when specifications do not contain prerelease versions" do + let(:specifications) { [ + double("spec1", full_name: "spec1", version: double("version1", prerelease?: false)), + double("spec2", full_name: "spec2", version: double("version2", prerelease?: false)), + double("spec3", full_name: "spec3", version: double("version3", prerelease?: false)) + ] } + + it "should not modify prerelease" do + subject.send(:enable_prerelease!, specs: specifications) + expect(ENV["VAGRANT_ALLOW_PRERELEASE"]).to be_falsey + end + + it "should not have enabled allow prerelease dependencies" do + subject.send(:enable_prerelease!, specs: specifications) + expect(Vagrant.allow_prerelease_dependencies?).to be_falsey + end + end + + context "when specifications contain prerelease versions" do + let(:specifications) { [ + double("spec1", full_name: "spec1", version: double("version1", prerelease?: false)), + double("spec2", full_name: "spec2", version: double("version2", prerelease?: true)), + double("spec3", full_name: "spec3", version: double("version3", prerelease?: false)) + ] } + + it "should enable prerelease" do + subject.send(:enable_prerelease!, specs: specifications) + expect(ENV["VAGRANT_ALLOW_PRERELEASE"]).to be_truthy + end + + it "should have enabled allow prerelease dependencies" do + subject.send(:enable_prerelease!, specs: specifications) + expect(Vagrant.allow_prerelease_dependencies?).to be_truthy + end + end + end + + context "with request set" do + let(:request_set) { double("request_set", dependencies: dependencies) } + let(:dependencies) { [] } + + it "should not modify prerelease by default" do + subject.send(:enable_prerelease!, request_set: request_set) + expect(ENV["VAGRANT_ALLOW_PRERELEASE"]).to be_falsey + end + + it "should not have enabled allow prerelease dependencies" do + subject.send(:enable_prerelease!, request_set: request_set) + expect(Vagrant.allow_prerelease_dependencies?).to be_falsey + end + + context "when specifications do not contain prerelease versions" do + let(:dependencies) { [ + double("dep1", prerelease?: false, to_s: nil), + double("dep2", prerelease?: false, to_s: nil), + double("dep3", prerelease?: false, to_s: nil) + ] } + + it "should not modify prerelease" do + subject.send(:enable_prerelease!, request_set: request_set) + expect(ENV["VAGRANT_ALLOW_PRERELEASE"]).to be_falsey + end + + it "should not have enabled allow prerelease dependencies" do + subject.send(:enable_prerelease!, request_set: request_set) + expect(Vagrant.allow_prerelease_dependencies?).to be_falsey + end + end + + context "when specifications contain prerelease versions" do + let(:dependencies) { [ + double("dep1", prerelease?: false, to_s: nil), + double("dep2", prerelease?: true, to_s: nil), + double("dep3", prerelease?: false, to_s: nil) + ] } + + it "should enable prerelease" do + subject.send(:enable_prerelease!, request_set: request_set) + expect(ENV["VAGRANT_ALLOW_PRERELEASE"]).to be_truthy + end + + it "should have enabled allow prerelease dependencies" do + subject.send(:enable_prerelease!, request_set: request_set) + expect(Vagrant.allow_prerelease_dependencies?).to be_truthy + end + end + end + end end describe Vagrant::Bundler::PluginSet do diff --git a/test/unit/vagrant/shared_helpers_test.rb b/test/unit/vagrant/shared_helpers_test.rb index 781c882ea..a2d1b5b59 100644 --- a/test/unit/vagrant/shared_helpers_test.rb +++ b/test/unit/vagrant/shared_helpers_test.rb @@ -142,24 +142,22 @@ describe Vagrant do stub_const("Vagrant::VERSION", "1.0.0") expect(subject.prerelease?).to be(false) end + end + describe ".allow_prerelease_dependencies?" do context "with environment variable set" do before { allow(ENV).to receive(:[]).with("VAGRANT_ALLOW_PRERELEASE").and_return("1") } - context "when version is development version" do - before { stub_const("Vagrant::VERSION", "1.0.0.dev") } - - it "should return true" do - expect(subject.prerelease?).to be(true) - end + it "should return true" do + expect(subject.allow_prerelease_dependencies?).to be(true) end + end - context "when version is non-development version" do - before { stub_const("Vagrant::VERSION", "1.0.0") } + context "with environment variable unset" do + before { allow(ENV).to receive(:[]).with("VAGRANT_ALLOW_PRERELEASE").and_return(nil) } - it "should return true" do - expect(subject.prerelease?).to be(true) - end + it "should return false" do + expect(subject.allow_prerelease_dependencies?).to be(false) end end end