use_packwerk 0.55.0 → 0.56.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b5e32955dbb7051402503ee3aad2d5358deeb9261f9e54b2bc86f330cb6ec4c
4
- data.tar.gz: 4089b2018b9cc9321e50895b47682583e6a09d6ec95b07bf57e8fe74a41c4cca
3
+ metadata.gz: 6f2315b30561bd988826f08430f4bcecade3056549d1c78069dcbd72cd8aa90b
4
+ data.tar.gz: 2d8cb765865b07158ffb0dd6e7e30765e66e93912b49ccb63ede8e0e6116b41c
5
5
  SHA512:
6
- metadata.gz: 020a051dd86236ea68eaa469a49393ac4cd11432a110912f716ab12b2a6e048c859fa4ba45eb9e3f989bd135fa6c7b0d294b3eb003711a2c9c6c326004b3518a
7
- data.tar.gz: 3556b96d07434dd28e511fb639250cf71bd1129b3ecabcb63403438c0aa55b1f94dcf18891862092deb2d36bba5d3a965f790f8abfa088a4126f368d8869dd13
6
+ metadata.gz: 03d1a533f3323bad78ddef6843a3bcf996cb6390f71feeafdc7844baed5af13ee18ebe558b98c5e4fea89240f0f7645732ca90d73a555e78630758e90d04424a
7
+ data.tar.gz: 1cada76edf9ec7c76b343946c8c6373d1eaeb665312b226a7a2fecc2facca855c42a0b18d08f847722663f16799aca20383da82ef0f866bc962260652183d373
@@ -6,13 +6,13 @@ module UsePackwerk
6
6
  class CLI < Thor
7
7
  extend T::Sig
8
8
 
9
- desc "create packs/your_pack", "Create pack with name packs/your_pack"
9
+ desc 'create packs/your_pack', 'Create pack with name packs/your_pack'
10
10
  sig { params(pack_name: String).void }
11
11
  def create(pack_name)
12
12
  UsePackwerk.create_pack!(pack_name: pack_name)
13
13
  end
14
14
 
15
- desc "add_dependency packs/from_pack packs/to_pack", "Add packs/to_pack to packs/from_pack/package.yml list of dependencies"
15
+ desc 'add_dependency packs/from_pack packs/to_pack', 'Add packs/to_pack to packs/from_pack/package.yml list of dependencies'
16
16
  long_desc <<~LONG_DESC
17
17
  Use this to add a dependency between packs.
18
18
 
@@ -29,7 +29,7 @@ module UsePackwerk
29
29
  )
30
30
  end
31
31
 
32
- desc "list_top_dependency_violations packs/your_pack", "List the top dependency violations of packs/your_pack"
32
+ desc 'list_top_dependency_violations packs/your_pack', 'List the top dependency violations of packs/your_pack'
33
33
  option :limit, type: :numeric, default: 10, aliases: :l, banner: 'Specify the limit of constants to analyze'
34
34
  sig { params(pack_name: String).void }
35
35
  def list_top_dependency_violations(pack_name)
@@ -39,7 +39,7 @@ module UsePackwerk
39
39
  )
40
40
  end
41
41
 
42
- desc "list_top_privacy_violations packs/your_pack", "List the top privacy violations of packs/your_pack"
42
+ desc 'list_top_privacy_violations packs/your_pack', 'List the top privacy violations of packs/your_pack'
43
43
  option :limit, type: :numeric, default: 10, aliases: :l, banner: 'Specify the limit of constants to analyze'
44
44
  sig { params(pack_name: String).void }
45
45
  def list_top_privacy_violations(pack_name)
@@ -49,32 +49,32 @@ module UsePackwerk
49
49
  )
50
50
  end
51
51
 
52
- desc "make_public path/to/file.rb path/to/directory", "Pass in a space-separated list of file or directory paths to make public"
52
+ desc 'make_public path/to/file.rb path/to/directory', 'Pass in a space-separated list of file or directory paths to make public'
53
53
  sig { params(paths: String).void }
54
54
  def make_public(*paths)
55
55
  UsePackwerk.make_public!(
56
56
  paths_relative_to_root: paths,
57
- per_file_processors: [UsePackwerk::RubocopPostProcessor.new, UsePackwerk::CodeOwnershipPostProcessor.new],
57
+ per_file_processors: [UsePackwerk::RubocopPostProcessor.new, UsePackwerk::CodeOwnershipPostProcessor.new]
58
58
  )
