modularization_statistics 1.37.0 → 1.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/modularization_statistics/private/metrics/packages.rb +9 -11
- data/lib/modularization_statistics/private/metrics/packages_by_team.rb +11 -11
- data/lib/modularization_statistics/private/metrics/protection_usage.rb +119 -3
- data/lib/modularization_statistics/private/metrics/rubocop_protections_exclusions.rb +5 -2
- data/sorbet/rbi/gems/{parse_packwerk@0.12.0.rbi → parse_packwerk@0.14.0.rbi} +10 -1
- metadata +4 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c11bc9704708d387bff6b5d7245832c6d57c9291a7dcc306513e3942afb53311
         | 
| 4 | 
            +
              data.tar.gz: 7d5403d37a5811f5ef1798a3a8bfb96b304124ada289b75dba14db0844fd252e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 2c82a234d983ddc50d494f6eb8933633a0b61a7e82783d375f5d22b02c1e12fb476f9fb70ca35885ecadc879dd1fc94179cf6db3b1d52f47501afe38c6349651
         | 
| 7 | 
            +
              data.tar.gz: ec00762292cdec0eb441ad424bdd5e80733a9acd418925f82c92142988df9d4b3b6843b8e4de1d9b8190e48cf23f6818b2e4f7176bf263a6541fa490181c38b0
         | 
| @@ -17,36 +17,34 @@ module ModularizationStatistics | |
| 17 17 | 
             
                      all_metrics = []
         | 
| 18 18 | 
             
                      app_level_tag = Tag.for('app', app_name)
         | 
| 19 19 | 
             
                      package_tags = T.let([app_level_tag], T::Array[Tag])
         | 
| 20 | 
            -
                      protected_packages = packages.map { |p| PackageProtections::ProtectedPackage.from(p) }
         | 
| 21 20 |  | 
| 22 21 | 
             
                      all_metrics << GaugeMetric.for('all_packages.count', packages.count, package_tags)
         | 
| 23 22 | 
             
                      all_metrics << GaugeMetric.for('all_packages.dependencies.count', packages.sum { |package| package.dependencies.count }, package_tags)
         | 
