summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThom May <thom@may.lt>2018-06-18 17:50:07 +0100
committerGitHub <noreply@github.com>2018-06-18 17:50:07 +0100
commitd5907bf00781fd82adac6182cc398f2dc0975900 (patch)
tree61108d0403077f2c54358c8fde0040206c04a478
parente07f9e716008251f82ea3e5f255a250c28109363 (diff)
parent7a12fa4b66d18b79233c2c29de5cead0ea0c1af9 (diff)
downloadchef-d5907bf00781fd82adac6182cc398f2dc0975900.tar.gz
Merge pull request #7375 from coderanger/silence-deprecations
Silence deprecation warnings
-rw-r--r--RELEASE_NOTES.md49
-rw-r--r--chef-config/lib/chef-config/config.rb5
-rw-r--r--lib/chef/chef_class.rb24
-rw-r--r--lib/chef/deprecated.rb282
-rw-r--r--lib/chef/formatters/base.rb15
-rw-r--r--lib/chef/formatters/doc.rb16
-rw-r--r--lib/chef/log.rb18
-rw-r--r--lib/chef/node_map.rb19
-rw-r--r--spec/integration/knife/common_options_spec.rb2
-rw-r--r--spec/unit/chef_class_spec.rb120
-rw-r--r--spec/unit/deprecated_spec.rb30
-rw-r--r--spec/unit/node_map_spec.rb14
12 files changed, 357 insertions, 237 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index d9747c80df..85181821c6 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,54 @@
This file holds "in progress" release notes for the current release under development and is intended for consumption by the Chef Documentation team. Please see <https://docs.chef.io/release_notes.html> for the official Chef release notes.
+## Silencing deprecation warnings
+
+While deprecation warnings have been great for the Chef community to ensure
+cookbooks are kept up-to-date and to prepare for major version upgrades, sometimes
+you just can't fix a deprecation right now. This is often compounded by the
+recommendation to enable `treat_deprecation_warnings_as_errors` mode in your
+Test Kitchen integration tests, which doesn't understand the difference between
+deprecations from community cookbooks and those from your own code.
+
+Two new options are provided for silencing deprecation warnings: `silence_deprecation_warnings`
+and inline `chef:silence_deprecation` comments.
+
+The `silence_deprecation_warnings` configuration value can be set in your
+`client.rb` or `solo.rb` config file, either to `true` to silence all deprecation
+warnings or to an array of deprecations to silence. You can specify which to
+silence either by the deprecation key name (e.g. `"internal_api"`), the numeric
+deprecation ID (e.g. `25` or `"CHEF-25"`), or by specifying the filename and
+line number where the deprecation is being raised from (e.g. `"default.rb:67"`).
+
+An example of setting the `silence_deprecation_warnings` option in your `client.rb`
+or `solo.rb`:
+
+```ruby
+silence_deprecation_warnings %w{deploy_resource chef-23 recipes/install.rb:22}
+```
+
+or in your `kitchen.yml`:
+
+```yaml
+provisioner:
+ name: chef_solo
+ solo_rb:
+ treat_deprecation_warnings_as_errors: true
+ silence_deprecation_warnings:
+ - deploy_resource
+ - chef-23
+ - recipes/install.rb:22
+```
+
+You can also silence deprecations using a comment on the line that is raising
+the warning:
+
+```ruby
+erl_call 'something' do # chef:silence_deprecation
+```
+
+We advise caution in the use of this feature, as excessive or prolonged silencing
+can lead to difficulty upgrading when the next major release of Chef comes out.
+
# Chef Client Release Notes 14.2:
## `ssh-agent` support for user keys
diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb
index 82f25f4139..ed8fab9ee4 100644
--- a/chef-config/lib/chef-config/config.rb
+++ b/chef-config/lib/chef-config/config.rb
@@ -715,6 +715,11 @@ module ChefConfig
ENV.key?("CHEF_TREAT_DEPRECATION_WARNINGS_AS_ERRORS")
end
+ # Which deprecations warnings to silence. Can be set to `true` to silence
+ # all warnings, or an array of strings like either `"deprecation_type"` or
+ # `"filename.rb:lineno"`.
+ default :silence_deprecation_warnings, []
+
# Whether the resource count should be updated for log resource
# on running chef-client
default :count_log_resource_updates, true
diff --git a/lib/chef/chef_class.rb b/lib/chef/chef_class.rb
index bfea51609a..95b03f1c5c 100644
--- a/lib/chef/chef_class.rb
+++ b/lib/chef/chef_class.rb
@@ -200,13 +200,14 @@ class Chef
#
# Emit a deprecation message.
#
- # @param [Symbol] type The message to send. This should refer to a class
+ # @param type [Symbol] The message to send. This should refer to a class
# defined in Chef::Deprecated
- # @param message An explicit message to display, rather than the generic one
- # associated with the deprecation.
- # @param location The location. Defaults to the caller who called you (since
- # generally the person who triggered the check is the one that needs to be
- # fixed).
+ # @param message [String, nil] An explicit message to display, rather than
+ # the generic one associated with the deprecation.
+ # @param location [String, nil] The location. Defaults to the caller who
+ # called you (since generally the person who triggered the check is the one
+ # that needs to be fixed).
+ # @return [void]
#
# @example
# Chef.deprecated(:my_deprecation, message: "This is deprecated!")
@@ -220,11 +221,18 @@ class Chef
# run. If we are not yet in a run, print to `Chef::Log`.
if run_context && run_context.events
run_context.events.deprecation(deprecation, location)
- else
- Chef::Log.deprecation(deprecation, location)
+ elsif !deprecation.silenced?
+ Chef::Log.deprecation(deprecation.to_s)
end
end
+ # Log a generic deprecation warning that doesn't have a specific class in
+ # Chef::Deprecated.
+ #
+ # This should generally not be used, as the user will not be given a link
+ # to get more infomration on fixing the deprecation warning.
+ #
+ # @see #deprecated
def log_deprecation(message, location = nil)
location ||= Chef::Log.caller_location
Chef.deprecated(:generic, message, location)
diff --git a/lib/chef/deprecated.rb b/lib/chef/deprecated.rb
index 904578ff0b..d9a8df7b83 100644
--- a/lib/chef/deprecated.rb
+++ b/lib/chef/deprecated.rb
@@ -24,276 +24,196 @@ class Chef
class << self
include Chef::Mixin::ConvertToClassName
- def create(type, message = nil, location = nil)
- Chef::Deprecated.const_get(convert_to_class_name(type.to_s)).send(:new, message, location)
+ def create(type, message, location)
+ Chef::Deprecated.const_get(convert_to_class_name(type.to_s)).new(message, location)
end
end
class Base
BASE_URL = "https://docs.chef.io/deprecations_"
- attr_accessor :message, :location
+ attr_reader :message, :location
def initialize(msg = nil, location = nil)
- @message = msg if msg
- @location = location if location
+ @message = msg
+ @location = location
end
def link
"Please see #{url} for further details and information on how to correct this problem."
end
+ # Render the URL for the deprecation documentation page.
+ #
+ # @return [String]
def url
- "#{BASE_URL}#{target}"
- end
-
- # We know that the only time this gets called is by Chef::Log.deprecation,
- # so special case
- def <<(location)
- @location = location
- end
-
- def inspect
- "#{message} (CHEF-#{id})#{location}.\n#{link}"
- end
-
- def id
- raise NotImplementedError, "subclasses of Chef::Deprecated::Base should define #id with a unique number"
- end
-
- def target
- raise NotImplementedError, "subclasses of Chef::Deprecated::Base should define #target"
+ "#{BASE_URL}#{self.class.doc_page}"
+ end
+
+ # Render the user-visible message for this deprecation.
+ #
+ # @return [String]
+ def to_s
+ "Deprecation CHEF-#{self.class.deprecation_id} from #{location}\n\n #{message}\n\n#{link}"
+ end
+
+ # Check if this deprecation has been silenced.
+ #
+ # @return [Boolean]
+ def silenced?
+ # Check if all warnings have been silenced.
+ return true if Chef::Config[:silence_deprecation_warnings] == true
+ # Check if this warning has been silenced by the config.
+ return true if Chef::Config[:silence_deprecation_warnings].any? do |silence_spec|
+ # Just in case someone uses a symbol in the config by mistake.
+ silence_spec = silence_spec.to_s
+ # Check for a silence by deprecation name, or by location.
+ self.class.deprecation_key == silence_spec || self.class.deprecation_id.to_s == silence_spec || "chef-#{self.class.deprecation_id}" == silence_spec.downcase || location.include?(silence_spec)
+ end
+ # check if this warning has been silenced by inline comment.
+ return true if location =~ /^(.*?):(\d+):in/ && begin
+ # Don't buffer the whole file in memory, so read it one line at a time.
+ line_no = $2.to_i
+ location_file = ::File.open($1)
+ (line_no - 1).times { location_file.readline } # Read all the lines we don't care about.
+ relevant_line = location_file.readline
+ relevant_line.match?(/#.*chef:silence_deprecation($|[^:]|:#{self.class.deprecation_key})/)
+ end
+ false
+ end
+
+ class << self
+ attr_reader :deprecation_id, :doc_page
+
+ # Return the deprecation key as would be used with {Chef::Deprecated.create}.
+ #
+ # @return [String]
+ def deprecation_key
+ Chef::Mixin::ConvertToClassName.convert_to_snake_case(name, "Chef::Deprecated")
+ end
+
+ # Set the ID and documentation page path for this deprecation.
+ #
+ # Used in subclasses to set the data for each type of deprecation.
+ #
+ # @example
+ # class MyDeprecation < Base
+ # target 123, "my_deprecation.html"
+ # end
+ # @param id [Integer] Deprecation ID number. This must be unique among
+ # all deprecations.
+ # @param page [String, nil] Optional documentation page path. If not
+ # specified, the deprecation key is used.
+ # @return [void]
+ def target(id, page = nil)
+ @deprecation_id = id
+ @doc_page = page || "#{deprecation_key}.html"
+ end
end
end
class InternalApi < Base
- def id
- 0
- end
-
- def target
- "internal_api.html"
- end
+ target 0
end
class JsonAutoInflate < Base
- def id
- 1
- end
-
- def target
- "json_auto_inflate.html"
- end
+ target 1
end
class ExitCode < Base
- def id
- 2
- end
-
- def target
- "exit_code.html"
- end
+ target 2
end
# id 3 has been deleted
class Attributes < Base
- def id
- 4
- end
-
- def target
- "attributes.html"
- end
+ target 4
end
class CustomResource < Base
- def id
- 5
- end
-
- def target
- "custom_resource_cleanups.html"
- end
+ target 5, "custom_resource_cleanups.html"
end
class EasyInstall < Base
- def id
- 6
- end
-
- def target
- "easy_install.html"
- end
+ target 6
end
class VerifyFile < Base
- def id
- 7
- end
-
- def target
- "verify_file.html"
- end
+ target 7
end
class SupportsProperty < Base
- def id
- 8
- end
-
- def target
- "supports_property.html"
- end
+ target 8
end
class ChefRest < Base
- def id
- 9
- end
-
- def target
- "chef_rest.html"
- end
+ target 9
end
class DnfPackageAllowDowngrade < Base
- def id
- 10
- end
-
- def target
- "dnf_package_allow_downgrade.html"
- end
+ target 10
end
class PropertyNameCollision < Base
- def id
- 11
- end
-
- def target
- "property_name_collision.html"
- end
+ target 11
end
class LaunchdHashProperty < Base
- def id
- 12
- end
-
- def target
- "launchd_hash_property.html"
- end
+ target 12
end
class ChefPlatformMethods < Base
- def id
- 13
- end
-
- def target
- "chef_platform_methods.html"
- end
+ target 13
end
class RunCommand < Base
- def id
- 14
- end
-
- def target
- "run_command.html"
- end
+ target 14
end
class PackageMisc < Base
- def id
- 15
- end
-
- def target
- "package_misc.html"
- end
+ target 15
end
class MultiresourceMatch < Base
- def id
- 16
- end
-
- def target
- "multiresource_match.html"
- end
+ target 16
end
class UseInlineResources < Base
- def id
- 17
- end
-
- def target
- "use_inline_resources.html"
- end
+ target 17
end
class LocalListen < Base
- def id
- 18
- end
-
- def target
- "local_listen.html"
- end
+ target 18
end
class NamespaceCollisions < Base
- def id
- 19
- end
-
- def target
- "namespace_collisions.html"
- end
+ target 19
end
class DeployResource < Base
- def id
- 21
- end
-
- def target
- "deploy_resource.html"
- end
+ target 21
end
class ErlResource < Base
- def id
- 22
- end
-
- def target
- "erl_resource.html"
- end
+ target 22
end
class FreebsdPkgProvider < Base
- def id
- 23
- end
+ target 23
+ end
- def target
- "freebsd_pkg_provider.html"
- end
+ class MapCollision < Base
+ target 25
end
# id 3694 was deleted
# Returned when using the deprecated option on a property
class Property < Base
- def inspect
- "#{message}\n#{location}"
+ target 24
+
+ def to_s
+ "Deprecated resource property used from #{location}\n\n #{message}\n\nPlease consult the resource documentation for more information."
end
end
@@ -302,8 +222,8 @@ class Chef
"https://docs.chef.io/chef_deprecations_client.html"
end
- def inspect
- "#{message}\nThis is a generic error message and should be updated to have a proper deprecation class. #{location}\nPlease see #{url} for an overview of Chef deprecations."
+ def to_s
+ "Deprecation from #{location}\n\n #{message}\n\n#{link}"
end
end
diff --git a/lib/chef/formatters/base.rb b/lib/chef/formatters/base.rb
index 0b27b55048..997577aa7b 100644
--- a/lib/chef/formatters/base.rb
+++ b/lib/chef/formatters/base.rb
@@ -212,14 +212,13 @@ class Chef
file_load_failed(path, exception)
end
- def deprecation(message, location = caller(2..2)[0])
- out = if is_structured_deprecation?(message)
- message.inspect
- else
- "#{message} at #{location}"
- end
-
- Chef::Log.deprecation(out)
+ # Log a deprecation warning object.
+ #
+ # @param deprecation [Chef::Deprecated::Base] Deprecation object to log.
+ # In previous versions, this could be a string. Don't do that anymore.
+ # @param location [Object] Unused, present only for compatbility.
+ def deprecation(deprecation, _location = nil)
+ Chef::Log.deprecation(deprecation.to_s) unless deprecation.silenced?
end
def is_structured_deprecation?(deprecation)
diff --git a/lib/chef/formatters/doc.rb b/lib/chef/formatters/doc.rb
index 0c51cc2cfb..d47ab73a30 100644
--- a/lib/chef/formatters/doc.rb
+++ b/lib/chef/formatters/doc.rb
@@ -414,19 +414,15 @@ class Chef
end
end
- def deprecation(message, location = caller(2..2)[0])
+ # (see Base#deprecation)
+ def deprecation(deprecation, _location = nil)
if Chef::Config[:treat_deprecation_warnings_as_errors]
super
+ elsif !deprecation.silenced?
+ # Save non-silenced deprecations to the screen until the end.
+ deprecations[deprecation.message] ||= { url: deprecation.url, locations: Set.new }
+ deprecations[deprecation.message][:locations] << deprecation.location
end
-
- # Save deprecations to the screen until the end
- if is_structured_deprecation?(message)
- url = message.url
- message = message.message
- end
-
- deprecations[message] ||= { url: url, locations: Set.new }
- deprecations[message][:locations] << location
end
def indent
diff --git a/lib/chef/log.rb b/lib/chef/log.rb
index 10c9f0f20d..3f77158579 100644
--- a/lib/chef/log.rb
+++ b/lib/chef/log.rb
@@ -46,19 +46,21 @@ class Chef
#
def self.caller_location
# Pick the first caller that is *not* part of the Chef gem, that's the
- # thing the user wrote.
+ # thing the user wrote. Or failing that, the most recent caller.
chef_gem_path = File.expand_path("../..", __FILE__)
- caller(0..20).find { |c| !c.start_with?(chef_gem_path) }
+ caller(0..20).find { |c| !c.start_with?(chef_gem_path) } || caller(0..1)[0]
end
- def self.deprecation(msg = nil, location = caller(2..2)[0], &block)
- if msg
- msg << " at #{Array(location).join("\n")}"
- msg = msg.join("") if msg.respond_to?(:join)
- end
+ # Log a deprecation warning.
+ #
+ # If the treat_deprecation_warnings_as_errors config option is set, this
+ # will raise an exception instead.
+ #
+ # @param msg [String] Deprecation message to display.
+ def self.deprecation(msg, &block)
if Chef::Config[:treat_deprecation_warnings_as_errors]
error(msg, &block)
- raise Chef::Exceptions::DeprecatedFeatureError.new(msg.inspect)
+ raise Chef::Exceptions::DeprecatedFeatureError.new(msg)
else
warn(msg, &block)
end
diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb
index 634786af93..c0066bfce5 100644
--- a/lib/chef/node_map.rb
+++ b/lib/chef/node_map.rb
@@ -37,6 +37,21 @@
#
class Chef
class NodeMap
+ COLLISION_WARNING_14 = <<-EOH.gsub(/\s+/, " ").strip
+%{type_caps} %{key} has been loaded from a cookbook. The %{type} %{key} is now
+included in Chef and will take precedence over the existing cookbook %{type} in the
+next major release of Chef (15.0, April 2019). You may be able to remove this cookbook dependency from
+your runlist if you do not use other recipes/resources/libraries from the cookbook.
+Alternatively there may be a newer version of this cookbook without the %{key} %{type}.
+EOH
+
+ COLLISION_WARNING_15 = <<-EOH.gsub(/\s+/, " ").strip
+%{type_caps} %{key} attempted to load from a cookbook. The %{type} %{key} is now
+included in Chef and takes precedence over the existing cookbook %{type}
+which will be ignored. You may be able to remove this cookbook dependency from
+your runlist if you do not use other recipes/resources/libraries from the cookbook.
+Alternatively there may be a newer version of this cookbook without the %{key} %{type}.
+EOH
#
# Set a key/value pair on the map with a filter. The filter must be true
@@ -85,9 +100,9 @@ class Chef
klass.superclass.to_s
end
# For now, only log the warning.
- Chef.log_deprecation("Trying to register #{type_of_thing} #{key} on top of existing Chef core #{type_of_thing}. Check if a new version of the cookbook is available.")
+ Chef.deprecated(:map_collision, COLLISION_WARNING_14 % { type: type_of_thing, key: key, type_caps: type_of_thing.capitalize })
# In 15.0, uncomment this and remove the log above.
- # Chef.log_deprecation("Rejecting attempt to register #{type_of_thing} #{key} on top of existing Chef core #{type_of_thing}. Check if a new version of the cookbook is available.")
+ # Chef.deprecated(:map_collision, COLLISION_WARNING_15 % {type: type_of_thing, key: key, type_caps: type_of_thing.capitalize}))
# return
end
diff --git a/spec/integration/knife/common_options_spec.rb b/spec/integration/knife/common_options_spec.rb
index 6b6b83aafe..da1409456b 100644
--- a/spec/integration/knife/common_options_spec.rb
+++ b/spec/integration/knife/common_options_spec.rb
@@ -28,7 +28,7 @@ describe "knife common options", :workstation do
Chef::Config.treat_deprecation_warnings_as_errors(false)
end
- let(:local_listen_warning) { /\Awarn:.*local.*listen.*$/i }
+ let(:local_listen_warning) { /\Awarn:.*local.*listen.*$/im }
when_the_repository "has a node" do
before { file "nodes/x.json", {} }
diff --git a/spec/unit/chef_class_spec.rb b/spec/unit/chef_class_spec.rb
index 21987c01ab..2f370388fa 100644
--- a/spec/unit/chef_class_spec.rb
+++ b/spec/unit/chef_class_spec.rb
@@ -107,4 +107,124 @@ describe "Chef class" do
end.to raise_error(Chef::Exceptions::InvalidEventType)
end
end
+
+ describe "Deprecation system" do
+ context "with treat_deprecation_warnings_as_errors false" do
+ before { Chef::Config[:treat_deprecation_warnings_as_errors] = false }
+
+ it "displays a simple deprecation warning" do
+ expect(Chef::Log).to receive(:warn).with(%r{spec/unit/chef_class_spec\.rb.*?I'm a little teapot.*?Please see}m)
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ end
+
+ it "allows silencing all warnings" do
+ Chef::Config[:silence_deprecation_warnings] = true
+ expect(Chef::Log).to_not receive(:warn)
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:internal_api, "Short and stout.")
+ Chef.deprecated(:generic, "This is my handle.")
+ end
+
+ it "allows silencing specific types" do
+ Chef::Config[:silence_deprecation_warnings] = [:internal_api]
+ expect(Chef::Log).to receive(:warn).with(/I'm a little teapot/).once
+ expect(Chef::Log).to receive(:warn).with(/This is my handle/).once
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:internal_api, "Short and stout.")
+ Chef.deprecated(:generic, "This is my handle.")
+ end
+
+ it "allows silencing specific IDs" do
+ Chef::Config[:silence_deprecation_warnings] = [0]
+ expect(Chef::Log).to receive(:warn).with(/I'm a little teapot/).once
+ expect(Chef::Log).to receive(:warn).with(/This is my handle/).once
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:internal_api, "Short and stout.")
+ Chef.deprecated(:generic, "This is my handle.")
+ end
+
+ it "allows silencing specific IDs using the CHEF- syntax" do
+ Chef::Config[:silence_deprecation_warnings] = ["CHEF-0"]
+ expect(Chef::Log).to receive(:warn).with(/I'm a little teapot/).once
+ expect(Chef::Log).to receive(:warn).with(/This is my handle/).once
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:internal_api, "Short and stout.")
+ Chef.deprecated(:generic, "This is my handle.")
+ end
+
+ it "allows silencing specific IDs using the chef- syntax" do
+ Chef::Config[:silence_deprecation_warnings] = ["chef-0"]
+ expect(Chef::Log).to receive(:warn).with(/I'm a little teapot/).once
+ expect(Chef::Log).to receive(:warn).with(/This is my handle/).once
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:internal_api, "Short and stout.")
+ Chef.deprecated(:generic, "This is my handle.")
+ end
+
+ it "allows silencing specific lines" do
+ Chef::Config[:silence_deprecation_warnings] = ["chef_class_spec.rb:#{__LINE__ + 4}"]
+ expect(Chef::Log).to receive(:warn).with(/I'm a little teapot/).once
+ expect(Chef::Log).to receive(:warn).with(/This is my handle/).once
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:generic, "Short and stout.")
+ Chef.deprecated(:internal_api, "This is my handle.")
+ end
+
+ it "allows silencing all via inline comments" do
+ expect(Chef::Log).to receive(:warn).with(/I'm a little teapot/).once
+ expect(Chef::Log).to receive(:warn).with(/This is my handle/).once
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:generic, "Short and stout.") # chef:silence_deprecation
+ Chef.deprecated(:internal_api, "This is my handle.")
+ end
+
+ it "allows silencing specific types via inline comments" do
+ expect(Chef::Log).to receive(:warn).with(/I'm a little teapot/).once
+ expect(Chef::Log).to receive(:warn).with(/This is my handle/).once
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:generic, "Short and stout.") # chef:silence_deprecation:generic
+ Chef.deprecated(:internal_api, "This is my handle.")
+ end
+
+ it "does not silence via inline comments when the types don't match" do
+ expect(Chef::Log).to receive(:warn).with(/I'm a little teapot/).once
+ expect(Chef::Log).to receive(:warn).with(/Short and stout/).once
+ expect(Chef::Log).to receive(:warn).with(/This is my handle/).once
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:internal_api, "Short and stout.") # chef:silence_deprecation:generic
+ Chef.deprecated(:internal_api, "This is my handle.")
+ end
+
+ it "allows silencing all via inline comments with other stuff in the comment" do
+ expect(Chef::Log).to receive(:warn).with(/I'm a little teapot/).once
+ expect(Chef::Log).to receive(:warn).with(/This is my handle/).once
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:generic, "Short and stout.") # rubocop:something chef:silence_deprecation other stuff
+ Chef.deprecated(:internal_api, "This is my handle.")
+ end
+
+ it "handles multiple silence configurations at the same time" do
+ Chef::Config[:silence_deprecation_warnings] = ["exit_code", "chef_class_spec.rb:#{__LINE__ + 6}"]
+ expect(Chef::Log).to receive(:warn).with(/I'm a little teapot/).once
+ expect(Chef::Log).to receive(:warn).with(/This is my spout/).once
+ expect(Chef::Log).to receive(:warn).with(/Hear me shout/).once
+ Chef.deprecated(:generic, "I'm a little teapot.")
+ Chef.deprecated(:generic, "Short and stout.") # chef:silence_deprecation
+ Chef.deprecated(:internal_api, "This is my handle.")
+ Chef.deprecated(:internal_api, "This is my spout.")
+ Chef.deprecated(:exit_code, "When I get all steamed up.")
+ Chef.deprecated(:generic, "Hear me shout.")
+ end
+ end
+
+ context "with treat_deprecation_warnings_as_errors true" do
+ # This is already turned on globally for Chef's unit tests, but just for clarity do it here too.
+ before { Chef::Config[:treat_deprecation_warnings_as_errors] = true }
+
+ it "displays a simple deprecation error" do
+ expect(Chef::Log).to receive(:error).with(%r{spec/unit/chef_class_spec\.rb.*?I'm a little teapot.*?Please see}m)
+ expect { Chef.deprecated(:generic, "I'm a little teapot.") }.to raise_error(/I'm a little teapot./)
+ end
+ end
+ end
end
diff --git a/spec/unit/deprecated_spec.rb b/spec/unit/deprecated_spec.rb
index 4eba764b63..9c60080cef 100644
--- a/spec/unit/deprecated_spec.rb
+++ b/spec/unit/deprecated_spec.rb
@@ -20,40 +20,46 @@ require "chef/deprecated"
describe Chef::Deprecated do
class TestDeprecation < Chef::Deprecated::Base
- def id; 999; end
-
- def target; "test.html"; end
-
- def link; "#{Chef::Deprecated::Base::BASE_URL}test.html"; end
+ target 999, "test.html"
end
context "loading a deprecation class" do
it "loads the correct class" do
- expect(Chef::Deprecated.create(:test_deprecation)).to be_an_instance_of(TestDeprecation)
+ expect(Chef::Deprecated.create(:test_deprecation, nil, nil)).to be_an_instance_of(TestDeprecation)
end
- it "optionally sets a message" do
- deprecation = Chef::Deprecated.create(:test_deprecation, "A test message")
+ it "sets a message" do
+ deprecation = Chef::Deprecated.create(:test_deprecation, "A test message", nil)
expect(deprecation.message).to eql("A test message")
end
- it "optionally sets the location" do
+ it "sets the location" do
deprecation = Chef::Deprecated.create(:test_deprecation, nil, "A test location")
expect(deprecation.location).to eql("A test location")
end
end
context "formatting deprecation warnings" do
- let(:base_url) { Chef::Deprecated::Base::BASE_URL }
let(:message) { "A test message" }
let(:location) { "the location" }
it "displays the full URL" do
- expect(TestDeprecation.new().url).to eql("#{base_url}test.html")
+ expect(TestDeprecation.new().url).to eql("https://docs.chef.io/deprecations_test.html")
end
it "formats a complete deprecation message" do
- expect(TestDeprecation.new(message, location).inspect).to eql("#{message} (CHEF-999)#{location}.\nhttps://docs.chef.io/deprecations_test.html")
+ expect(TestDeprecation.new(message, location).to_s).to eql("Deprecation CHEF-999 from the location\n\n A test message\n\nPlease see https://docs.chef.io/deprecations_test.html for further details and information on how to correct this problem.")
+ end
+ end
+
+ it "has no overlapping deprecation IDs" do
+ id_map = {}
+ ObjectSpace.each_object(Class).select { |cls| cls < Chef::Deprecated::Base }.each do |cls|
+ (id_map[cls.deprecation_id] ||= []) << cls
+ end
+ collisions = id_map.select { |k, v| v.size != 1 }
+ unless collisions.empty?
+ raise "Found deprecation ID collisions:\n#{collisions.map { |k, v| "* #{k} #{v.map(&:name).join(', ')}" }.join("\n")}"
end
end
end
diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb
index 7e4980219a..253486438b 100644
--- a/spec/unit/node_map_spec.rb
+++ b/spec/unit/node_map_spec.rb
@@ -213,7 +213,7 @@ describe Chef::NodeMap do
describe "locked mode" do
context "while unlocked" do
it "allows setting the same key twice" do
- expect(Chef).to_not receive(:log_deprecation)
+ expect(Chef).to_not receive(:deprecated)
node_map.set(:foo, FooResource)
node_map.set(:foo, BarResource)
expect(node_map.get(node, :foo)).to eql(BarResource)
@@ -223,7 +223,7 @@ describe Chef::NodeMap do
context "while locked" do
# Uncomment the commented `expect`s in 15.0.
it "rejects setting the same key twice" do
- expect(Chef).to receive(:log_deprecation).with("Trying to register resource foo on top of existing Chef core resource. Check if a new version of the cookbook is available.")
+ expect(Chef).to receive(:deprecated).with(:map_collision, /resource foo/)
node_map.set(:foo, FooResource)
node_map.lock!
node_map.set(:foo, BarResource)
@@ -231,7 +231,7 @@ describe Chef::NodeMap do
end
it "allows setting the same key twice when the first has allow_cookbook_override" do
- expect(Chef).to_not receive(:log_deprecation)
+ expect(Chef).to_not receive(:deprecated)
node_map.set(:foo, FooResource, allow_cookbook_override: true)
node_map.lock!
node_map.set(:foo, BarResource)
@@ -239,7 +239,7 @@ describe Chef::NodeMap do
end
it "allows setting the same key twice when the first has allow_cookbook_override with a future version" do
- expect(Chef).to_not receive(:log_deprecation)
+ expect(Chef).to_not receive(:deprecated)
node_map.set(:foo, FooResource, allow_cookbook_override: "< 100")
node_map.lock!
node_map.set(:foo, BarResource)
@@ -247,7 +247,7 @@ describe Chef::NodeMap do
end
it "rejects setting the same key twice when the first has allow_cookbook_override with a past version" do
- expect(Chef).to receive(:log_deprecation).with("Trying to register resource foo on top of existing Chef core resource. Check if a new version of the cookbook is available.")
+ expect(Chef).to receive(:deprecated).with(:map_collision, /resource foo/)
node_map.set(:foo, FooResource, allow_cookbook_override: "< 1")
node_map.lock!
node_map.set(:foo, BarResource)
@@ -255,7 +255,7 @@ describe Chef::NodeMap do
end
it "allows setting the same key twice when the second has __core_override__" do
- expect(Chef).to_not receive(:log_deprecation)
+ expect(Chef).to_not receive(:deprecated)
node_map.set(:foo, FooResource)
node_map.lock!
node_map.set(:foo, BarResource, __core_override__: true)
@@ -263,7 +263,7 @@ describe Chef::NodeMap do
end
it "rejects setting the same key twice for a provider" do
- expect(Chef).to receive(:log_deprecation).with("Trying to register provider foo on top of existing Chef core provider. Check if a new version of the cookbook is available.")
+ expect(Chef).to receive(:deprecated).with(:map_collision, /provider foo/)
node_map.set(:foo, FooProvider)
node_map.lock!
node_map.set(:foo, BarProvider)