pack_stats 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +127 -0
- data/lib/pack_stats/gauge_metric.rb +39 -0
- data/lib/pack_stats/private/datadog_reporter.rb +61 -0
- data/lib/pack_stats/private/metrics/files.rb +47 -0
- data/lib/pack_stats/private/metrics/nested_packs.rb +137 -0
- data/lib/pack_stats/private/metrics/packages.rb +105 -0
- data/lib/pack_stats/private/metrics/packages_by_team.rb +69 -0
- data/lib/pack_stats/private/metrics/packwerk_checker_usage.rb +52 -0
- data/lib/pack_stats/private/metrics/public_usage.rb +36 -0
- data/lib/pack_stats/private/metrics/rubocop_usage.rb +98 -0
- data/lib/pack_stats/private/metrics.rb +49 -0
- data/lib/pack_stats/private/source_code_file.rb +24 -0
- data/lib/pack_stats/private.rb +54 -0
- data/lib/pack_stats/tag.rb +28 -0
- data/lib/pack_stats/tags.rb +20 -0
- data/lib/pack_stats.rb +154 -0
- data/sorbet/config +4 -0
- data/sorbet/rbi/gems/code_ownership@1.28.0.rbi +337 -0
- data/sorbet/rbi/gems/code_teams@1.0.0.rbi +120 -0
- data/sorbet/rbi/gems/dogapi@1.45.0.rbi +551 -0
- data/sorbet/rbi/gems/manual.rbi +4 -0
- data/sorbet/rbi/gems/parse_packwerk@0.14.0.rbi +155 -0
- data/sorbet/rbi/gems/rspec@3.10.0.rbi +13 -0
- data/sorbet/rbi/gems/rubocop-packs@0.0.20.rbi +141 -0
- data/sorbet/rbi/todo.rbi +5 -0
- metadata +228 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module PackStats
|
5
|
+
module Private
|
6
|
+
module Metrics
|
7
|
+
class PublicUsage
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(prefix: String, packages: T::Array[ParsePackwerk::Package], package_tags: T::Array[Tag]).returns(T::Array[GaugeMetric]) }
|
11
|
+
def self.get_public_usage_metrics(prefix, packages, package_tags)
|
12
|
+
packages_except_for_root = packages.reject { |package| package.name == ParsePackwerk::ROOT_PACKAGE_NAME }
|
13
|
+
all_files = packages_except_for_root.flat_map do |package|
|
14
|
+
package.directory.glob('**/**.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
all_public_files = T.let([], T::Array[Pathname])
|
18
|
+
is_using_public_directory = 0
|
19
|
+
packages_except_for_root.each do |package|
|
20
|
+
public_files = package.directory.glob('app/public/**/**.rb')
|
21
|
+
all_public_files += public_files
|
22
|
+
is_using_public_directory += 1 if public_files.any?
|
23
|
+
end
|
24
|
+
|
25
|
+
# In Datadog, we can divide public files by all files to get the ratio.
|
26
|
+
# This is not a metric that we are targeting -- its for observability and reflection only.
|
27
|
+
[
|
28
|
+
GaugeMetric.for("#{prefix}.all_files.count", all_files.count, package_tags),
|
29
|
+
GaugeMetric.for("#{prefix}.public_files.count", all_public_files.count, package_tags),
|
30
|
+
GaugeMetric.for("#{prefix}.using_public_directory.count", is_using_public_directory, package_tags),
|
31
|
+
]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module PackStats
|
5
|
+
module Private
|
6
|
+
module Metrics
|
7
|
+
class RubocopUsage
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(prefix: String, packages: T::Array[ParsePackwerk::Package], package_tags: T::Array[Tag]).returns(T::Array[GaugeMetric]) }
|
11
|
+
def self.get_metrics(prefix, packages, package_tags)
|
12
|
+
[
|
13
|
+
*get_rubocop_exclusions(prefix, packages, package_tags),
|
14
|
+
*get_rubocop_usage_metrics(prefix, packages, package_tags)
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
sig { params(prefix: String, packages: T::Array[ParsePackwerk::Package], package_tags: T::Array[Tag]).returns(T::Array[GaugeMetric]) }
|
19
|
+
def self.get_rubocop_usage_metrics(prefix, packages, package_tags)
|
20
|
+
metrics = T.let([], T::Array[GaugeMetric])
|
21
|
+
|
22
|
+
rubocops.each do |cop_name|
|
23
|
+
['false', 'true', 'strict'].each do |enabled_mode|
|
24
|
+
count_of_packages = ParsePackwerk.all.count do |package|
|
25
|
+
# We will likely want a rubocop-packs API for this, to be able to ask if a cop is enabled for a pack.
|
26
|
+
# It's possible we will want to allow these to be enabled at the top-level `.rubocop.yml`,
|
27
|
+
# in which case we wouldn't get the right metrics with this approach. However, we can also accept
|
28
|
+
# that as a current limitation.
|
29
|
+
rubocop_yml_file = package.directory.join(RuboCop::Packs::PACK_LEVEL_RUBOCOP_YML)
|
30
|
+
next false if !rubocop_yml_file.exist?
|
31
|
+
rubocop_yml = YAML.load_file(rubocop_yml_file)
|
32
|
+
cop_config = rubocop_yml[cop_name]
|
33
|
+
|
34
|
+
strict_mode = cop_config && cop_config['FailureMode'] == 'strict'
|
35
|
+
enabled = cop_config && cop_config['Enabled']
|
36
|
+
case enabled_mode
|
37
|
+
when 'false'
|
38
|
+
!enabled
|
39
|
+
when 'true'
|
40
|
+
enabled && !strict_mode
|
41
|
+
when 'strict'
|
42
|
+
!!strict_mode
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
metric_name = "#{prefix}.rubocops.#{to_tag_name(cop_name)}.#{enabled_mode}.count"
|
47
|
+
metrics << GaugeMetric.for(metric_name, count_of_packages, package_tags)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
metrics
|
52
|
+
end
|
53
|
+
|
54
|
+
sig { params(prefix: String, packages: T::Array[ParsePackwerk::Package], package_tags: T::Array[Tag]).returns(T::Array[GaugeMetric]) }
|
55
|
+
def self.get_rubocop_exclusions(prefix, packages, package_tags)
|
56
|
+
rubocops.flat_map do |cop_name|
|
57
|
+
metric_name = "#{prefix}.rubocops.#{to_tag_name(cop_name)}.exclusions.count"
|
58
|
+
all_exclusions_count = ParsePackwerk.all.sum { |package| exclude_count_for_package_and_protection(package, cop_name)}
|
59
|
+
GaugeMetric.for(metric_name, all_exclusions_count, package_tags)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# TODO: `rubocop-packs` may want to expose API for this
|
64
|
+
sig { params(package: ParsePackwerk::Package, cop_name: String).returns(Integer) }
|
65
|
+
def self.exclude_count_for_package_and_protection(package, cop_name)
|
66
|
+
if package.name == ParsePackwerk::ROOT_PACKAGE_NAME
|
67
|
+
rubocop_todo = package.directory.join('.rubocop_todo.yml')
|
68
|
+
else
|
69
|
+
rubocop_todo = package.directory.join(RuboCop::Packs::PACK_LEVEL_RUBOCOP_TODO_YML)
|
70
|
+
end
|
71
|
+
|
72
|
+
if rubocop_todo.exist?
|
73
|
+
loaded_rubocop_todo = YAML.load_file(rubocop_todo)
|
74
|
+
cop_config = loaded_rubocop_todo.fetch(cop_name, {})
|
75
|
+
cop_config.fetch('Exclude', []).count
|
76
|
+
else
|
77
|
+
0
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
sig { returns(T::Array[String])}
|
82
|
+
def self.rubocops
|
83
|
+
[
|
84
|
+
'Packs/ClassMethodsAsPublicApis',
|
85
|
+
'Packs/RootNamespaceIsPackName',
|
86
|
+
'Packs/TypedPublicApis',
|
87
|
+
'Packs/DocumentedPublicApis',
|
88
|
+
]
|
89
|
+
end
|
90
|
+
|
91
|
+
sig { params(cop_name: String).returns(String) }
|
92
|
+
def self.to_tag_name(cop_name)
|
93
|
+
cop_name.gsub('/', '_').downcase
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module PackStats
|
5
|
+
module Private
|
6
|
+
module Metrics
|
7
|
+
extend T::Sig
|
8
|
+
UNKNOWN_OWNER = T.let('Unknown', String)
|
9
|
+
|
10
|
+
sig { params(team_name: T.nilable(String)).returns(T::Array[Tag]) }
|
11
|
+
def self.tags_for_team(team_name)
|
12
|
+
[Tag.for('team', team_name || UNKNOWN_OWNER)]
|
13
|
+
end
|
14
|
+
|
15
|
+
sig { params(package: ParsePackwerk::Package, app_name: String).returns(T::Array[Tag]) }
|
16
|
+
def self.tags_for_package(package, app_name)
|
17
|
+
[
|
18
|
+
Tag.new(key: 'package', value: humanized_package_name(package.name)),
|
19
|
+
Tag.new(key: 'app', value: app_name),
|
20
|
+
*Metrics.tags_for_team(CodeOwnership.for_package(package)&.name),
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
sig { params(team_name: T.nilable(String)).returns(T::Array[Tag]) }
|
25
|
+
def self.tags_for_to_team(team_name)
|
26
|
+
[Tag.for('to_team', team_name || Metrics::UNKNOWN_OWNER)]
|
27
|
+
end
|
28
|
+
|
29
|
+
sig { params(name: String).returns(String) }
|
30
|
+
def self.humanized_package_name(name)
|
31
|
+
if name == ParsePackwerk::ROOT_PACKAGE_NAME
|
32
|
+
'root'
|
33
|
+
else
|
34
|
+
name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
sig { params(violations: T::Array[ParsePackwerk::Violation]).returns(Integer) }
|
39
|
+
def self.file_count(violations)
|
40
|
+
violations.sum { |v| v.files.count }
|
41
|
+
end
|
42
|
+
|
43
|
+
sig { params(package: ParsePackwerk::Package).returns(T::Boolean) }
|
44
|
+
def self.has_readme?(package)
|
45
|
+
package.directory.join('README.md').exist?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module PackStats
|
4
|
+
module Private
|
5
|
+
class SourceCodeFile < T::Struct
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
const :is_componentized_file, T::Boolean
|
9
|
+
const :is_packaged_file, T::Boolean
|
10
|
+
const :team_owner, T.nilable(CodeTeams::Team)
|
11
|
+
const :pathname, Pathname
|
12
|
+
|
13
|
+
sig { returns(T::Boolean) }
|
14
|
+
def componentized_file?
|
15
|
+
self.is_componentized_file
|
16
|
+
end
|
17
|
+
|
18
|
+
sig { returns(T::Boolean) }
|
19
|
+
def packaged_file?
|
20
|
+
self.is_packaged_file
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module PackStats
|
4
|
+
module Private
|
5
|
+
extend T::Sig
|
6
|
+
|
7
|
+
METRIC_REPLACEMENTS = T.let({
|
8
|
+
# enforce_dependencies
|
9
|
+
'packwerk_checkers.enforce_dependencies.false' => 'prevent_this_package_from_violating_its_stated_dependencies.no',
|
10
|
+
'packwerk_checkers.enforce_dependencies.true' => 'prevent_this_package_from_violating_its_stated_dependencies.fail_the_build_if_new_instances_appear',
|
11
|
+
'packwerk_checkers.enforce_dependencies.strict' => 'prevent_this_package_from_violating_its_stated_dependencies.fail_the_build_on_any_instances',
|
12
|
+
# enforce_privacy
|
13
|
+
'packwerk_checkers.enforce_privacy.false' => 'prevent_other_packages_from_using_this_packages_internals.no',
|
14
|
+
'packwerk_checkers.enforce_privacy.true' => 'prevent_other_packages_from_using_this_packages_internals.fail_the_build_if_new_instances_appear',
|
15
|
+
'packwerk_checkers.enforce_privacy.strict' => 'prevent_other_packages_from_using_this_packages_internals.fail_the_build_on_any_instances',
|
16
|
+
# Packs/TypedPublicApis
|
17
|
+
'rubocops.packs_typedpublicapis.false' => 'prevent_this_package_from_exposing_an_untyped_api.no',
|
18
|
+
'rubocops.packs_typedpublicapis.true' => 'prevent_this_package_from_exposing_an_untyped_api.fail_the_build_if_new_instances_appear',
|
19
|
+
'rubocops.packs_typedpublicapis.strict' => 'prevent_this_package_from_exposing_an_untyped_api.fail_the_build_on_any_instances',
|
20
|
+
'rubocops.packs_typedpublicapis.exclusions' => 'prevent_this_package_from_exposing_an_untyped_api.rubocop_exclusions',
|
21
|
+
# Packs/RootNamespaceIsPackName
|
22
|
+
'rubocops.packs_rootnamespaceispackname.false' => 'prevent_this_package_from_creating_other_namespaces.no',
|
23
|
+
'rubocops.packs_rootnamespaceispackname.true' => 'prevent_this_package_from_creating_other_namespaces.fail_the_build_if_new_instances_appear',
|
24
|
+
'rubocops.packs_rootnamespaceispackname.strict' => 'prevent_this_package_from_creating_other_namespaces.fail_the_build_on_any_instances',
|
25
|
+
'rubocops.packs_rootnamespaceispackname.exclusions' => 'prevent_this_package_from_creating_other_namespaces.rubocop_exclusions',
|
26
|
+
# Packs/ClassMethodsAsPublicApis
|
27
|
+
'rubocops.packs_classmethodsaspublicapis.false' => 'prevent_this_package_from_exposing_instance_method_public_apis.no',
|
28
|
+
'rubocops.packs_classmethodsaspublicapis.true' => 'prevent_this_package_from_exposing_instance_method_public_apis.fail_the_build_if_new_instances_appear',
|
29
|
+
'rubocops.packs_classmethodsaspublicapis.strict' => 'prevent_this_package_from_exposing_instance_method_public_apis.fail_the_build_on_any_instances',
|
30
|
+
'rubocops.packs_classmethodsaspublicapis.exclusions' => 'prevent_this_package_from_exposing_instance_method_public_apis.rubocop_exclusions',
|
31
|
+
# Packs/DocumentedPublicApis
|
32
|
+
'rubocops.packs_documentedpublicapis.false' => 'prevent_this_package_from_exposing_undocumented_public_apis.no',
|
33
|
+
'rubocops.packs_documentedpublicapis.true' => 'prevent_this_package_from_exposing_undocumented_public_apis.fail_the_build_if_new_instances_appear',
|
34
|
+
'rubocops.packs_documentedpublicapis.strict' => 'prevent_this_package_from_exposing_undocumented_public_apis.fail_the_build_on_any_instances',
|
35
|
+
'rubocops.packs_documentedpublicapis.exclusions' => 'prevent_this_package_from_exposing_undocumented_public_apis.rubocop_exclusions',
|
36
|
+
}, T::Hash[String, String])
|
37
|
+
|
38
|
+
sig { params(metrics: T::Array[GaugeMetric]).returns(T::Array[GaugeMetric]) }
|
39
|
+
def self.convert_metrics_to_legacy(metrics)
|
40
|
+
metrics.map do |metric|
|
41
|
+
new_metric = metric
|
42
|
+
METRIC_REPLACEMENTS.each do |current_name, legacy_name|
|
43
|
+
new_metric = new_metric.with(
|
44
|
+
name: new_metric.name.gsub(current_name, legacy_name)
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
new_metric
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private_constant :Private
|
54
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module PackStats
|
4
|
+
class Tag < T::Struct
|
5
|
+
extend T::Sig
|
6
|
+
const :key, String
|
7
|
+
const :value, String
|
8
|
+
|
9
|
+
sig { returns(String) }
|
10
|
+
def to_s
|
11
|
+
"#{key}:#{value}"
|
12
|
+
end
|
13
|
+
|
14
|
+
sig { params(key: String, value: String).returns(Tag) }
|
15
|
+
def self.for(key, value)
|
16
|
+
new(
|
17
|
+
key: key,
|
18
|
+
value: value
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
sig { params(other: Tag).returns(T::Boolean) }
|
23
|
+
def ==(other)
|
24
|
+
other.key == self.key &&
|
25
|
+
other.value == self.value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module PackStats
|
4
|
+
module Tags
|
5
|
+
extend T::Sig
|
6
|
+
|
7
|
+
sig { params(colon_delimited_tag_strings: T::Array[String]).returns(T::Array[Tag]) }
|
8
|
+
def self.for(colon_delimited_tag_strings)
|
9
|
+
colon_delimited_tag_strings.map do |colon_delimited_tag_string|
|
10
|
+
key, value = colon_delimited_tag_string.split(':')
|
11
|
+
raise StandardError, "Improperly formatted tag `#{colon_delimited_tag_string}`" if key.nil? || value.nil?
|
12
|
+
|
13
|
+
Tag.new(
|
14
|
+
key: key,
|
15
|
+
value: value
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/pack_stats.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
require 'sorbet-runtime'
|
4
|
+
require 'json'
|
5
|
+
require 'yaml'
|
6
|
+
require 'benchmark'
|
7
|
+
require 'code_teams'
|
8
|
+
require 'code_ownership'
|
9
|
+
require 'pathname'
|
10
|
+
require 'pack_stats/private'
|
11
|
+
require 'pack_stats/private/source_code_file'
|
12
|
+
require 'pack_stats/private/datadog_reporter'
|
13
|
+
require 'parse_packwerk'
|
14
|
+
require 'pack_stats/tag'
|
15
|
+
require 'pack_stats/tags'
|
16
|
+
require 'pack_stats/gauge_metric'
|
17
|
+
|
18
|
+
module PackStats
|
19
|
+
extend T::Sig
|
20
|
+
|
21
|
+
ROOT_PACKAGE_NAME = T.let('root'.freeze, String)
|
22
|
+
|
23
|
+
DEFAULT_COMPONENTIZED_SOURCE_CODE_LOCATIONS = T.let(
|
24
|
+
[
|
25
|
+
Pathname.new('components'),
|
26
|
+
Pathname.new('gems'),
|
27
|
+
].freeze, T::Array[Pathname]
|
28
|
+
)
|
29
|
+
|
30
|
+
DEFAULT_PACKAGED_SOURCE_CODE_LOCATIONS = T.let(
|
31
|
+
[
|
32
|
+
Pathname.new('packs'),
|
33
|
+
Pathname.new('packages'),
|
34
|
+
].freeze, T::Array[Pathname]
|
35
|
+
)
|
36
|
+
|
37
|
+
sig do
|
38
|
+
params(
|
39
|
+
datadog_client: Dogapi::Client,
|
40
|
+
app_name: String,
|
41
|
+
source_code_pathnames: T::Array[Pathname],
|
42
|
+
componentized_source_code_locations: T::Array[Pathname],
|
43
|
+
packaged_source_code_locations: T::Array[Pathname],
|
44
|
+
report_time: Time,
|
45
|
+
verbose: T::Boolean,
|
46
|
+
# See note on get_metrics
|
47
|
+
use_gusto_legacy_names: T::Boolean
|
48
|
+
).void
|
49
|
+
end
|
50
|
+
def self.report_to_datadog!(
|
51
|
+
datadog_client:,
|
52
|
+
app_name:,
|
53
|
+
source_code_pathnames:,
|
54
|
+
componentized_source_code_locations: DEFAULT_COMPONENTIZED_SOURCE_CODE_LOCATIONS,
|
55
|
+
packaged_source_code_locations: DEFAULT_PACKAGED_SOURCE_CODE_LOCATIONS,
|
56
|
+
report_time: Time.now, # rubocop:disable Rails/TimeZone
|
57
|
+
verbose: false,
|
58
|
+
use_gusto_legacy_names: false
|
59
|
+
)
|
60
|
+
|
61
|
+
all_metrics = self.get_metrics(
|
62
|
+
source_code_pathnames: source_code_pathnames,
|
63
|
+
componentized_source_code_locations: componentized_source_code_locations,
|
64
|
+
packaged_source_code_locations: packaged_source_code_locations,
|
65
|
+
app_name: app_name,
|
66
|
+
use_gusto_legacy_names: use_gusto_legacy_names,
|
67
|
+
)
|
68
|
+
|
69
|
+
# This helps us debug what metrics are being sent
|
70
|
+
if verbose
|
71
|
+
all_metrics.each do |metric|
|
72
|
+
puts "Sending metric: #{metric}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if use_gusto_legacy_names
|
77
|
+
all_metrics = Private.convert_metrics_to_legacy(all_metrics)
|
78
|
+
end
|
79
|
+
|
80
|
+
Private::DatadogReporter.report!(
|
81
|
+
datadog_client: datadog_client,
|
82
|
+
report_time: report_time,
|
83
|
+
metrics: all_metrics
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
sig do
|
88
|
+
params(
|
89
|
+
source_code_pathnames: T::Array[Pathname],
|
90
|
+
componentized_source_code_locations: T::Array[Pathname],
|
91
|
+
packaged_source_code_locations: T::Array[Pathname],
|
92
|
+
app_name: String,
|
93
|
+
# It is not recommended to set this to true.
|
94
|
+
# Gusto uses this to preserve historical trends in Dashboards as the names of
|
95
|
+
# things changed, but new dashboards can use names that better match current tooling conventions.
|
96
|
+
# The behavior of setting this parameter to true might change without warning
|
97
|
+
use_gusto_legacy_names: T::Boolean
|
98
|
+
).returns(T::Array[GaugeMetric])
|
99
|
+
end
|
100
|
+
def self.get_metrics(
|
101
|
+
source_code_pathnames:,
|
102
|
+
componentized_source_code_locations:,
|
103
|
+
packaged_source_code_locations:,
|
104
|
+
app_name:,
|
105
|
+
use_gusto_legacy_names: false
|
106
|
+
)
|
107
|
+
all_metrics = Private::DatadogReporter.get_metrics(
|
108
|
+
source_code_files: source_code_files(
|
109
|
+
source_code_pathnames: source_code_pathnames,
|
110
|
+
componentized_source_code_locations: componentized_source_code_locations,
|
111
|
+
packaged_source_code_locations: packaged_source_code_locations
|
112
|
+
),
|
113
|
+
app_name: app_name
|
114
|
+
)
|
115
|
+
|
116
|
+
if use_gusto_legacy_names
|
117
|
+
all_metrics = Private.convert_metrics_to_legacy(all_metrics)
|
118
|
+
end
|
119
|
+
|
120
|
+
all_metrics
|
121
|
+
end
|
122
|
+
|
123
|
+
sig do
|
124
|
+
params(
|
125
|
+
source_code_pathnames: T::Array[Pathname],
|
126
|
+
componentized_source_code_locations: T::Array[Pathname],
|
127
|
+
packaged_source_code_locations: T::Array[Pathname]
|
128
|
+
).returns(T::Array[Private::SourceCodeFile])
|
129
|
+
end
|
130
|
+
def self.source_code_files(
|
131
|
+
source_code_pathnames:,
|
132
|
+
componentized_source_code_locations:,
|
133
|
+
packaged_source_code_locations:
|
134
|
+
)
|
135
|
+
|
136
|
+
# Sorbet has the wrong signatures for `Pathname#find`, whoops!
|
137
|
+
componentized_file_set = Set.new(componentized_source_code_locations.select(&:exist?).flat_map { |pathname| T.unsafe(pathname).find.to_a })
|
138
|
+
packaged_file_set = Set.new(packaged_source_code_locations.select(&:exist?).flat_map { |pathname| T.unsafe(pathname).find.to_a })
|
139
|
+
|
140
|
+
source_code_pathnames.map do |pathname|
|
141
|
+
componentized_file = componentized_file_set.include?(pathname)
|
142
|
+
packaged_file = packaged_file_set.include?(pathname)
|
143
|
+
|
144
|
+
Private::SourceCodeFile.new(
|
145
|
+
pathname: pathname,
|
146
|
+
team_owner: CodeOwnership.for_file(pathname.to_s),
|
147
|
+
is_componentized_file: componentized_file,
|
148
|
+
is_packaged_file: packaged_file
|
149
|
+
)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
private_class_method :source_code_files
|
154
|
+
end
|
data/sorbet/config
ADDED