modularization_statistics 1.37.0 → 1.38.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 +44 -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: 1ab5b40d2d974d45aae986a4a0418e8d50984c4d4d39e963815dfd5fb875efc6
|
4
|
+
data.tar.gz: 91a571c247677445e408cd8aa0d2cc0a4adc2e5daed55ce4a6a8cc2e69429b81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3454d7e5f523f3d6030e1b1789fa1d0b363fbcc6c7069170797c4efd4256a463a77d43dbfa94da1fce24b13283592eb016f7923591b28406038ed9e44fd0eb5
|
7
|
+
data.tar.gz: 5718efcffc45331f23b185f8b7565301cd35d8c1735eca4e9723b3086725ec30b7b6c399c16fdcc0788795fa4d39654c7bfa8348ec8b6188d3522584e55de147
|
@@ -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,7 +23,47 @@ 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
|
+
case violation_behavior
|
41
|
+
when PackageProtections::ViolationBehavior::FailOnAny
|
42
|
+
# There is not yet an implementation for `FailOnAny` for systems that don't use package protections
|
43
|
+
false
|
44
|
+
when PackageProtections::ViolationBehavior::FailNever
|
45
|
+
if protection.identifier == 'prevent_this_package_from_violating_its_stated_dependencies'
|
46
|
+
!p.original_package.enforces_dependencies?
|
47
|
+
elsif protection.identifier == 'prevent_other_packages_from_using_this_packages_internals'
|
48
|
+
!p.original_package.enforces_privacy?
|
49
|
+
else
|
50
|
+
# This is not applicable if you're not using package protections
|
51
|
+
true
|
52
|
+
end
|
53
|
+
when PackageProtections::ViolationBehavior::FailOnNew
|
54
|
+
if protection.identifier == 'prevent_this_package_from_violating_its_stated_dependencies'
|
55
|
+
p.original_package.enforces_dependencies?
|
56
|
+
elsif protection.identifier == 'prevent_other_packages_from_using_this_packages_internals'
|
57
|
+
p.original_package.enforces_privacy?
|
58
|
+
else
|
59
|
+
# This is not applicable if you're not using package protections
|
60
|
+
false
|
61
|
+
end
|
62
|
+
else
|
63
|
+
T.absurd(violation_behavior)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
26
67
|
GaugeMetric.for(metric_name, count_of_packages, package_tags)
|
27
68
|
end
|
28
69
|
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.38.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-10-26 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
|