| 24 | 
            -
                      all_metrics << GaugeMetric.for('all_packages.dependency_violations.count',  | 
| 25 | 
            -
                      all_metrics << GaugeMetric.for('all_packages.privacy_violations.count',  | 
| 23 | 
            +
                      all_metrics << GaugeMetric.for('all_packages.dependency_violations.count', packages.sum { |package| Metrics.file_count(package.violations.select(&:dependency?)) }, package_tags)
         | 
| 24 | 
            +
                      all_metrics << GaugeMetric.for('all_packages.privacy_violations.count', packages.sum { |package| Metrics.file_count(package.violations.select(&:privacy?)) }, package_tags)
         | 
| 26 25 | 
             
                      all_metrics << GaugeMetric.for('all_packages.enforcing_dependencies.count', packages.count(&:enforces_dependencies?), package_tags)
         | 
| 27 26 | 
             
                      all_metrics << GaugeMetric.for('all_packages.enforcing_privacy.count', packages.count(&:enforces_privacy?), package_tags)
         | 
| 28 27 |  | 
| 29 28 | 
             
                      all_metrics << GaugeMetric.for('all_packages.notify_on_package_yml_changes.count', packages.count { |p| p.metadata['notify_on_package_yml_changes'] }, package_tags)
         | 
| 30 29 | 
             
                      all_metrics << GaugeMetric.for('all_packages.notify_on_new_violations.count', packages.count { |p| p.metadata['notify_on_new_violations'] }, package_tags)
         | 
| 31 30 |  | 
| 32 | 
            -
                      all_metrics << GaugeMetric.for('all_packages.with_violations.count',  | 
| 31 | 
            +
                      all_metrics << GaugeMetric.for('all_packages.with_violations.count', packages.count { |package| package.violations.any? }, package_tags)
         | 
| 33 32 | 
             
                      all_metrics += Metrics::PublicUsage.get_public_usage_metrics('all_packages', packages, package_tags)
         | 
| 34 33 | 
             
                      all_metrics << GaugeMetric.for('all_packages.has_readme.count', packages.count { |package| Metrics.has_readme?(package) }, package_tags)
         | 
| 35 34 |  | 
| 36 | 
            -
                      all_metrics += Metrics::ProtectionUsage.get_protections_metrics('all_packages',  | 
| 37 | 
            -
                      all_metrics += Metrics::RubocopProtectionsExclusions.get_rubocop_exclusions('all_packages',  | 
| 35 | 
            +
                      all_metrics += Metrics::ProtectionUsage.get_protections_metrics('all_packages', packages, package_tags)
         | 
| 36 | 
            +
                      all_metrics += Metrics::RubocopProtectionsExclusions.get_rubocop_exclusions('all_packages', packages, package_tags)
         | 
| 38 37 | 
             
                      all_metrics << GaugeMetric.for('all_packages.package_based_file_ownership.count', packages.count { |package| !package.metadata['owner'].nil? }, package_tags)
         | 
| 39 38 |  | 
| 40 | 
            -
                      inbound_violations_by_package =  | 
| 39 | 
            +
                      inbound_violations_by_package = packages.flat_map(&:violations).group_by(&:to_package_name)
         | 
| 41 40 |  | 
| 42 | 
            -
                       | 
| 43 | 
            -
                        package = protected_package.original_package
         | 
| 41 | 
            +
                      packages.each do |package|
         | 
| 44 42 | 
             
                        package_tags = Metrics.tags_for_package(package, app_name)
         | 
| 45 43 |  | 
| 46 44 | 
             
                        #
         | 
| 47 45 | 
             
                        # VIOLATIONS (implicit dependencies)
         | 
| 48 46 | 
             
                        #
         | 
| 49 | 
            -
                        outbound_violations =  | 
| 47 | 
            +
                        outbound_violations = package.violations
         | 
| 50 48 | 
             
                        inbound_violations = inbound_violations_by_package[package.name] || []
         | 
| 51 49 | 
             
                        all_dependency_violations = (outbound_violations + inbound_violations).select(&:dependency?)
         | 
| 52 50 | 
             
                        all_privacy_violations = (outbound_violations + inbound_violations).select(&:privacy?)
         | 
| @@ -62,7 +60,7 @@ module ModularizationStatistics | |
| 62 60 |  | 
| 63 61 | 
             
                        all_metrics += Metrics::PublicUsage.get_public_usage_metrics('by_package', [package], package_tags)
         | 
| 64 62 |  | 
| 65 | 
            -
                         | 
| 63 | 
            +
                        package.violations.group_by(&:to_package_name).each do |to_package_name, violations|
         | 
| 66 64 | 
             
                          to_package = ParsePackwerk.find(to_package_name)
         | 
| 67 65 | 
             
                          if to_package.nil?
         | 
| 68 66 | 
             
                            raise StandardError, "Could not find matching package #{to_package_name}"
         | 
| @@ -16,25 +16,25 @@ module ModularizationStatistics | |
| 16 16 | 
             
                    def self.get_package_metrics_by_team(all_packages, app_name)
         | 
| 17 17 | 
             
                      all_metrics = T.let([], T::Array[GaugeMetric])
         | 
| 18 18 | 
             
                      app_level_tag = Tag.for('app', app_name)
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                       | 
| 19 | 
            +
             | 
| 20 | 
            +
                      all_packages.group_by { |package| CodeOwnership.for_package(package)&.name }.each do |team_name, packages_by_team|
         | 
| 21 21 | 
             
                        # We look at `all_packages` because we care about ALL inbound violations across all teams
         | 
| 22 | 
            -
                        inbound_violations_by_package =  | 
| 22 | 
            +
                        inbound_violations_by_package = all_packages.flat_map(&:violations).group_by(&:to_package_name)
         | 
| 23 23 |  | 
| 24 24 | 
             
                        team_tags = Metrics.tags_for_team(team_name) + [app_level_tag]
         | 
| 25 | 
            -
                        all_metrics << GaugeMetric.for('by_team.all_packages.count',  | 
| 26 | 
            -
                        all_metrics += Metrics::ProtectionUsage.get_protections_metrics('by_team',  | 
| 27 | 
            -
                        all_metrics += Metrics::PublicUsage.get_public_usage_metrics('by_team',  | 
| 25 | 
            +
                        all_metrics << GaugeMetric.for('by_team.all_packages.count', packages_by_team.count, team_tags)
         | 
| 26 | 
            +
                        all_metrics += Metrics::ProtectionUsage.get_protections_metrics('by_team', packages_by_team, team_tags)
         | 
| 27 | 
            +
                        all_metrics += Metrics::PublicUsage.get_public_usage_metrics('by_team', packages_by_team, team_tags)
         | 
| 28 28 |  | 
| 29 | 
            -
                        all_metrics << GaugeMetric.for('by_team.notify_on_package_yml_changes.count',  | 
| 30 | 
            -
                        all_metrics << GaugeMetric.for('by_team.notify_on_new_violations.count',  | 
| 29 | 
            +
                        all_metrics << GaugeMetric.for('by_team.notify_on_package_yml_changes.count', packages_by_team.count { |p| p.metadata['notify_on_package_yml_changes'] }, team_tags)
         | 
| 30 | 
            +
                        all_metrics << GaugeMetric.for('by_team.notify_on_new_violations.count', packages_by_team.count { |p| p.metadata['notify_on_new_violations'] }, team_tags)
         | 
| 31 31 |  | 
| 32 32 | 
             
                        #
         | 
| 33 33 | 
             
                        # VIOLATIONS (implicit dependencies)
         | 
| 34 34 | 
             
                        #
         | 
| 35 | 
            -
                        outbound_violations =  | 
| 35 | 
            +
                        outbound_violations = packages_by_team.flat_map(&:violations)
         | 
| 36 36 | 
             
                        # Here we only look at packages_by_team because we only care about inbound violations onto packages for this team
         | 
| 37 | 
            -
                        inbound_violations =  | 
| 37 | 
            +
                        inbound_violations = packages_by_team.flat_map { |package| inbound_violations_by_package[package.name] || [] }
         | 
| 38 38 | 
             
                        all_dependency_violations = (outbound_violations + inbound_violations).select(&:dependency?)
         | 
| 39 39 | 
             
                        all_privacy_violations = (outbound_violations + inbound_violations).select(&:privacy?)
         | 
| 40 40 |  | 
| @@ -47,7 +47,7 @@ module ModularizationStatistics | |
| 47 47 | 
             
                        all_metrics << GaugeMetric.for('by_team.outbound_privacy_violations.count', Metrics.file_count(outbound_violations.select(&:privacy?)), team_tags)
         | 
| 48 48 | 
             
                        all_metrics << GaugeMetric.for('by_team.inbound_privacy_violations.count', Metrics.file_count(inbound_violations.select(&:privacy?)), team_tags)
         | 
| 49 49 |  | 
| 50 | 
            -
                        all_metrics << GaugeMetric.for('by_team.has_readme.count',  | 
| 50 | 
            +
                        all_metrics << GaugeMetric.for('by_team.has_readme.count', packages_by_team.count { |package| Metrics.has_readme?(package) }, team_tags)
         | 
| 51 51 |  | 
| 52 52 | 
             
                        grouped_outbound_violations = outbound_violations.group_by do |violation|
         | 
| 53 53 | 
             
                          to_package = ParsePackwerk.find(violation.to_package_name)
         | 
| @@ -7,8 +7,9 @@ module ModularizationStatistics | |
| 7 7 | 
             
                  class ProtectionUsage
         | 
| 8 8 | 
             
                    extend T::Sig
         | 
| 9 9 |  | 
| 10 | 
            -
                    sig { params(prefix: String,  | 
| 11 | 
            -
                    def self.get_protections_metrics(prefix,  | 
| 10 | 
            +
                    sig { params(prefix: String, packages: T::Array[ParsePackwerk::Package], package_tags: T::Array[Tag]).returns(T::Array[GaugeMetric]) }
         | 
| 11 | 
            +
                    def self.get_protections_metrics(prefix, packages, package_tags)
         | 
| 12 | 
            +
                      protected_packages = packages.map { |p| PackageProtections::ProtectedPackage.from(p) }
         | 
| 12 13 | 
             
                      PackageProtections.all.flat_map do |protection|
         | 
| 13 14 | 
             
                        PackageProtections::ViolationBehavior.each_value.map do |violation_behavior|
         | 
| 14 15 | 
             
                          # https://github.com/Gusto/package_protections/pull/42 changed the public API of these violation behaviors.
         | 
| @@ -22,11 +23,126 @@ module ModularizationStatistics | |
| 22 23 | 
             
                          }
         | 
| 23 24 | 
             
                          violation_behavior_name = violation_behavior_map[violation_behavior]
         | 
| 24 25 | 
             
                          metric_name = "#{prefix}.#{protection.identifier}.#{violation_behavior_name}.count"
         | 
| 25 | 
            -
                          count_of_packages = protected_packages.count  | 
| 26 | 
            +
                          count_of_packages = protected_packages.count do |p|
         | 
| 27 | 
            +
                            #
         | 
| 28 | 
            +
                            # This is temporarily in place until we migrate off of `package_protections` in favor of `rubocop-packs`.
         | 
| 29 | 
            +
                            # At that point, we want to delete this branch and instead it we'd probably have two separate branches.
         | 
| 30 | 
            +
                            # One branch would look at `enforce_x` and `metadata.strictly_enforce_x`.
         | 
| 31 | 
            +
                            # The other branch would look at `.pack_rubocop.yml`.
         | 
| 32 | 
            +
                            # Later on, we could generalize this so that it automatically incorporates new cops from `rubocop-packs`,
         | 
| 33 | 
            +
                            # or even new packwerk plugins.
         | 
| 34 | 
            +
                            #
         | 
| 35 | 
            +
                            # Regardless, we'll want to keep the way we are naming these behaviors for now to preserve historical trends in the data.
         | 
| 36 | 
            +
                            #
         | 
| 37 | 
            +
                            if p.metadata['protections']
         | 
| 38 | 
            +
                              p.violation_behavior_for(protection.identifier) == violation_behavior
         | 
| 39 | 
            +
                            else
         | 
| 40 | 
            +
                              should_count_package?(p.original_package, protection, violation_behavior)
         | 
| 41 | 
            +
                            end
         | 
| 42 | 
            +
                          end
         | 
| 26 43 | 
             
                          GaugeMetric.for(metric_name, count_of_packages, package_tags)
         | 
| 27 44 | 
             
                        end
         | 
| 28 45 | 
             
                      end
         | 
| 29 46 | 
             
                    end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    #
         | 
| 49 | 
            +
                    # Later, when we remove package protections, we can make this simpler by iterating over
         | 
| 50 | 
            +
                    # packwerk checkers and rubocop packs specifically. That would let us use a common, simple
         | 
| 51 | 
            +
                    # strategy to get metrics for both of them. For the first iteration, we'll want to continue
         | 
| 52 | 
            +
                    # to map the old names of things to the "protection" names. After that, I think we will want to
         | 
| 53 | 
            +
                    # extract that mapping into a tool that transforms the metrics that can be optionally turned off
         | 
| 54 | 
            +
                    # so that we can see metrics that are more closely connected to the new API.
         | 
| 55 | 
            +
                    # e.g. instead of `all_packages.prevent_this_package_from_violating_its_stated_dependencies.fail_on_any.count`, we'd see
         | 
| 56 | 
            +
                    # e.g. instead of `all_packages.checkers.enforce_dependencies.strict.count`, we'd see
         | 
| 57 | 
            +
                    # e.g. instead of `all_packages.prevent_this_package_from_creating_other_namespaces.fail_on_new.count`, we'd see
         | 
| 58 | 
            +
                    # e.g. instead of `all_packages.cops.packs_namespaceconvention.true.count`, we'd see
         | 
| 59 | 
            +
                    # 
         | 
| 60 | 
            +
                    sig do
         | 
| 61 | 
            +
                      params(
         | 
| 62 | 
            +
                        package: ParsePackwerk::Package,
         | 
| 63 | 
            +
                        protection: PackageProtections::ProtectionInterface,
         | 
| 64 | 
            +
                        violation_behavior: PackageProtections::ViolationBehavior
         | 
| 65 | 
            +
                      ).returns(T::Boolean)
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
                    def self.should_count_package?(package, protection, violation_behavior)
         | 
| 68 | 
            +
                      if protection.identifier == 'prevent_this_package_from_violating_its_stated_dependencies'
         | 
| 69 | 
            +
                        strict_mode = package.metadata['strictly_enforce_dependencies']
         | 
| 70 | 
            +
                        enabled = package.enforces_dependencies?
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                        case violation_behavior
         | 
| 73 | 
            +
                        when PackageProtections::ViolationBehavior::FailOnAny
         | 
| 74 | 
            +
                          !!strict_mode
         | 
| 75 | 
            +
                        when PackageProtections::ViolationBehavior::FailNever
         | 
| 76 | 
            +
                          !enabled
         | 
| 77 | 
            +
                        when PackageProtections::ViolationBehavior::FailOnNew
         | 
| 78 | 
            +
                          enabled && !strict_mode
         | 
| 79 | 
            +
                        else
         | 
| 80 | 
            +
                          T.absurd(violation_behavior)
         | 
| 81 | 
            +
                        end
         | 
| 82 | 
            +
                      elsif protection.identifier == 'prevent_other_packages_from_using_this_packages_internals'
         | 
| 83 | 
            +
                        strict_mode = package.metadata['strictly_enforce_privacy']
         | 
| 84 | 
            +
                        enabled = package.enforces_privacy?
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                        case violation_behavior
         | 
| 87 | 
            +
                        when PackageProtections::ViolationBehavior::FailOnAny
         | 
| 88 | 
            +
                          !!strict_mode
         | 
| 89 | 
            +
                        when PackageProtections::ViolationBehavior::FailNever
         | 
| 90 | 
            +
                          !enabled
         | 
| 91 | 
            +
                        when PackageProtections::ViolationBehavior::FailOnNew
         | 
| 92 | 
            +
                          enabled && !strict_mode
         | 
| 93 | 
            +
                        else
         | 
| 94 | 
            +
                          T.absurd(violation_behavior)
         | 
| 95 | 
            +
                        end
         | 
| 96 | 
            +
                      elsif protection.identifier == 'prevent_other_packages_from_using_this_package_without_explicit_visibility'
         | 
| 97 | 
            +
                        case violation_behavior
         | 
| 98 | 
            +
                        when PackageProtections::ViolationBehavior::FailOnAny
         | 
| 99 | 
            +
                          # We'd probably not want to support this right away
         | 
| 100 | 
            +
                          false
         | 
| 101 | 
            +
                        when PackageProtections::ViolationBehavior::FailNever
         | 
| 102 | 
            +
                          # We'd need to add this to `parse_packwerk` so that we can get other arbitrary top-level keys.
         | 
| 103 | 
            +
                          # Alternatively we can put this in `metadata` for the time being to unblock us.
         | 
| 104 | 
            +
                          # package.config['enforce_visibility']
         | 
| 105 | 
            +
                          !package.metadata['enforce_visibility']
         | 
| 106 | 
            +
                        when PackageProtections::ViolationBehavior::FailOnNew
         | 
| 107 | 
            +
                          !!package.metadata['enforce_visibility']
         | 
| 108 | 
            +
                        else
         | 
| 109 | 
            +
                          T.absurd(violation_behavior)
         | 
| 110 | 
            +
                        end
         | 
| 111 | 
            +
                      else
         | 
| 112 | 
            +
                        # Otherwise, we're in a rubocop case
         | 
| 113 | 
            +
                        rubocop_yml_file = package.directory.join('.rubocop.yml')
         | 
| 114 | 
            +
                        return false if !rubocop_yml_file.exist?
         | 
| 115 | 
            +
                        rubocop_yml = YAML.load_file(rubocop_yml_file)
         | 
| 116 | 
            +
                        protection = T.cast(protection, PackageProtections::RubocopProtectionInterface)
         | 
| 117 | 
            +
                        # We will likely want a rubocop-packs API for this, to be able to ask if a cop is enabled for a pack.
         | 
| 118 | 
            +
                        # It's possible we will want to allow these to be enabled at the top-level `.rubocop.yml`,
         | 
| 119 | 
            +
                        # in which case we wouldn't get the right metrics with this approach. However, we can also accept
         | 
| 120 | 
            +
                        # that as a current limitation.
         | 
| 121 | 
            +
                        cop_map = {
         | 
| 122 | 
            +
                          'PackageProtections/TypedPublicApi' => 'Packs/TypedPublicApi',
         | 
| 123 | 
            +
                          'PackageProtections/NamespacedUnderPackageName' => 'Packs/NamespaceConvention',
         | 
| 124 | 
            +
                          'PackageProtections/OnlyClassMethods' => 'Packs/ClassMethodsAsPublicApis',
         | 
| 125 | 
            +
                          'PackageProtections/RequireDocumentedPublicApis' => 'Packs/RequireDocumentedPublicApis',
         | 
| 126 | 
            +
                        }
         | 
| 127 | 
            +
                        # We want to use the cop names from `rubocop-packs`. Eventually, we'll just literate over these
         | 
| 128 | 
            +
                        # cop names directly, or ask `rubocop-packs` for the list of cops to care about.
         | 
| 129 | 
            +
                        cop_config = rubocop_yml[cop_map[protection.cop_name]]
         | 
| 130 | 
            +
                        return false if cop_config.nil?
         | 
| 131 | 
            +
                        enabled = cop_config['Enabled']
         | 
| 132 | 
            +
                        strict_mode = cop_config['FailureMode'] == 'strict'
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                        case violation_behavior
         | 
| 135 | 
            +
                        when PackageProtections::ViolationBehavior::FailOnAny
         | 
| 136 | 
            +
                          !!strict_mode
         | 
| 137 | 
            +
                        when PackageProtections::ViolationBehavior::FailNever
         | 
| 138 | 
            +
                          !enabled
         | 
| 139 | 
            +
                        when PackageProtections::ViolationBehavior::FailOnNew
         | 
| 140 | 
            +
                          enabled && !strict_mode
         | 
| 141 | 
            +
                        else
         | 
| 142 | 
            +
                          T.absurd(violation_behavior)
         | 
| 143 | 
            +
                        end
         | 
| 144 | 
            +
                      end
         | 
| 145 | 
            +
                    end
         | 
| 30 146 | 
             
                  end
         | 
| 31 147 | 
             
                end
         | 
| 32 148 | 
             
              end
         | 
| @@ -7,8 +7,10 @@ module ModularizationStatistics | |
| 7 7 | 
             
                  class RubocopProtectionsExclusions
         | 
| 8 8 | 
             
                    extend T::Sig
         | 
| 9 9 |  | 
| 10 | 
            -
                    sig { params(prefix: String,  | 
| 11 | 
            -
                    def self.get_rubocop_exclusions(prefix,  | 
| 10 | 
            +
                    sig { params(prefix: String, packages: T::Array[ParsePackwerk::Package], package_tags: T::Array[Tag]).returns(T::Array[GaugeMetric]) }
         | 
| 11 | 
            +
                    def self.get_rubocop_exclusions(prefix, packages, package_tags)
         | 
| 12 | 
            +
                      protected_packages = packages.map { |p| PackageProtections::ProtectedPackage.from(p) }
         | 
| 13 | 
            +
             | 
| 12 14 | 
             
                      rubocop_based_package_protections = T.cast(PackageProtections.all.select { |p| p.is_a?(PackageProtections::RubocopProtectionInterface) }, T::Array[PackageProtections::RubocopProtectionInterface])
         | 
| 13 15 | 
             
                      rubocop_based_package_protections.flat_map do |rubocop_based_package_protection|
         | 
| 14 16 | 
             
                        metric_name = "#{prefix}.#{rubocop_based_package_protection.identifier}.rubocop_exclusions.count"
         | 
| @@ -17,6 +19,7 @@ module ModularizationStatistics | |
| 17 19 | 
             
                      end
         | 
| 18 20 | 
             
                    end
         | 
| 19 21 |  | 
| 22 | 
            +
                    # TODO: `rubocop-packs` may want to expose API for this
         | 
| 20 23 | 
             
                    sig { params(package: ParsePackwerk::Package, protection: PackageProtections::RubocopProtectionInterface).returns(Integer) }
         | 
| 21 24 | 
             
                    def self.exclude_count_for_package_and_protection(package, protection)
         | 
| 22 25 | 
             
                      rubocop_todo = package.directory.join('.rubocop_todo.yml')
         | 
| @@ -15,7 +15,7 @@ module ParsePackwerk | |
| 15 15 | 
             
                sig { params(name: ::String).returns(T.nilable(::ParsePackwerk::Package)) }
         | 
| 16 16 | 
             
                def find(name); end
         | 
| 17 17 |  | 
| 18 | 
            -
                sig { params(file_path: T.any(::Pathname, ::String)).returns( | 
| 18 | 
            +
                sig { params(file_path: T.any(::Pathname, ::String)).returns(::ParsePackwerk::Package) }
         | 
| 19 19 | 
             
                def package_from_path(file_path); end
         | 
| 20 20 |  | 
| 21 21 | 
             
                sig { params(package: ::ParsePackwerk::Package).void }
         | 
| @@ -51,6 +51,7 @@ end | |
| 51 51 |  | 
| 52 52 | 
             
            ParsePackwerk::DEFAULT_EXCLUDE_GLOBS = T.let(T.unsafe(nil), Array)
         | 
| 53 53 | 
             
            ParsePackwerk::DEFAULT_PACKAGE_PATHS = T.let(T.unsafe(nil), Array)
         | 
| 54 | 
            +
            ParsePackwerk::DEFAULT_PUBLIC_PATH = T.let(T.unsafe(nil), String)
         | 
| 54 55 | 
             
            ParsePackwerk::DEPENDENCIES = T.let(T.unsafe(nil), String)
         | 
| 55 56 | 
             
            ParsePackwerk::DEPRECATED_REFERENCES_YML_NAME = T.let(T.unsafe(nil), String)
         | 
| 56 57 |  | 
| @@ -81,6 +82,7 @@ end | |
| 81 82 |  | 
| 82 83 | 
             
            ParsePackwerk::PACKAGE_YML_NAME = T.let(T.unsafe(nil), String)
         | 
| 83 84 | 
             
            ParsePackwerk::PACKWERK_YML_NAME = T.let(T.unsafe(nil), String)
         | 
| 85 | 
            +
            ParsePackwerk::PUBLIC_PATH = T.let(T.unsafe(nil), String)
         | 
| 84 86 |  | 
| 85 87 | 
             
            class ParsePackwerk::Package < ::T::Struct
         | 
| 86 88 | 
             
              const :dependencies, T::Array[::String]
         | 
| @@ -88,6 +90,7 @@ class ParsePackwerk::Package < ::T::Struct | |
| 88 90 | 
             
              const :enforce_privacy, T::Boolean
         | 
| 89 91 | 
             
              const :metadata, T::Hash[T.untyped, T.untyped]
         | 
| 90 92 | 
             
              const :name, ::String
         | 
| 93 | 
            +
              const :public_path, ::String, default: T.unsafe(nil)
         | 
| 91 94 |  | 
| 92 95 | 
             
              sig { returns(::Pathname) }
         | 
| 93 96 | 
             
              def directory; end
         | 
| @@ -98,6 +101,12 @@ class ParsePackwerk::Package < ::T::Struct | |
| 98 101 | 
             
              sig { returns(T::Boolean) }
         | 
| 99 102 | 
             
              def enforces_privacy?; end
         | 
| 100 103 |  | 
| 104 | 
            +
              sig { returns(::Pathname) }
         | 
| 105 | 
            +
              def public_directory; end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
              sig { returns(T::Array[::ParsePackwerk::Violation]) }
         | 
| 108 | 
            +
              def violations; end
         | 
| 109 | 
            +
             | 
| 101 110 | 
             
              sig { returns(::Pathname) }
         | 
| 102 111 | 
             
              def yml; end
         | 
| 103 112 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: modularization_statistics
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.39.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Gusto Engineers
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022- | 
| 11 | 
            +
            date: 2022-11-01 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: code_teams
         | 
| @@ -194,7 +194,7 @@ files: | |
| 194 194 | 
             
            - sorbet/rbi/gems/dogapi@1.45.0.rbi
         | 
| 195 195 | 
             
            - sorbet/rbi/gems/manual.rbi
         | 
| 196 196 | 
             
            - sorbet/rbi/gems/package_protections@1.4.0.rbi
         | 
| 197 | 
            -
            - sorbet/rbi/gems/parse_packwerk@0. | 
| 197 | 
            +
            - sorbet/rbi/gems/parse_packwerk@0.14.0.rbi
         | 
| 198 198 | 
             
            - sorbet/rbi/gems/rspec@3.10.0.rbi
         | 
| 199 199 | 
             
            - sorbet/rbi/todo.rbi
         | 
| 200 200 | 
             
            homepage: https://github.com/rubyatscale/modularization_statistics
         | 
| @@ -220,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 220 220 | 
             
                - !ruby/object:Gem::Version
         | 
| 221 221 | 
             
                  version: '0'
         | 
| 222 222 | 
             
            requirements: []
         | 
| 223 | 
            -
            rubygems_version: 3. | 
| 223 | 
            +
            rubygems_version: 3.1.6
         | 
| 224 224 | 
             
            signing_key: 
         | 
| 225 225 | 
             
            specification_version: 4
         | 
| 226 226 | 
             
            summary: A gem to collect statistics about modularization progress in a Rails application
         |