diff --git a/.rubocop.yml b/.rubocop.yml index d3e9be5..4aac8a8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -58,6 +58,9 @@ Metrics/CyclomaticComplexity: Metrics/ModuleLength: Enabled: false +Metrics/ClassLength: + Enabled: false + Sorbet/FalseSigil: Enabled: false diff --git a/lib/danger-packwerk/danger_packwerk.rb b/lib/danger-packwerk/danger_packwerk.rb index af3a472..f7ca665 100644 --- a/lib/danger-packwerk/danger_packwerk.rb +++ b/lib/danger-packwerk/danger_packwerk.rb @@ -108,10 +108,14 @@ def check( packwerk_reference_offenses_to_care_about = packwerk_reference_offenses.reject do |packwerk_reference_offense| constant_name = packwerk_reference_offense.reference.constant.name filepath_that_defines_this_constant = Private.constant_resolver.resolve(constant_name)&.location + reference_path = packwerk_reference_offense.reference.relative_path + # Ignore references that have been renamed renamed_files.include?(filepath_that_defines_this_constant) || # Ignore violations that are not in the allow-list of violation types to leave comments for - !violation_types.include?(packwerk_reference_offense.violation_type) + !violation_types.include?(packwerk_reference_offense.violation_type) || + # Ignore violations that match enforcement_globs_ignore + ignored_by_enforcement_globs(packwerk_reference_offense, reference_path) end # We group by the constant name, line number, and reference path. Any offenses with these same values should only differ on what type of violation @@ -151,5 +155,34 @@ def check( on_failure.call(packwerk_reference_offenses) end end + + sig do + params( + packwerk_reference_offense: Packwerk::ReferenceOffense, + reference_path: String + ).returns(T::Boolean) + end + def ignored_by_enforcement_globs(packwerk_reference_offense, reference_path) + # Get the package for this reference to check for enforcement_globs_ignore + package = ParsePackwerk.package_from_path(reference_path) + enforcement_globs_ignore = package.config['enforcement_globs_ignore'] + + # Check if this offense should be ignored based on enforcement_globs_ignore + if enforcement_globs_ignore.is_a?(Array) + enforcement_globs_ignore.any? do |glob_config| + next false unless glob_config.is_a?(Hash) + + enforcements = glob_config['enforcements'] + ignores = glob_config['ignores'] + + # Check if this violation type is in the enforcements list + # and if the file path matches any of the ignores glob patterns + enforcements&.include?(packwerk_reference_offense.violation_type) && + ignores&.any? { |ignore_pattern| File.fnmatch(ignore_pattern, reference_path) } + end + else + false + end + end end end diff --git a/spec/danger_packwerk/danger_packwerk_spec.rb b/spec/danger_packwerk/danger_packwerk_spec.rb index f239148..2290de9 100644 --- a/spec/danger_packwerk/danger_packwerk_spec.rb +++ b/spec/danger_packwerk/danger_packwerk_spec.rb @@ -89,6 +89,7 @@ def format_offenses(offenses, repo_link, org_name, repo_url_builder:) let(:modified_files) { [write_file('packs/referencing_pack/some_file.rb').to_s] } before do + # This is the root package.yml file write_file('package.yml', <<~YML) enforce_dependencies: true enforce_privacy: true @@ -112,7 +113,7 @@ def format_offenses(offenses, repo_link, org_name, repo_url_builder:) context 'when the only files modified are ones that packwerk ignores' do let(:modified_files) { [write_file('frontend/javascript/some_file.js').to_s] } - it 'leaves an inline comment helping the user figure out what to do next' do + it 'leaves no comments' do expect_any_instance_of(Packwerk::Cli).not_to receive(:execute_command) packwerk_check expect(dangerfile.status_report[:warnings]).to be_empty @@ -122,6 +123,48 @@ def format_offenses(offenses, repo_link, org_name, repo_url_builder:) end end + context 'when the privacy violation matches enforcement_globs_ignore' do + let(:offenses) { [generic_privacy_violation] } + + it 'does not report when ignoring privacy violations with a path' do + write_file('packs/some_pack/package.yml', <<~YML) + enforce_dependencies: true + enforce_privacy: true + enforcement_globs_ignore: + - enforcements: + - privacy + ignores: + - packs/referencing_pack/some_file.rb + reason: man this one is just too difficult to fix + YML + + packwerk_check + expect(dangerfile.status_report[:warnings]).to be_empty + expect(dangerfile.status_report[:errors]).to be_empty + actual_markdowns = dangerfile.status_report[:markdowns] + expect(actual_markdowns.first&.message).to be_nil + end + + it 'does not report when ignoring privacy violations with a glob' do + write_file('packs/some_pack/package.yml', <<~YML) + enforce_dependencies: true + enforce_privacy: true + enforcement_globs_ignore: + - enforcements: + - privacy + ignores: + - packs/referencing_pack/*.rb + reason: All of these are impossible + YML + + packwerk_check + expect(dangerfile.status_report[:warnings]).to be_empty + expect(dangerfile.status_report[:errors]).to be_empty + actual_markdowns = dangerfile.status_report[:markdowns] + expect(actual_markdowns.first&.message).to be_nil + end + end + context 'when there is a new privacy violation when running packwerk check' do let(:offenses) { [generic_privacy_violation] } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1cd31f7..896cf5c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -69,8 +69,6 @@ def sorbet_double(stubbed_class, attr_map = {}) end end -def write_package_yml( - pack_name -) +def write_package_yml(pack_name) write_pack(pack_name, { 'enforce_dependencies' => true, 'enforce_privacy' => true }) end