packs 0.0.5 → 0.0.22
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/README.md +101 -12
- data/bin/packs +10 -0
- data/bin/rubocop +29 -0
- data/bin/tapioca +29 -0
- data/lib/packs/cli.rb +164 -0
- data/lib/packs/code_ownership_post_processor.rb +58 -0
- data/lib/packs/configuration.rb +61 -0
- data/lib/packs/default_user_event_logger.rb +7 -0
- data/lib/packs/logging.rb +37 -0
- data/lib/packs/per_file_processor_interface.rb +18 -0
- data/lib/packs/private/file_move_operation.rb +80 -0
- data/lib/packs/private/interactive_cli/file_selector.rb +26 -0
- data/lib/packs/private/interactive_cli/pack_selector.rb +55 -0
- data/lib/packs/private/interactive_cli/team_selector.rb +58 -0
- data/lib/packs/private/interactive_cli/use_cases/add_dependency.rb +30 -0
- data/lib/packs/private/interactive_cli/use_cases/check.rb +25 -0
- data/lib/packs/private/interactive_cli/use_cases/create.rb +27 -0
- data/lib/packs/private/interactive_cli/use_cases/get_info.rb +37 -0
- data/lib/packs/private/interactive_cli/use_cases/interface.rb +34 -0
- data/lib/packs/private/interactive_cli/use_cases/lint_package_todo_yml_files.rb +25 -0
- data/lib/packs/private/interactive_cli/use_cases/lint_package_yml_files.rb +26 -0
- data/lib/packs/private/interactive_cli/use_cases/make_public.rb +30 -0
- data/lib/packs/private/interactive_cli/use_cases/move.rb +32 -0
- data/lib/packs/private/interactive_cli/use_cases/move_to_parent.rb +31 -0
- data/lib/packs/private/interactive_cli/use_cases/query.rb +51 -0
- data/lib/packs/private/interactive_cli/use_cases/rename.rb +25 -0
- data/lib/packs/private/interactive_cli/use_cases/update.rb +25 -0
- data/lib/packs/private/interactive_cli/use_cases/validate.rb +25 -0
- data/lib/packs/private/interactive_cli/use_cases/visualize.rb +44 -0
- data/lib/packs/private/interactive_cli.rb +52 -0
- data/lib/packs/private/pack_relationship_analyzer.rb +135 -0
- data/lib/packs/private/packwerk_wrapper/offenses_aggregator_formatter.rb +44 -0
- data/lib/packs/private/packwerk_wrapper.rb +70 -0
- data/lib/packs/private.rb +606 -4
- data/lib/packs/rubocop_post_processor.rb +30 -0
- data/lib/packs/user_event_logger.rb +199 -0
- data/lib/packs.rb +233 -53
- metadata +225 -14
- data/lib/packs/pack.rb +0 -43
- data/lib/packs/private/configuration.rb +0 -36
- data/lib/packs/rspec/fixture_helper.rb +0 -33
- data/lib/packs/rspec/support.rb +0 -21
@@ -0,0 +1,135 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module Packs
|
4
|
+
module Private
|
5
|
+
module PackRelationshipAnalyzer
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
sig do
|
9
|
+
params(
|
10
|
+
pack_name: T.nilable(String),
|
11
|
+
limit: Integer
|
12
|
+
).void
|
13
|
+
end
|
14
|
+
def self.list_top_privacy_violations(pack_name, limit)
|
15
|
+
all_packages = ParsePackwerk.all
|
16
|
+
if pack_name.nil?
|
17
|
+
to_package_names = all_packages.map(&:name)
|
18
|
+
else
|
19
|
+
pack_name = Private.clean_pack_name(pack_name)
|
20
|
+
package = all_packages.find { |p| p.name == pack_name }
|
21
|
+
if package.nil?
|
22
|
+
raise StandardError, "Can not find package with name #{pack_name}. Make sure the argument is of the form `packs/my_pack/`"
|
23
|
+
end
|
24
|
+
|
25
|
+
to_package_names = [pack_name]
|
26
|
+
end
|
27
|
+
|
28
|
+
violations_by_count = {}
|
29
|
+
total_pack_violation_count = 0
|
30
|
+
|
31
|
+
Logging.section('👋 Hi there') do
|
32
|
+
intro = Packs.config.user_event_logger.before_list_top_privacy_violations(pack_name, limit)
|
33
|
+
Logging.print_bold_green(intro)
|
34
|
+
end
|
35
|
+
|
36
|
+
# TODO: This is a copy of the implementation below. We may want to refactor out this implementation detail before making changes that apply to both.
|
37
|
+
all_packages.each do |client_package|
|
38
|
+
client_package.violations.select(&:privacy?).each do |violation|
|
39
|
+
next unless to_package_names.include?(violation.to_package_name)
|
40
|
+
|
41
|
+
if pack_name.nil?
|
42
|
+
violated_symbol = "#{violation.class_name} (#{violation.to_package_name})"
|
43
|
+
else
|
44
|
+
violated_symbol = violation.class_name
|
45
|
+
end
|
46
|
+
violations_by_count[violated_symbol] ||= {}
|
47
|
+
violations_by_count[violated_symbol][:total_count] ||= 0
|
48
|
+
violations_by_count[violated_symbol][:by_package] ||= {}
|
49
|
+
violations_by_count[violated_symbol][:by_package][client_package.name] ||= 0
|
50
|
+
violations_by_count[violated_symbol][:total_count] += violation.files.count
|
51
|
+
violations_by_count[violated_symbol][:by_package][client_package.name] += violation.files.count
|
52
|
+
total_pack_violation_count += violation.files.count
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Logging.print("Total Count: #{total_pack_violation_count}")
|
57
|
+
|
58
|
+
sorted_violations = violations_by_count.sort_by { |violated_symbol, count_info| [-count_info[:total_count], violated_symbol] }
|
59
|
+
sorted_violations.first(limit).each do |violated_symbol, count_info|
|
60
|
+
percentage_of_total = (count_info[:total_count] * 100.0 / total_pack_violation_count).round(2)
|
61
|
+
Logging.print(violated_symbol)
|
62
|
+
Logging.print(" - Total Count: #{count_info[:total_count]} (#{percentage_of_total}% of total)")
|
63
|
+
|
64
|
+
Logging.print(' - By package:')
|
65
|
+
count_info[:by_package].sort_by { |client_package_name, count| [-count, client_package_name] }.each do |client_package_name, count|
|
66
|
+
Logging.print(" - #{client_package_name}: #{count}")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
sig do
|
72
|
+
params(
|
73
|
+
pack_name: T.nilable(String),
|
74
|
+
limit: Integer
|
75
|
+
).void
|
76
|
+
end
|
77
|
+
def self.list_top_dependency_violations(pack_name, limit)
|
78
|
+
all_packages = ParsePackwerk.all
|
79
|
+
|
80
|
+
if pack_name.nil?
|
81
|
+
to_package_names = all_packages.map(&:name)
|
82
|
+
else
|
83
|
+
pack_name = Private.clean_pack_name(pack_name)
|
84
|
+
package = all_packages.find { |p| p.name == pack_name }
|
85
|
+
if package.nil?
|
86
|
+
raise StandardError, "Can not find package with name #{pack_name}. Make sure the argument is of the form `packs/my_pack/`"
|
87
|
+
end
|
88
|
+
|
89
|
+
to_package_names = [pack_name]
|
90
|
+
end
|
91
|
+
|
92
|
+
Logging.section('👋 Hi there') do
|
93
|
+
intro = Packs.config.user_event_logger.before_list_top_dependency_violations(pack_name, limit)
|
94
|
+
Logging.print_bold_green(intro)
|
95
|
+
end
|
96
|
+
|
97
|
+
violations_by_count = {}
|
98
|
+
total_pack_violation_count = 0
|
99
|
+
|
100
|
+
# TODO: This is a copy of the implementation above. We may want to refactor out this implementation detail before making changes that apply to both.
|
101
|
+
all_packages.each do |client_package|
|
102
|
+
client_package.violations.select(&:dependency?).each do |violation|
|
103
|
+
next unless to_package_names.include?(violation.to_package_name)
|
104
|
+
|
105
|
+
if pack_name.nil?
|
106
|
+
violated_symbol = "#{violation.class_name} (#{violation.to_package_name})"
|
107
|
+
else
|
108
|
+
violated_symbol = violation.class_name
|
109
|
+
end
|
110
|
+
violations_by_count[violated_symbol] ||= {}
|
111
|
+
violations_by_count[violated_symbol][:total_count] ||= 0
|
112
|
+
violations_by_count[violated_symbol][:by_package] ||= {}
|
113
|
+
violations_by_count[violated_symbol][:by_package][client_package.name] ||= 0
|
114
|
+
violations_by_count[violated_symbol][:total_count] += violation.files.count
|
115
|
+
violations_by_count[violated_symbol][:by_package][client_package.name] += violation.files.count
|
116
|
+
total_pack_violation_count += violation.files.count
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
Logging.print("Total Count: #{total_pack_violation_count}")
|
121
|
+
|
122
|
+
sorted_violations = violations_by_count.sort_by { |violated_symbol, count_info| [-count_info[:total_count], violated_symbol] }
|
123
|
+
sorted_violations.first(limit).each do |violated_symbol, count_info|
|
124
|
+
percentage_of_total = (count_info[:total_count] * 100.0 / total_pack_violation_count).round(2)
|
125
|
+
Logging.print(violated_symbol)
|
126
|
+
Logging.print(" - Total Count: #{count_info[:total_count]} (#{percentage_of_total}% of total)")
|
127
|
+
Logging.print(' - By package:')
|
128
|
+
count_info[:by_package].sort_by { |client_package_name, count| [-count, client_package_name] }.each do |client_package_name, count|
|
129
|
+
Logging.print(" - #{client_package_name}: #{count}")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module Packs
|
4
|
+
module Private
|
5
|
+
module PackwerkWrapper
|
6
|
+
#
|
7
|
+
# This formatter simply collects offenses so we can feed them into other systems
|
8
|
+
#
|
9
|
+
class OffensesAggregatorFormatter
|
10
|
+
extend T::Sig
|
11
|
+
include Packwerk::OffensesFormatter
|
12
|
+
|
13
|
+
sig { returns(T::Array[Packwerk::ReferenceOffense]) }
|
14
|
+
attr_reader :aggregated_offenses
|
15
|
+
|
16
|
+
sig { void }
|
17
|
+
def initialize
|
18
|
+
@aggregated_offenses = T.let([], T::Array[Packwerk::ReferenceOffense])
|
19
|
+
end
|
20
|
+
|
21
|
+
sig { override.params(offenses: T::Array[T.nilable(Packwerk::Offense)]).returns(String) }
|
22
|
+
def show_offenses(offenses)
|
23
|
+
@aggregated_offenses = T.unsafe(offenses)
|
24
|
+
''
|
25
|
+
end
|
26
|
+
|
27
|
+
sig { override.params(offense_collection: Packwerk::OffenseCollection, for_files: T::Set[String]).returns(String) }
|
28
|
+
def show_stale_violations(offense_collection, for_files)
|
29
|
+
''
|
30
|
+
end
|
31
|
+
|
32
|
+
sig { override.params(strict_mode_violations: T::Array[::Packwerk::ReferenceOffense]).returns(::String) }
|
33
|
+
def show_strict_mode_violations(strict_mode_violations)
|
34
|
+
''
|
35
|
+
end
|
36
|
+
|
37
|
+
sig { override.returns(::String) }
|
38
|
+
def identifier
|
39
|
+
'offenses_aggregator'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
require 'packwerk'
|
4
|
+
require 'packs/private/packwerk_wrapper/offenses_aggregator_formatter'
|
5
|
+
|
6
|
+
module Packs
|
7
|
+
module Private
|
8
|
+
module PackwerkWrapper
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
#
|
12
|
+
# execute_command is like `run` except it does not `exit`
|
13
|
+
#
|
14
|
+
sig { params(argv: T.untyped, formatter: T.nilable(Packwerk::OffensesFormatter)).void }
|
15
|
+
def self.packwerk_cli_execute_safely(argv, formatter = nil)
|
16
|
+
with_safe_exit_if_no_files_found do
|
17
|
+
packwerk_cli(formatter).execute_command(argv)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
sig { params(block: T.proc.returns(T.untyped)).void }
|
22
|
+
def self.with_safe_exit_if_no_files_found(&block)
|
23
|
+
block.call
|
24
|
+
rescue SystemExit => e
|
25
|
+
# Packwerk should probably exit positively here rather than raising an error -- there should be no
|
26
|
+
# errors if the user has excluded all files being checked.
|
27
|
+
unless e.message == 'No files found or given. Specify files or check the include and exclude glob in the config file.'
|
28
|
+
raise
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
sig { params(formatter: T.nilable(Packwerk::OffensesFormatter)).returns(Packwerk::Cli) }
|
33
|
+
def self.packwerk_cli(formatter)
|
34
|
+
# This is mostly copied from exe/packwerk within the packwerk gem, but we use our own formatters
|
35
|
+
# Note that packwerk does not allow you to pass in your own progress formatter currently
|
36
|
+
ENV['RAILS_ENV'] = 'test'
|
37
|
+
|
38
|
+
style = Packwerk::OutputStyles::Coloured.new
|
39
|
+
Packwerk::Cli.new(style: style, offenses_formatter: formatter)
|
40
|
+
end
|
41
|
+
|
42
|
+
sig { params(files: T::Array[String]).returns(T::Array[Packwerk::ReferenceOffense]) }
|
43
|
+
def self.get_offenses_for_files(files)
|
44
|
+
formatter = OffensesAggregatorFormatter.new
|
45
|
+
packwerk_cli_execute_safely(['check', *files], formatter)
|
46
|
+
formatter.aggregated_offenses.compact
|
47
|
+
end
|
48
|
+
|
49
|
+
sig { void }
|
50
|
+
def self.validate!
|
51
|
+
formatter = OffensesAggregatorFormatter.new
|
52
|
+
packwerk_cli_execute_safely(['validate'], formatter)
|
53
|
+
end
|
54
|
+
|
55
|
+
sig { params(files: T::Array[String]).returns(T::Array[Packwerk::ReferenceOffense]) }
|
56
|
+
def self.get_offenses_for_files_by_package(files)
|
57
|
+
packages = package_names_for_files(files)
|
58
|
+
argv = ['check', '--packages', packages.join(',')]
|
59
|
+
formatter = OffensesAggregatorFormatter.new
|
60
|
+
packwerk_cli_execute_safely(argv, formatter)
|
61
|
+
formatter.aggregated_offenses.compact
|
62
|
+
end
|
63
|
+
|
64
|
+
sig { params(files: T::Array[String]).returns(T::Array[String]) }
|
65
|
+
def self.package_names_for_files(files)
|
66
|
+
files.map { |f| ParsePackwerk.package_from_path(f).name }.compact.uniq
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|