59
59
  end
60
60
 
61
- desc "move packs/destination_pack path/to/file.rb path/to/directory", "Pass in a destination pack and a space-separated list of file or directory paths to move to the destination pack"
61
+ desc 'move packs/destination_pack path/to/file.rb path/to/directory', 'Pass in a destination pack and a space-separated list of file or directory paths to move to the destination pack'
62
62
  sig { params(pack_name: String, paths: String).void }
63
63
  def move(pack_name, *paths)
64
64
  UsePackwerk.move_to_pack!(
65
65
  pack_name: pack_name,
66
66
  paths_relative_to_root: paths,
67
- per_file_processors: [UsePackwerk::RubocopPostProcessor.new, UsePackwerk::CodeOwnershipPostProcessor.new],
67
+ per_file_processors: [UsePackwerk::RubocopPostProcessor.new, UsePackwerk::CodeOwnershipPostProcessor.new]
68
68
  )
69
69
  end
70
70
 
71
- desc "move_to_parent packs/parent_pack packs/child_pack", "Pass in a parent pack and another pack to be made as a child to the parent pack!"
71
+ desc 'move_to_parent packs/parent_pack packs/child_pack', 'Pass in a parent pack and another pack to be made as a child to the parent pack!'
72
72
  sig { params(parent_name: String, pack_name: String).void }
73
73
  def move_to_parent(parent_name, pack_name)
74
74
  UsePackwerk.move_to_parent!(
75
75
  parent_name: parent_name,
76
76
  pack_name: pack_name,
77
- per_file_processors: [UsePackwerk::RubocopPostProcessor.new, UsePackwerk::CodeOwnershipPostProcessor.new],
77
+ per_file_processors: [UsePackwerk::RubocopPostProcessor.new, UsePackwerk::CodeOwnershipPostProcessor.new]
78
78
  )
79
79
  end
80
80
  end
@@ -22,7 +22,7 @@ module UsePackwerk
22
22
  UsePackwerk.replace_in_file(
23
23
  file: code_owners_allow_list_file.to_s,
24
24
  find: relative_path_to_origin,
25
- replace_with: relative_path_to_destination,
25
+ replace_with: relative_path_to_destination
26
26
  )
27
27
  end
28
28
 
@@ -45,11 +45,11 @@ module UsePackwerk
45
45
  if @teams.any?
46
46
  Logging.section('Code Ownership') do
47
47
  Logging.print('This section contains info about the current ownership distribution of the moved files.')
48
- @teams.group_by { |team| team }.sort_by { |team, instances| -instances.count }.each do |team, instances|
48
+ @teams.group_by { |team| team }.sort_by { |_team, instances| -instances.count }.each do |team, instances|
49
49
  Logging.print " #{team} - #{instances.count} files"
50
50
  end
51
51
  if @did_move_files
52
- Logging.print "Since the destination package has package-based ownership, file-annotations were removed from moved files."
52
+ Logging.print 'Since the destination package has package-based ownership, file-annotations were removed from moved files.'
53
53
  end
54
54
  end
55
55
  end
@@ -1,5 +1,8 @@
1
1
  # typed: strict
2
2
 
3
+ require 'use_packwerk/user_event_logger'
4
+ require 'use_packwerk/default_user_event_logger'
5
+
3
6
  module UsePackwerk
4
7
  class Configuration
5
8
  extend T::Sig
@@ -7,28 +10,28 @@ module UsePackwerk
7
10
  sig { params(enforce_dependencies: T::Boolean).void }
8
11
  attr_writer :enforce_dependencies
9
12
 
10
- sig { params(documentation_link: String).void }
11
- attr_writer :documentation_link
13
+ sig { returns(UserEventLogger) }
14
+ attr_accessor :user_event_logger
12
15
 
13
16
  sig { void }
14
17
  def initialize
15
- @enforce_dependencies = T.let(@enforce_dependencies, T.nilable(T::Boolean))
16
- @documentation_link = T.let(documentation_link, T.nilable(String) )
18
+ @enforce_dependencies = T.let(default_enforce_dependencies, T::Boolean)
19
+ @user_event_logger = T.let(DefaultUserEventLogger.new, UserEventLogger)
17
20
  end
