packs 0.0.6 → 0.0.23

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +120 -4
  3. data/bin/packs +10 -0
  4. data/bin/rubocop +29 -0
  5. data/bin/tapioca +29 -0
  6. data/lib/packs/cli.rb +164 -0
  7. data/lib/packs/code_ownership_post_processor.rb +58 -0
  8. data/lib/packs/configuration.rb +61 -0
  9. data/lib/packs/default_user_event_logger.rb +7 -0
  10. data/lib/packs/logging.rb +37 -0
  11. data/lib/packs/per_file_processor_interface.rb +18 -0
  12. data/lib/packs/private/file_move_operation.rb +80 -0
  13. data/lib/packs/private/interactive_cli/file_selector.rb +26 -0
  14. data/lib/packs/private/interactive_cli/pack_selector.rb +55 -0
  15. data/lib/packs/private/interactive_cli/team_selector.rb +58 -0
  16. data/lib/packs/private/interactive_cli/use_cases/add_dependency.rb +30 -0
  17. data/lib/packs/private/interactive_cli/use_cases/check.rb +25 -0
  18. data/lib/packs/private/interactive_cli/use_cases/create.rb +27 -0
  19. data/lib/packs/private/interactive_cli/use_cases/get_info.rb +37 -0
  20. data/lib/packs/private/interactive_cli/use_cases/interface.rb +34 -0
  21. data/lib/packs/private/interactive_cli/use_cases/lint_package_todo_yml_files.rb +25 -0
  22. data/lib/packs/private/interactive_cli/use_cases/lint_package_yml_files.rb +26 -0
  23. data/lib/packs/private/interactive_cli/use_cases/make_public.rb +30 -0
  24. data/lib/packs/private/interactive_cli/use_cases/move.rb +32 -0
  25. data/lib/packs/private/interactive_cli/use_cases/move_to_parent.rb +31 -0
  26. data/lib/packs/private/interactive_cli/use_cases/query.rb +51 -0
  27. data/lib/packs/private/interactive_cli/use_cases/rename.rb +25 -0
  28. data/lib/packs/private/interactive_cli/use_cases/update.rb +25 -0
  29. data/lib/packs/private/interactive_cli/use_cases/validate.rb +25 -0
  30. data/lib/packs/private/interactive_cli/use_cases/visualize.rb +44 -0
  31. data/lib/packs/private/interactive_cli.rb +52 -0
  32. data/lib/packs/private/pack_relationship_analyzer.rb +135 -0
  33. data/lib/packs/private/packwerk_wrapper/offenses_aggregator_formatter.rb +44 -0
  34. data/lib/packs/private/packwerk_wrapper.rb +70 -0
  35. data/lib/packs/private.rb +606 -4
  36. data/lib/packs/rubocop_post_processor.rb +30 -0
  37. data/lib/packs/user_event_logger.rb +199 -0
  38. data/lib/packs.rb +233 -53
  39. metadata +225 -14
  40. data/lib/packs/pack.rb +0 -48
  41. data/lib/packs/private/configuration.rb +0 -36
  42. data/lib/packs/rspec/fixture_helper.rb +0 -33
  43. 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