diff --git a/lib/vagrant/action/builtin/provisioner_cleanup.rb b/lib/vagrant/action/builtin/provisioner_cleanup.rb index c76b88f39..ead72268c 100644 --- a/lib/vagrant/action/builtin/provisioner_cleanup.rb +++ b/lib/vagrant/action/builtin/provisioner_cleanup.rb @@ -32,10 +32,20 @@ module Vagrant # Ask the provisioners to modify the configuration if needed provisioner_instances(env).each do |p, _| - env[:ui].info(I18n.t( - "vagrant.provisioner_cleanup", - name: type_map[p].to_s)) - p.cleanup + name = type_map[p].to_s + + # Check if the subclass defined a cleanup method. The parent + # provisioning class defines a `cleanup` method, so we cannot use + # `respond_to?` here. Instead, we have to check if _this_ instance + # defines a cleanup task. + if p.public_methods(false).include?(:cleanup) + env[:ui].info(I18n.t("vagrant.provisioner_cleanup", + name: name, + )) + p.cleanup + else + @logger.debug("Skipping cleanup tasks for `#{name}' - not defined") + end end end end diff --git a/test/unit/vagrant/action/builtin/provisioner_cleanup_test.rb b/test/unit/vagrant/action/builtin/provisioner_cleanup_test.rb index 00132f616..2d3b907c7 100644 --- a/test/unit/vagrant/action/builtin/provisioner_cleanup_test.rb +++ b/test/unit/vagrant/action/builtin/provisioner_cleanup_test.rb @@ -55,4 +55,30 @@ describe Vagrant::Action::Builtin::ProvisionerCleanup do instance.call(env) end end + + it "only runs cleanup tasks if the subclass defines it" do + parent = Class.new do + class_variable_set(:@@cleanup, false) + + def self.called? + class_variable_get(:@@cleanup) + end + + def cleanup + self.class.class_variable_set(:@@cleanup) + end + end + + child = Class.new(parent) + + allow_any_instance_of(described_class).to receive(:provisioner_type_map) + .and_return(child => :test_provisioner) + allow_any_instance_of(described_class).to receive(:provisioner_instances) + .and_return([child]) + + expect(parent.called?).to be(false) + instance = described_class.new(app, env) + instance.call(env) + expect(parent.called?).to be(false) + end end