18
21
 
19
22
  sig { returns(T::Boolean) }
20
23
  def enforce_dependencies
21
- if !@enforce_dependencies.nil?
22
- @enforce_dependencies
23
- else
24
- true
25
- end
24
+ @enforce_dependencies
26
25
  end
27
26
 
28
- # Configure a link to show up for users who are looking for more info
29
- sig { returns(String) }
30
- def documentation_link
31
- "https://go/packwerk"
27
+ sig { void }
28
+ def bust_cache!
29
+ @enforce_dependencies = default_enforce_dependencies
30
+ end
31
+
32
+ sig { returns(T::Boolean) }
33
+ def default_enforce_dependencies
34
+ true
32
35
  end
33
36
  end
34
37
 
@@ -37,12 +40,13 @@ module UsePackwerk
37
40
 
38
41
  sig { returns(Configuration) }
39
42
  def config
43
+ Private.load_client_configuration
40
44
  @config = T.let(@config, T.nilable(Configuration))
41
45
  @config ||= Configuration.new
42
46
  end
43
47
 
44
48
  sig { params(blk: T.proc.params(arg0: Configuration).void).void }
45
- def configure(&blk) # rubocop:disable Lint/UnusedMethodArgument
49
+ def configure(&blk)
46
50
  yield(config)
47
51
  end
48
52
  end
@@ -0,0 +1,7 @@
1
+ # typed: strict
2
+
3
+ module UsePackwerk
4
+ class DefaultUserEventLogger
5
+ include UserEventLogger
6
+ end
7
+ end
@@ -9,7 +9,7 @@ module UsePackwerk
9
9
  sig { params(title: String, block: T.proc.void).void }
10
10
  def self.section(title, &block)
11
11
  print_divider
12
- out ColorizedString.new("#{title}").green.bold
12
+ out ColorizedString.new(title).green.bold
13
13
  out "\n"
14
14
  yield
15
15
  end
@@ -35,4 +35,3 @@ module UsePackwerk
35
35
  end
36
36
  end
37
37
  end
38
-
@@ -8,8 +8,7 @@ module UsePackwerk
8
8
  abstract!
9
9
 
10
10
  sig { abstract.params(file_move_operation: Private::FileMoveOperation).void }
11
- def before_move_file!(file_move_operation)
12
- end
11
+ def before_move_file!(file_move_operation); end
13
12
 
14
13
  sig { void }
15
14
  def print_final_message!
@@ -18,7 +18,6 @@ module UsePackwerk
18
18
  def self.destination_pathname_for_package_move(origin_pathname, new_package_root)
19
19
  origin_pack = T.must(ParsePackwerk.package_from_path(origin_pathname))
20
20
 
21
- new_implementation = nil
22
21
  if origin_pack.name == ParsePackwerk::ROOT_PACKAGE_NAME
23
22
  new_package_root.join(origin_pathname).cleanpath
24
23
  else
@@ -28,7 +27,6 @@ module UsePackwerk
28
27
 
29
28
  sig { params(origin_pathname: Pathname).returns(Pathname) }
30
29
  def self.destination_pathname_for_new_public_api(origin_pathname)
31
-
32
30
  origin_pack = T.must(ParsePackwerk.package_from_path(origin_pathname))
33
31
  if origin_pack.name == ParsePackwerk::ROOT_PACKAGE_NAME
34
32
  filepath_without_pack_name = origin_pathname.to_s
@@ -37,15 +35,15 @@ module UsePackwerk
37
35
  end
38
36
 
39
37
  # We join the pack name with the rest of the path...
40
- path_parts = filepath_without_pack_name.split("/")
38
+ path_parts = filepath_without_pack_name.split('/')
41
39
  Pathname.new(origin_pack.name).join(
42
40
  # ... keeping the "app" or "spec"
43
41
  T.must(path_parts[0]),
44
42
  # ... substituting "controllers," "services," etc. with "public"
45
43
  'public',
46
44
  # ... then the rest is the same
47
- T.must(path_parts[2..]).join("/")
48
- # and we take the cleanpath so `./app/...` becomes `app/...`
45
+ T.must(path_parts[2..]).join('/')
46
+ # and we take the cleanpath so `./app/...` becomes `app/...`
49
47
  ).cleanpath
