diff --git a/.version b/.version index a918a2aa..ee6cdce3 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -0.6.0 +0.6.1 diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index ce3a69bf..e1696b06 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -8,6 +8,15 @@
-f FROM_BRANCH
diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/filters.rb b/lib/octocatalog-diff/catalog-diff/cli/options/filters.rb
new file mode 100644
index 00000000..a998c56e
--- /dev/null
+++ b/lib/octocatalog-diff/catalog-diff/cli/options/filters.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+# Specify one or more filters to apply to the results of the catalog difference.
+# For a list of available filters and further explanation, please refer to
+# [Filtering results](/doc/advanced-filter.md).
+# @param parser [OptionParser object] The OptionParser argument
+# @param options [Hash] Options hash being constructed; this is modified in this method.
+OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:filters) do
+ has_weight 199
+
+ def parse(parser, options)
+ parser.on('--filters FILTER1[,FILTER2[,...]]', Array, 'Filters to apply') do |x|
+ options[:filters] ||= []
+ options[:filters].concat x
+ end
+ end
+end
diff --git a/lib/octocatalog-diff/catalog-diff/differ.rb b/lib/octocatalog-diff/catalog-diff/differ.rb
index 206c2d2c..3805779d 100644
--- a/lib/octocatalog-diff/catalog-diff/differ.rb
+++ b/lib/octocatalog-diff/catalog-diff/differ.rb
@@ -7,6 +7,7 @@
require 'stringio'
require_relative '../catalog'
+require_relative 'filter'
module OctocatalogDiff
module CatalogDiff
@@ -153,6 +154,9 @@ def catdiff
# out any such parameters from the result array.
filter_diffs_for_absent_files(result) if @opts[:suppress_absent_file_details]
+ # Apply any additional pluggable filters.
+ OctocatalogDiff::CatalogDiff::Filter.apply_filters(result, @opts[:filters])
+
# That's it!
@logger.debug "Exiting catdiff; change count: #{result.size}"
result
@@ -175,7 +179,7 @@ def filter_diffs_for_absent_files(result)
absent_files = Set.new
result.each do |diff|
next unless diff[0] == '~' || diff[0] == '!'
- next unless diff[1] =~ /^File\f(.+)\fparameters\fensure$/
+ next unless diff[1] =~ /^File\f([^\f]+)\fparameters\fensure$/
next unless ['absent', 'false', false].include?(diff[3])
absent_files.add Regexp.last_match(1)
end
diff --git a/lib/octocatalog-diff/catalog-diff/filter.rb b/lib/octocatalog-diff/catalog-diff/filter.rb
new file mode 100644
index 00000000..69e12932
--- /dev/null
+++ b/lib/octocatalog-diff/catalog-diff/filter.rb
@@ -0,0 +1,38 @@
+require_relative 'filter/yaml'
+
+module OctocatalogDiff
+ module CatalogDiff
+ # Filtering of diffs, and parent class for inheritance.
+ class Filter
+ # Public: Apply multiple filters by repeatedly calling the `filter` method for each
+ # filter in an array. This method returns nothing.
+ #
+ # @param result [Array] Difference array (mutated)
+ # @param filter_names [Array] Filters to run
+ # @param options [Hash] Options for each filter (hashed by name)
+ def self.apply_filters(result, filter_names, options = {})
+ return unless filter_names.is_a?(Array)
+ filter_names.each { |x| filter(result, x, options[x] || {}) }
+ end
+
+ # Public: Perform a filter on `result` using the specified filter class.
+ # This mutates `result` by removing items that are ignored. This method
+ # returns nothing.
+ #
+ # @param result [Array] Difference array (mutated)
+ # @param filter_class_name [String] Filter class name (from `filter` subdirectory)
+ # @param options [Hash] Additional options (optional) to pass to filtered? method
+ def self.filter(result, filter_class_name, options = {})
+ filter_class_name = [name.to_s, filter_class_name].join('::')
+ clazz = Kernel.const_get(filter_class_name)
+ result.reject! { |item| clazz.filtered?(item, options) }
+ end
+
+ # Inherited: Construct a default `filtered?` method for the subclass via inheritance.
+ # Each subclass must implement this method, so the default method errors.
+ def self.filtered?(_item, _options = {})
+ raise "No `filtered?` method is implemented in #{name}"
+ end
+ end
+ end
+end
diff --git a/lib/octocatalog-diff/catalog-diff/filter/yaml.rb b/lib/octocatalog-diff/catalog-diff/filter/yaml.rb
new file mode 100644
index 00000000..6e845af7
--- /dev/null
+++ b/lib/octocatalog-diff/catalog-diff/filter/yaml.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'yaml'
+
+module OctocatalogDiff
+ module CatalogDiff
+ class Filter
+ # Filter based on equivalence of YAML objects for file resources with named extensions.
+ class YAML < OctocatalogDiff::CatalogDiff::Filter
+ # Public: Actually do the comparison of YAML objects for appropriate resources.
+ # Return true if the YAML objects are known to be equivalent. Return false if they
+ # are not equivalent, or if equivalence cannot be determined.
+ #
+ # @param diff [Array] Difference
+ # @param _options [Hash] Additional options (there are none for this filter)
+ # @return [Boolean] true if this difference is a YAML file with identical objects, false otherwise
+ def self.filtered?(diff, _options = {})
+ # Skip additions or removals - focus only on changes
+ return false unless diff[0] == '~' || diff[0] == '!'
+
+ # Make sure we are comparing file content for a file ending in .yaml or .yml extension
+ return false unless diff[1] =~ /^File\f([^\f]+)\.ya?ml\fparameters\fcontent$/
+
+ # Attempt to convert the old (diff[2]) and new (diff[3]) into YAML objects. Assuming
+ # that doesn't error out, the return value is whether or not they're equal.
+ obj_old = ::YAML.load(diff[2])
+ obj_new = ::YAML.load(diff[3])
+ obj_old == obj_new
+ rescue # Rescue everything - if something failed, we aren't sure what's going on, so we'll return false.
+ false
+ end
+ end
+ end
+ end
+end
diff --git a/spec/octocatalog-diff/fixtures/catalogs/ignore-equivalent-yaml-1.json b/spec/octocatalog-diff/fixtures/catalogs/ignore-equivalent-yaml-1.json
new file mode 100644
index 00000000..850a1596
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/catalogs/ignore-equivalent-yaml-1.json
@@ -0,0 +1,22 @@
+{
+ "document_type": "Catalog",
+ "data": {
+ "tags": ["settings"],
+ "name": "my.rspec.node",
+ "version": "production",
+ "environment": "production",
+ "resources": [
+ {
+ "type": "File",
+ "title": "/tmp/foo.yaml",
+ "exported": false,
+ "parameters": {
+ "content": "foo:\n bar: baz\n"
+ }
+ }
+ ]
+ },
+ "metadata": {
+ "api_version": 1
+ }
+}
diff --git a/spec/octocatalog-diff/fixtures/catalogs/ignore-equivalent-yaml-2.json b/spec/octocatalog-diff/fixtures/catalogs/ignore-equivalent-yaml-2.json
new file mode 100644
index 00000000..a144cec3
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/catalogs/ignore-equivalent-yaml-2.json
@@ -0,0 +1,22 @@
+{
+ "document_type": "Catalog",
+ "data": {
+ "tags": ["settings"],
+ "name": "my.rspec.node",
+ "version": "production",
+ "environment": "production",
+ "resources": [
+ {
+ "type": "File",
+ "title": "/tmp/foo.yaml",
+ "exported": false,
+ "parameters": {
+ "content": "---\n foo:\n bar: baz\n"
+ }
+ }
+ ]
+ },
+ "metadata": {
+ "api_version": 1
+ }
+}
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/hiera.yaml b/spec/octocatalog-diff/fixtures/repos/yaml-diff/hiera.yaml
new file mode 100644
index 00000000..180b0a53
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/hiera.yaml
@@ -0,0 +1,10 @@
+---
+:backends:
+ - yaml
+:yaml:
+ :datadir: /var/lib/puppet/environments/%{::environment}/hieradata
+:hierarchy:
+ - roles/%{::role}
+ - common
+:merge_behavior: deeper
+:logger: console
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/hieradata/common.yaml b/spec/octocatalog-diff/fixtures/repos/yaml-diff/hieradata/common.yaml
new file mode 100644
index 00000000..4fb48568
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/hieradata/common.yaml
@@ -0,0 +1,2 @@
+---
+ bar::parameter: default
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/hieradata/roles/bar.yaml b/spec/octocatalog-diff/fixtures/repos/yaml-diff/hieradata/roles/bar.yaml
new file mode 100644
index 00000000..7cece0c6
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/hieradata/roles/bar.yaml
@@ -0,0 +1,2 @@
+---
+ bar::parameter: bar
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/manifests/site.pp b/spec/octocatalog-diff/fixtures/repos/yaml-diff/manifests/site.pp
new file mode 100644
index 00000000..355a89f0
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/manifests/site.pp
@@ -0,0 +1,3 @@
+node default {
+ include bar
+}
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/different-yaml.bar b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/different-yaml.bar
new file mode 100644
index 00000000..04b22b62
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/different-yaml.bar
@@ -0,0 +1,2 @@
+---
+ value: bar
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/different-yaml.default b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/different-yaml.default
new file mode 100644
index 00000000..ac8ea2bb
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/different-yaml.default
@@ -0,0 +1,2 @@
+---
+ value: default
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/identical-yaml b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/identical-yaml
new file mode 100644
index 00000000..e05acdb6
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/identical-yaml
@@ -0,0 +1,2 @@
+---
+ value: identical
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/not-yaml.bar b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/not-yaml.bar
new file mode 100644
index 00000000..ec2b2686
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/not-yaml.bar
@@ -0,0 +1 @@
+---{ "title": "This is not YAML", "value": "bar" }
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/not-yaml.default b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/not-yaml.default
new file mode 100644
index 00000000..c4a57a13
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/not-yaml.default
@@ -0,0 +1 @@
+---{ "title": "This is not YAML", "value": "default" }
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/similar-yaml.bar b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/similar-yaml.bar
new file mode 100644
index 00000000..535bab4b
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/similar-yaml.bar
@@ -0,0 +1,7 @@
+---
+structure:
+ value: bar
+ array:
+ - foo
+ - bar
+ - baz
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/similar-yaml.default b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/similar-yaml.default
new file mode 100644
index 00000000..de5e4c1c
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/similar-yaml.default
@@ -0,0 +1,7 @@
+---
+ structure:
+ value: bar
+ array:
+ - foo
+ - bar
+ - baz
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/unparseable-yaml.bar b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/unparseable-yaml.bar
new file mode 100644
index 00000000..8cd580ac
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/unparseable-yaml.bar
@@ -0,0 +1,3 @@
+--- !ruby/object:This::Does::Not::Exist
+ name: foo
+ value: bar
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/unparseable-yaml.default b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/unparseable-yaml.default
new file mode 100644
index 00000000..d4ca205d
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/files/unparseable-yaml.default
@@ -0,0 +1,3 @@
+--- !ruby/object:This::Does::Not::Exist
+ name: foo
+ value: default
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/manifests/init.pp b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/manifests/init.pp
new file mode 100644
index 00000000..7c8e3478
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/manifests/init.pp
@@ -0,0 +1,89 @@
+class bar ( $parameter ) {
+ file { '/tmp/template/different-yaml.yaml':
+ content => template('bar/different-yaml.erb')
+ }
+
+ file { "/tmp/template/different-yaml-${parameter}.yaml":
+ content => template('bar/different-yaml.erb')
+ }
+
+ file { '/tmp/template/identical-yaml.yaml':
+ content => template('bar/identical-yaml.erb')
+ }
+
+ file { '/tmp/template/not-yaml.yaml':
+ content => '{ "title": "This is not YAML" }'
+ }
+
+ file { '/tmp/template/not-yaml-2.yaml':
+ content => template('bar/not-yaml.erb')
+ }
+
+ file { "/tmp/template/not-yaml-${parameter}.yaml":
+ content => template('bar/not-yaml.erb')
+ }
+
+ file { '/tmp/template/similar-yaml.yaml':
+ content => template('bar/similar-yaml.erb')
+ }
+
+ file { '/tmp/template/similar-yaml.json':
+ content => template('bar/similar-yaml.erb')
+ }
+
+ file { '/tmp/template/unparseable-yaml.yaml':
+ content => template('bar/unparseable-yaml.erb'),
+ }
+
+ file { '/tmp/template/unparseable-yaml-2.yaml':
+ content => template('bar/unparseable-yaml-2.erb'),
+ }
+
+ file { "/tmp/template/unparseable-yaml-${parameter}.yaml":
+ content => template('bar/unparseable-yaml-2.erb'),
+ }
+
+ file { '/tmp/static/different-yaml.yaml':
+ source => "puppet:///modules/bar/different-yaml.${parameter}"
+ }
+
+ file { "/tmp/static/different-yaml-${parameter}.yaml":
+ source => "puppet:///modules/bar/different-yaml.${parameter}"
+ }
+
+ file { '/tmp/static/identical-yaml.yaml':
+ source => 'puppet:///modules/bar/identical-yaml',
+ }
+
+ file { '/tmp/static/not-yaml.yaml':
+ source => 'puppet:///modules/bar/not-yaml.default',
+ }
+
+ file { '/tmp/static/not-yaml-2.yaml':
+ source => "puppet:///modules/bar/not-yaml.${parameter}",
+ }
+
+ file { "/tmp/static/not-yaml-${parameter}.yaml":
+ source => "puppet:///modules/bar/not-yaml.${parameter}",
+ }
+
+ file { '/tmp/static/similar-yaml.yaml':
+ source => "puppet:///modules/bar/similar-yaml.${parameter}"
+ }
+
+ file { '/tmp/static/similar-yaml.json':
+ source => "puppet:///modules/bar/similar-yaml.${parameter}"
+ }
+
+ file { '/tmp/static/unparseable-yaml.yaml':
+ source => 'puppet:///modules/bar/unparseable-yaml.default',
+ }
+
+ file { '/tmp/static/unparseable-yaml-2.yaml':
+ source => "puppet:///modules/bar/unparseable-yaml.${parameter}",
+ }
+
+ file { "/tmp/static/unparseable-yaml-${parameter}.yaml":
+ source => "puppet:///modules/bar/unparseable-yaml.${parameter}",
+ }
+}
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/different-yaml.erb b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/different-yaml.erb
new file mode 100644
index 00000000..db59d25e
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/different-yaml.erb
@@ -0,0 +1,2 @@
+---
+ value: <%= @parameter %>
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/identical-yaml.erb b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/identical-yaml.erb
new file mode 100644
index 00000000..447f1ef3
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/identical-yaml.erb
@@ -0,0 +1,2 @@
+---
+ value: nachos
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/not-yaml.erb b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/not-yaml.erb
new file mode 100644
index 00000000..8573a20d
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/not-yaml.erb
@@ -0,0 +1 @@
+---{ "title": "This is not YAML", "value": "<%= @parameter %>" }
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/similar-yaml.erb b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/similar-yaml.erb
new file mode 100644
index 00000000..5e243614
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/similar-yaml.erb
@@ -0,0 +1,16 @@
+---
+<% if @parameter == 'default' %>
+ structure:
+ value: bar
+ array:
+ - foo
+ - bar
+ - baz
+<% else %>
+structure:
+ value: bar
+ array:
+ - foo
+ - bar
+ - baz
+<% end %>
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/unparseable-yaml-2.erb b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/unparseable-yaml-2.erb
new file mode 100644
index 00000000..fbd72484
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/unparseable-yaml-2.erb
@@ -0,0 +1,3 @@
+--- !ruby/object:This::Does::Not::Exist
+ name: foo
+ value: baz
diff --git a/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/unparseable-yaml.erb b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/unparseable-yaml.erb
new file mode 100644
index 00000000..879c3a5a
--- /dev/null
+++ b/spec/octocatalog-diff/fixtures/repos/yaml-diff/modules/bar/templates/unparseable-yaml.erb
@@ -0,0 +1,3 @@
+--- !ruby/object:This::Does::Not::Exist
+ name: foo
+ value: <%= @parameter %>
diff --git a/spec/octocatalog-diff/integration/yaml_diff_spec.rb b/spec/octocatalog-diff/integration/yaml_diff_spec.rb
new file mode 100644
index 00000000..e32ccd72
--- /dev/null
+++ b/spec/octocatalog-diff/integration/yaml_diff_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require_relative 'integration_helper'
+require 'json'
+
+describe 'YAML file suppression for identical diffs' do
+ context 'with YAML diff suppression disabled' do
+ before(:all) do
+ argv = ['-n', 'rspec-node.github.net', '--to-fact-override', 'role=bar']
+ hash = { hiera_config: 'hiera.yaml', spec_fact_file: 'facts.yaml', spec_repo: 'yaml-diff' }
+ @result = OctocatalogDiff::Integration.integration(hash.merge(argv: argv))
+ end
+
+ it 'should compile without error' do
+ expect(@result.exitcode).to eq(2), OctocatalogDiff::Integration.format_exception(@result)
+ expect(@result.exception).to be_nil
+ end
+
+ it 'should contain the correct number of diffs' do
+ expect(@result.diffs.size).to eq(22)
+ end
+
+ it 'should contain the "similar JSON" static file as a diff' do
+ arr = @result.diffs
+ answer = ['~', "File\f/tmp/static/similar-yaml.json\fparameters\fcontent"]
+ expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true)
+ end
+
+ it 'should contain the "similar YAML" static file as a diff' do
+ arr = @result.diffs
+ answer = ['~', "File\f/tmp/static/similar-yaml.yaml\fparameters\fcontent"]
+ expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true)
+ end
+
+ it 'should contain the "similar JSON" template file as a diff' do
+ arr = @result.diffs
+ answer = ['~', "File\f/tmp/template/similar-yaml.json\fparameters\fcontent"]
+ expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true)
+ end
+
+ it 'should contain the "similar YAML" template file as a diff' do
+ arr = @result.diffs
+ answer = ['~', "File\f/tmp/template/similar-yaml.yaml\fparameters\fcontent"]
+ expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true)
+ end
+ end
+
+ context 'with YAML diff suppression enabled' do
+ before(:all) do
+ argv = ['-n', 'rspec-node.github.net', '--to-fact-override', 'role=bar', '--filters', 'YAML']
+ hash = { hiera_config: 'hiera.yaml', spec_fact_file: 'facts.yaml', spec_repo: 'yaml-diff' }
+ @result = OctocatalogDiff::Integration.integration(hash.merge(argv: argv))
+ end
+
+ it 'should compile without error' do
+ expect(@result.exitcode).to eq(2), OctocatalogDiff::Integration.format_exception(@result)
+ expect(@result.exception).to be_nil
+ end
+
+ it 'should contain the correct number of diffs' do
+ expect(@result.diffs.size).to eq(20)
+ end
+
+ it 'should contain the "similar JSON" static file as a diff' do
+ arr = @result.diffs
+ answer = ['~', "File\f/tmp/static/similar-yaml.json\fparameters\fcontent"]
+ expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true)
+ end
+
+ it 'should not contain the "similar YAML" static file as a diff' do
+ arr = @result.diffs
+ answer = ['~', "File\f/tmp/static/similar-yaml.yaml\fparameters\fcontent"]
+ expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(false)
+ end
+
+ it 'should contain the "similar JSON" template file as a diff' do
+ arr = @result.diffs
+ answer = ['~', "File\f/tmp/template/similar-yaml.json\fparameters\fcontent"]
+ expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true)
+ end
+
+ it 'should not contain the "similar YAML" template file as a diff' do
+ arr = @result.diffs
+ answer = ['~', "File\f/tmp/template/similar-yaml.yaml\fparameters\fcontent"]
+ expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(false)
+ end
+ end
+end
diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/filters_spec.rb b/spec/octocatalog-diff/tests/catalog-diff/cli/options/filters_spec.rb
new file mode 100644
index 00000000..c7c4ef10
--- /dev/null
+++ b/spec/octocatalog-diff/tests/catalog-diff/cli/options/filters_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative '../options_helper'
+
+describe OctocatalogDiff::CatalogDiff::Cli::Options do
+ describe '#opt_ignore_equivalent_yaml_files' do
+ it 'should accept comma delimited parameters for --filters' do
+ result = run_optparse(['--filters', 'fizzbuzz,barbuzz'])
+ expect(result[:filters]).to eq(%w(fizzbuzz barbuzz))
+ end
+
+ it 'should accept multiple parameters for --filters' do
+ result = run_optparse(['--filters', 'fizzbuzz', '--filters', 'barbuzz'])
+ expect(result[:filters]).to eq(%w(fizzbuzz barbuzz))
+ end
+ end
+end
diff --git a/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb b/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb
index 0781f470..8d9594a5 100644
--- a/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb
+++ b/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb
@@ -532,7 +532,9 @@
end
end
end
+end
+describe OctocatalogDiff::CatalogDiff::Differ do
context 'ignoring only adds / removes / changes' do
describe '#ignore' do
before(:all) do
diff --git a/spec/octocatalog-diff/tests/catalog-diff/filter/yaml_spec.rb b/spec/octocatalog-diff/tests/catalog-diff/filter/yaml_spec.rb
new file mode 100644
index 00000000..53c5830b
--- /dev/null
+++ b/spec/octocatalog-diff/tests/catalog-diff/filter/yaml_spec.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+require_relative '../../spec_helper'
+require OctocatalogDiff::Spec.require_path('/catalog-diff/filter/yaml')
+
+describe OctocatalogDiff::CatalogDiff::Filter::YAML do
+ describe '#filtered?' do
+ let(:str1a) { "---\n foo: bar" }
+ let(:str1b) { "---\nfoo: bar" }
+ let(:str2) { "---\n foo: baz" }
+
+ it 'should not filter out an added resource' do
+ diff = ['+', "File\ffoobar.yaml", { 'parameters' => { 'content' => str1a } }]
+ result = described_class.filtered?(diff)
+ expect(result).to eq(false)
+ end
+
+ it 'should not filter out a removed resource' do
+ diff = ['-', "File\ffoobar.yaml", { 'parameters' => { 'content' => str1a } }]
+ result = described_class.filtered?(diff)
+ expect(result).to eq(false)
+ end
+
+ it 'should not filter out a non-file resource' do
+ diff = ['~', "Exec\ffoobar.yaml\fparameters\fcontent", str1a, str1b]
+ result = described_class.filtered?(diff)
+ expect(result).to eq(false)
+ end
+
+ it 'should not filter out a file whose extension is not .yaml / .yml' do
+ diff = ['~', "File\ffoobar.json\fparameters\fcontent", str1a, str1b]
+ result = described_class.filtered?(diff)
+ expect(result).to eq(false)
+ end
+
+ it 'should not filter out a change with no content change' do
+ diff = ['~', "File\ffoobar.json\fparameters\fowner", 'root', 'nobody']
+ result = described_class.filtered?(diff)
+ expect(result).to eq(false)
+ end
+
+ it 'should not filter out a change where YAML objects are dissimilar' do
+ diff = ['~', "File\ffoobar.yaml\fparameters\fcontent", str1a, str2]
+ result = described_class.filtered?(diff)
+ expect(result).to eq(false)
+ end
+
+ it 'should not filter out a change where YAML is invalid' do
+ x_str = '---{ "blah": "foo" }'
+ diff = ['~', "File\ffoobar.yaml\fparameters\fcontent", x_str, x_str]
+ result = described_class.filtered?(diff)
+ expect(result).to eq(false)
+ end
+
+ it 'should not filter out a change where YAML is unparseable' do
+ x_str = "--- !ruby/object:This::Does::Not::Exist\n foo: bar"
+ diff = ['~', "File\ffoobar.yaml\fparameters\fcontent", x_str, x_str]
+ result = described_class.filtered?(diff)
+ expect(result).to eq(false)
+ end
+
+ it 'should filter out a whitespace-only change to a .yaml file' do
+ diff = ['~', "File\ffoobar.yaml\fparameters\fcontent", str1a, str1b]
+ result = described_class.filtered?(diff)
+ expect(result).to eq(true)
+ end
+
+ it 'should filter out a whitespace-only change to a .yml file' do
+ diff = ['~', "File\ffoobar.yml\fparameters\fcontent", str1a, str1b]
+ result = described_class.filtered?(diff)
+ expect(result).to eq(true)
+ end
+ end
+end
diff --git a/spec/octocatalog-diff/tests/catalog-diff/filter_spec.rb b/spec/octocatalog-diff/tests/catalog-diff/filter_spec.rb
new file mode 100644
index 00000000..22ce2c08
--- /dev/null
+++ b/spec/octocatalog-diff/tests/catalog-diff/filter_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require_relative '../spec_helper'
+require OctocatalogDiff::Spec.require_path('/catalog-diff/filter')
+
+describe OctocatalogDiff::CatalogDiff::Filter do
+ before(:each) do
+ @class_1 = double
+ @class_2 = double
+ allow(Kernel).to receive(:const_get).with('OctocatalogDiff::CatalogDiff::Filter::Fake1').and_return(@class_1)
+ allow(Kernel).to receive(:const_get).with('OctocatalogDiff::CatalogDiff::Filter::Fake2').and_return(@class_2)
+ end
+
+ describe '#apply_filters' do
+ it 'should call self.filter() with appropriate options for each class' do
+ result = [false]
+ options = { 'Fake1' => { foo: 'bar' } }
+ classes = %w(Fake1 Fake2)
+ expect(@class_1).to receive(:'filtered?').with(false, foo: 'bar').and_return(false)
+ expect(@class_2).to receive(:'filtered?').with(false, {}).and_return(false)
+ expect { described_class.apply_filters(result, classes, options) }.not_to raise_error
+ expect(result).to eq([false])
+ end
+ end
+
+ describe '#filter' do
+ it 'should call .filtered?() in a class and remove matching items' do
+ result = [false, true]
+ expect(@class_1).to receive(:'filtered?').with(false, {}).and_return(false)
+ expect(@class_1).to receive(:'filtered?').with(true, {}).and_return(true)
+ expect { described_class.filter(result, 'Fake1') }.not_to raise_error
+ expect(result).to eq([false])
+ end
+ end
+
+ describe '#filtered?' do
+ it 'should raise error' do
+ expect { described_class.filtered?([]) }.to raise_error(RuntimeError, /No `filtered\?` method is implemented/)
+ end
+ end
+end