diff --git a/lib/vagrant/box_metadata.rb b/lib/vagrant/box_metadata.rb index fe8e62cea..28388c7b6 100644 --- a/lib/vagrant/box_metadata.rb +++ b/lib/vagrant/box_metadata.rb @@ -68,11 +68,25 @@ module Vagrant # Returns all the versions supported by this metadata. These # versions are sorted so the last element of the list is the - # latest version. + # latest version. Optionally filter versions by a matching + # provider. # # @return[Array] - def versions - @version_map.keys.sort.map(&:to_s) + def versions(**opts) + provider = nil + provider = opts[:provider].to_sym if opts[:provider] + + if provider + @version_map.select do |version, raw| + if raw["providers"] + raw["providers"].detect do |p| + p["name"].to_sym == provider + end + end + end.keys.sort.map(&:to_s) + else + @version_map.keys.sort.map(&:to_s) + end end # Represents a single version within the metadata. diff --git a/plugins/commands/box/command/outdated.rb b/plugins/commands/box/command/outdated.rb index f7bbdfee1..dd814c93e 100644 --- a/plugins/commands/box/command/outdated.rb +++ b/plugins/commands/box/command/outdated.rb @@ -73,7 +73,7 @@ module VagrantPlugins end current = Gem::Version.new(box.version) - latest = Gem::Version.new(md.versions.last) + latest = Gem::Version.new(md.versions(provider: box.provider).last) if latest <= current @env.ui.success(I18n.t( "vagrant.box_up_to_date", diff --git a/test/unit/plugins/commands/box/command/outdated_test.rb b/test/unit/plugins/commands/box/command/outdated_test.rb new file mode 100644 index 000000000..dc5ea60d3 --- /dev/null +++ b/test/unit/plugins/commands/box/command/outdated_test.rb @@ -0,0 +1,132 @@ +require File.expand_path("../../../../../base", __FILE__) + +require Vagrant.source_root.join("plugins/commands/box/command/outdated") + +describe VagrantPlugins::CommandBox::Command::Outdated do + include_context "unit" + + let(:argv) { [] } + let(:iso_env) do + env = isolated_environment + env.vagrantfile("") + env.create_vagrant_env + end + + subject { described_class.new(argv, iso_env) } + + let(:action_runner) { double("action_runner") } + + before do + allow(iso_env).to receive(:action_runner).and_return(action_runner) + end + + context "with global argument" do + let(:argv) { ["--global"] } + + it "calls outdated_global" do + expect(subject).to receive(:outdated_global) + + subject.execute + end + + before do + + end + + describe ".outdated_global" do + let(:test_iso_env) { isolated_environment } + + let(:md) { + md = Vagrant::BoxMetadata.new(StringIO.new(<<-RAW)) + { + "name": "foo", + "versions": [ + { + "version": "1.0" + }, + { + "version": "1.1", + "providers": [ + { + "name": "virtualbox", + "url": "bar" + } + ] + }, + { + "version": "1.2", + "providers": [ + { + "name": "vmware", + "url": "baz" + } + ] + } + ] + } + RAW + } + + let(:collection) do + collection = double("collection") + allow(collection).to receive(:all).and_return([box]) + allow(collection).to receive(:find).and_return(box) + collection + end + + context "when latest version is available for provider" do + let(:box) do + box_dir = test_iso_env.box3("foo", "1.0", :vmware) + box = Vagrant::Box.new( + "foo", :vmware, "1.0", box_dir, metadata_url: "foo") + allow(box).to receive(:load_metadata).and_return(md) + box + end + + it "displays the latest version" do + allow(iso_env).to receive(:boxes).and_return(collection) + + expect(I18n).to receive(:t).with(/box_outdated$/, hash_including(latest: "1.2")) + + subject.outdated_global({}) + end + end + + context "when latest version isn't available for provider" do + let(:box) do + box_dir = test_iso_env.box3("foo", "1.0", :virtualbox) + box = Vagrant::Box.new( + "foo", :virtualbox, "1.0", box_dir, metadata_url: "foo") + allow(box).to receive(:load_metadata).and_return(md) + box + end + + it "displays the latest version for that provider" do + allow(iso_env).to receive(:boxes).and_return(collection) + + expect(I18n).to receive(:t).with(/box_outdated$/, hash_including(latest: "1.1")) + + subject.outdated_global({}) + end + end + + context "when no versions are available for provider" do + let(:box) do + box_dir = test_iso_env.box3("foo", "1.0", :libvirt) + box = Vagrant::Box.new( + "foo", :libvirt, "1.0", box_dir, metadata_url: "foo") + allow(box).to receive(:load_metadata).and_return(md) + box + end + + it "displays up to date message" do + allow(iso_env).to receive(:boxes).and_return(collection) + + expect(I18n).to receive(:t).with(/box_up_to_date$/, hash_including(version: "1.0")) + + subject.outdated_global({}) + end + end + end + end +end diff --git a/test/unit/vagrant/box_metadata_test.rb b/test/unit/vagrant/box_metadata_test.rb index de3950c3b..91f505239 100644 --- a/test/unit/vagrant/box_metadata_test.rb +++ b/test/unit/vagrant/box_metadata_test.rb @@ -115,6 +115,11 @@ describe Vagrant::BoxMetadata do expect(subject.versions).to eq( ["1.0.0", "1.1.0", "1.1.5"]) end + + it "filters versions by matching provider" do + expect(subject.versions(provider: :vmware)).to eq( + ["1.0.0", "1.1.0"]) + end end end diff --git a/website/source/docs/cli/box.html.md b/website/source/docs/cli/box.html.md index cfc95725b..2c65a6d6c 100644 --- a/website/source/docs/cli/box.html.md +++ b/website/source/docs/cli/box.html.md @@ -119,6 +119,9 @@ This command tells you whether or not the box you are using in your current Vagrant environment is outdated. If the `--global` flag is present, every installed box will be checked for updates. +This will show the latest version available for the specific provider type, +which may be different than the absolute latest version available. + Checking for updates involves refreshing the metadata associated with a box. This generally requires an internet connection.