50
48
  end
51
49
 
@@ -54,16 +52,16 @@ module UsePackwerk
54
52
  # This could probably be implemented by some "strategy pattern" where different extension types are handled by different helpers
55
53
  # Such a thing could also include, for example, when moving a controller, moving its ERB view too.
56
54
  if origin_pathname.extname == '.rake'
57
- new_origin_pathname = origin_pathname.sub('/lib/', '/spec/lib/').sub(/^lib\//, 'spec/lib/').sub('.rake', '_spec.rb')
58
- new_destination_pathname = destination_pathname.sub('/lib/', '/spec/lib/').sub(/^lib\//, 'spec/lib/').sub('.rake', '_spec.rb')
55
+ new_origin_pathname = origin_pathname.sub('/lib/', '/spec/lib/').sub(%r{^lib/}, 'spec/lib/').sub('.rake', '_spec.rb')
56
+ new_destination_pathname = destination_pathname.sub('/lib/', '/spec/lib/').sub(%r{^lib/}, 'spec/lib/').sub('.rake', '_spec.rb')
59
57
  else
60
- new_origin_pathname = origin_pathname.sub('/app/', '/spec/').sub(/^app\//, 'spec/').sub('.rb', '_spec.rb')
61
- new_destination_pathname = destination_pathname.sub('/app/', '/spec/').sub(/^app\//, 'spec/').sub('.rb', '_spec.rb')
58
+ new_origin_pathname = origin_pathname.sub('/app/', '/spec/').sub(%r{^app/}, 'spec/').sub('.rb', '_spec.rb')
59
+ new_destination_pathname = destination_pathname.sub('/app/', '/spec/').sub(%r{^app/}, 'spec/').sub('.rb', '_spec.rb')
62
60
  end
63
61
  FileMoveOperation.new(
64
62
  origin_pathname: new_origin_pathname,
65
63
  destination_pathname: new_destination_pathname,
66
- destination_pack: destination_pack,
64
+ destination_pack: destination_pack
67
65
  )
68
66
  end
69
67
 
@@ -74,7 +72,7 @@ module UsePackwerk
74
72
  FileMoveOperation.new(
75
73
  origin_pathname: origin_pathname.relative_path_from(path),
76
74
  destination_pathname: destination_pathname.relative_path_from(path),
77
- destination_pack: destination_pack,
75
+ destination_pack: destination_pack
78
76
  )
79
77
  end
80
78
  end
@@ -8,72 +8,28 @@ module UsePackwerk
8
8
  sig do
9
9
  params(
10
10
  pack_name: T.nilable(String),
11
- limit: Integer,
11
+ limit: Integer
12
12
  ).void
13
13
  end
14
14
  def self.list_top_privacy_violations(pack_name, limit)
15
15
  all_packages = ParsePackwerk.all
16
- if !pack_name.nil?
16
+ if pack_name.nil?
17
+ to_package_names = all_packages.map(&:name)
18
+ else
17
19
  pack_name = Private.clean_pack_name(pack_name)
18
- package = all_packages.find { |package| package.name == pack_name }
20
+ package = all_packages.find { |p| p.name == pack_name }
19
21
  if package.nil?
20
- raise StandardError.new("Can not find package with name #{pack_name}. Make sure the argument is of the form `packs/my_pack/`")
22
+ raise StandardError, "Can not find package with name #{pack_name}. Make sure the argument is of the form `packs/my_pack/`"
21
23
  end
22
24
 
23
- pack_specific_content = <<~PACK_CONTENT
24
- You are listing top #{limit} privacy violations for #{pack_name}. See #{UsePackwerk.config.documentation_link} for other utilities!
25
- Pass in a limit to display more or less, e.g. `bin/use_packwerk list_top_privacy_violations #{pack_name} -l 1000`
26
-
27
- This script is intended to help you find which of YOUR pack's private classes, constants, or modules other packs are using the most.
28
- Anything not in #{pack_name}/app/public is considered private API.
29
- PACK_CONTENT
30
-
31
25
  to_package_names = [pack_name]
32
- else
33
- pack_specific_content = <<~PACK_CONTENT
34
- You are listing top #{limit} privacy violations for all packs. See #{UsePackwerk.config.documentation_link} for other utilities!
35
- Pass in a limit to display more or less, e.g. `bin/use_packwerk list_top_privacy_violations #{pack_name} -l 1000`
36
-
37
- This script is intended to help you find which of YOUR pack's private classes, constants, or modules other packs are using the most.
38
- Anything not in pack_name/app/public is considered private API.
39
- PACK_CONTENT
40
-
41
- to_package_names = all_packages.map(&:name)
42
26
  end
43
27
 
44
28
  violations_by_count = {}
45
29
  total_pack_violation_count = 0
46
30
 
47
31
  Logging.section('👋 Hi there') do
48
- intro = <<~INTRO
49
- #{pack_specific_content}
50
-
51
- When using this script, ask yourself some questions like:
52
- - What do I want to support?
53
- - What do I *not* want to support?
54
- - What is considered simply an implementation detail, and what is essential to the behavior of my pack?
55
- - What is a simple, minimialistic API for clients to engage with the behavior of your pack?
56
- - How do I ensure my public API is not coupled to specific client's use cases?
57
-
58
- Looking at privacy violations can help guide the development of your public API, but it is just the beginning!
59
-
60
- The script will output in the following format:
61
-
62
- SomeConstant # This is the name of a class, constant, or module defined in your pack, outside of app/public
63
- - Total Count: 5 # This is the total number of uses of this outside your pack
64
- - By package: # This is a breakdown of the use of this constant by other packages
65
- # This is the number of files in this pack that this constant is used.
66
- # Check `packs/other_pack_a/deprecated_references.yml` under the '#{pack_name}'.'SomeConstant' key to see where this constant is used
67
- - packs/other_pack_a: 3
68
- - packs/other_pack_b: 2
69
- SomeClass # This is the second most violated class, constant, or module defined in your pack
70
- - Total Count: 2
71
- - By package:
72
- - packs/other_pack_a: 1
73
- - packs/other_pack_b: 1
74
-
75
- Lastly, remember you can use `bin/use_packwerk make_public #{pack_name}/path/to/file.rb` to make your class, constant, or module public API.
76
- INTRO
32
+ intro = UsePackwerk.config.user_event_logger.before_list_top_privacy_violations(pack_name, limit)
77
33
  Logging.print_bold_green(intro)
78
34
  end
79
35
 
@@ -81,10 +37,11 @@ module UsePackwerk
81
37
  all_packages.each do |client_package|
82
38
  PackageProtections::ProtectedPackage.from(client_package).violations.select(&:privacy?).each do |violation|
83
39
  next unless to_package_names.include?(violation.to_package_name)
40
+
84
41
  if pack_name.nil?
85
42
  violated_symbol = "#{violation.class_name} (#{violation.to_package_name})"
86
43
  else
87
- violated_symbol = "#{violation.class_name}"
44
+ violated_symbol = violation.class_name
88
45
  end
89
46
  violations_by_count[violated_symbol] ||= {}
90
47
  violations_by_count[violated_symbol][:total_count] ||= 0
@@ -104,8 +61,8 @@ module UsePackwerk
104
61
  Logging.print(violated_symbol)
105
62
  Logging.print(" - Total Count: #{count_info[:total_count]} (#{percentage_of_total}% of total)")
106
63
 
107
- Logging.print(" - By package:")
108
- count_info[:by_package].sort_by{ |client_package_name, count| [-count, client_package_name] }.each do |client_package_name, count|
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|
109
66
  Logging.print(" - #{client_package_name}: #{count}")
110
67
  end
111
68
  end
@@ -120,76 +77,35 @@ module UsePackwerk
120
77
  def self.list_top_dependency_violations(pack_name, limit)
121
78
  all_packages = ParsePackwerk.all
122
79
 
123
- if !pack_name.nil?
80
+ if pack_name.nil?
81
+ to_package_names = all_packages.map(&:name)
82
+ else
124
83
  pack_name = Private.clean_pack_name(pack_name)
125
- package = all_packages.find { |package| package.name == pack_name }
84
+ package = all_packages.find { |p| p.name == pack_name }
126
85
  if package.nil?
127
- raise StandardError.new("Can not find package with name #{pack_name}. Make sure the argument is of the form `packs/my_pack/`")
86
+ raise StandardError, "Can not find package with name #{pack_name}. Make sure the argument is of the form `packs/my_pack/`"
128
87
  end
129
88
 
130
- pack_specific_content = <<~PACK_CONTENT
131
- You are listing top #{limit} dependency violations for #{pack_name}. See #{UsePackwerk.config.documentation_link} for other utilities!
132
- Pass in a limit to display more or less, e.g. `bin/use_packwerk list_top_dependency_violations #{pack_name} -l 1000`
133
-
134
- This script is intended to help you find which of YOUR pack's private classes, constants, or modules other packs are using the most.
135
- Anything not in #{pack_name}/app/public is considered private API.
136
- PACK_CONTENT
137
-
138
89
  to_package_names = [pack_name]
139
- else
140
- pack_specific_content = <<~PACK_CONTENT
141
- You are listing top #{limit} dependency violations for all packs. See #{UsePackwerk.config.documentation_link} for other utilities!
142
- Pass in a limit to display more or less, e.g. `use_packwerk list_top_dependency_violations #{pack_name} -l 1000`
143
-
144
- This script is intended to help you find which of YOUR pack's private classes, constants, or modules other packs are using the most.
145
- Anything not in pack_name/app/public is considered private API.
146
- PACK_CONTENT
147
-
148
- to_package_names = all_packages.map(&:name)
149
90
  end
150
91
 
151
- violations_by_count = {}
152
- total_pack_violation_count = 0
153
-
154
92
  Logging.section('👋 Hi there') do
155
- intro = <<~INTRO
156
- #{pack_specific_content}
157
-
158
- When using this script, ask yourself some questions like:
159
- - What do I want to support?
160
- - What do I *not* want to support?
161
- - Which direction should a dependency go?
162
- - What packs should depend on you, and what packs should not depend on you?
163
- - Would it be simpler if other packs only depended on interfaces to your pack rather than implementation?
164
-
165
- Looking at dependency violations can help guide the development of your public API, but it is just the beginning!
166
-
167
- The script will output in the following format:
168
-
169
- SomeConstant # This is the name of a class, constant, or module defined in your pack, outside of app/public
170
- - Total Count: 5 # This is the total number of unstated uses of this outside your pack
171
- - By package: # This is a breakdown of the use of this constant by other packages
172
- # This is the number of files in this pack that this constant is used.
173
- # Check `packs/other_pack_a/deprecated_references.yml` under the '#{pack_name}'.'SomeConstant' key to see where this constant is used
174
- - packs/other_pack_a: 3
175
- - packs/other_pack_b: 2
176
- SomeClass # This is the second most violated class, constant, or module defined in your pack
177
- - Total Count: 2
178
- - By package:
179
- - packs/other_pack_a: 1
180
- - packs/other_pack_b: 1
181
- INTRO
93
+ intro = UsePackwerk.config.user_event_logger.before_list_top_dependency_violations(pack_name, limit)
182
94
  Logging.print_bold_green(intro)
183
95
  end
184
96
 
97
+ violations_by_count = {}
98
+ total_pack_violation_count = 0
99
+
185
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.
186
101
  all_packages.each do |client_package|
187
102
  PackageProtections::ProtectedPackage.from(client_package).violations.select(&:dependency?).each do |violation|
188
103
  next unless to_package_names.include?(violation.to_package_name)
104
+
189
105
  if pack_name.nil?
190
106
  violated_symbol = "#{violation.class_name} (#{violation.to_package_name})"
191
107
  else
192
- violated_symbol = "#{violation.class_name}"
108
+ violated_symbol = violation.class_name
193
109
  end
194
110
  violations_by_count[violated_symbol] ||= {}
195
111
  violations_by_count[violated_symbol][:total_count] ||= 0
@@ -208,8 +124,8 @@ module UsePackwerk
208
124
  percentage_of_total = (count_info[:total_count] * 100.0 / total_pack_violation_count).round(2)
209
125
  Logging.print(violated_symbol)
210
126
  Logging.print(" - Total Count: #{count_info[:total_count]} (#{percentage_of_total}% of total)")
211
- Logging.print(" - By package:")
212
- count_info[:by_package].sort_by{ |client_package_name, count| [-count, client_package_name] }.each do |client_package_name, count|
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|
213
129
  Logging.print(" - #{client_package_name}: #{count}")
214
130
  end
215
131
  end