use_packwerk 0.55.0 → 0.57.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.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/bin/packs +5 -0
  3. data/lib/use_packwerk/cli.rb +10 -10
  4. data/lib/use_packwerk/code_ownership_post_processor.rb +3 -3
  5. data/lib/use_packwerk/configuration.rb +18 -14
  6. data/lib/use_packwerk/default_user_event_logger.rb +7 -0
  7. data/lib/use_packwerk/logging.rb +1 -2
  8. data/lib/use_packwerk/per_file_processor_interface.rb +1 -2
  9. data/lib/use_packwerk/private/file_move_operation.rb +9 -11
  10. data/lib/use_packwerk/private/interactive_cli/pack_selector.rb +34 -0
  11. data/lib/use_packwerk/private/interactive_cli/team_selector.rb +35 -0
  12. data/lib/use_packwerk/private/interactive_cli/use_cases/add_dependency.rb +30 -0
  13. data/lib/use_packwerk/private/interactive_cli/use_cases/create.rb +27 -0
  14. data/lib/use_packwerk/private/interactive_cli/use_cases/get_info.rb +74 -0
  15. data/lib/use_packwerk/private/interactive_cli/use_cases/interface.rb +34 -0
  16. data/lib/use_packwerk/private/interactive_cli/use_cases/make_public.rb +34 -0
  17. data/lib/use_packwerk/private/interactive_cli/use_cases/move.rb +36 -0
  18. data/lib/use_packwerk/private/interactive_cli/use_cases/nest.rb +31 -0
  19. data/lib/use_packwerk/private/interactive_cli/use_cases/query.rb +51 -0
  20. data/lib/use_packwerk/private/interactive_cli/use_cases/rename.rb +34 -0
  21. data/lib/use_packwerk/private/interactive_cli/use_cases/update_deprecations.rb +25 -0
  22. data/lib/use_packwerk/private/interactive_cli/use_cases/validate.rb +25 -0
  23. data/lib/use_packwerk/private/interactive_cli.rb +48 -0
  24. data/lib/use_packwerk/private/pack_relationship_analyzer.rb +24 -108
  25. data/lib/use_packwerk/private.rb +126 -161
  26. data/lib/use_packwerk/rubocop_post_processor.rb +17 -17
  27. data/lib/use_packwerk/user_event_logger.rb +265 -0
  28. data/lib/use_packwerk.rb +38 -76
  29. metadata +74 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b5e32955dbb7051402503ee3aad2d5358deeb9261f9e54b2bc86f330cb6ec4c
4
- data.tar.gz: 4089b2018b9cc9321e50895b47682583e6a09d6ec95b07bf57e8fe74a41c4cca
3
+ metadata.gz: 2f49d1c83c2428ea899e55eb53afa3ae0744e3257e08461066b098662de34c3d
4
+ data.tar.gz: 43350c95f8a33c1900c80f152eee0c644bc14376e69f2f13f1f9799162ea79f8
5
5
  SHA512:
6
- metadata.gz: 020a051dd86236ea68eaa469a49393ac4cd11432a110912f716ab12b2a6e048c859fa4ba45eb9e3f989bd135fa6c7b0d294b3eb003711a2c9c6c326004b3518a
7
- data.tar.gz: 3556b96d07434dd28e511fb639250cf71bd1129b3ecabcb63403438c0aa55b1f94dcf18891862092deb2d36bba5d3a965f790f8abfa088a4126f368d8869dd13
6
+ metadata.gz: c556f16dc02d9fbdc8a895ba1092abd003d258bfa43e8a89f68c90bd440da99edc446a5ea89bc85aa25b8e4547deb4b2256f7b7ccaca975b7cfcf1e202331c22
7
+ data.tar.gz: 816849ee8b3b65cb2307a4982b12114645f2890d998aee23ce685f78cf4ac41ba304cff44a63cf6f42604d08a59883b4e9fcd05f7f0300c72e1aa4223d14fe27
data/bin/packs ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # typed: strict
3
+
4
+ require_relative '../lib/use_packwerk'
5
+ UsePackwerk.start_interactive_mode!
@@ -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
@@ -0,0 +1,34 @@
1
+ # typed: strict
2
+
3
+ module UsePackwerk
4
+ module Private
5
+ module InteractiveCli
6
+ class PackSelector
7
+ extend T::Sig
8
+
9
+ sig { params(prompt: TTY::Prompt, question_text: String).returns(ParsePackwerk::Package) }
10
+ def self.single_pack_select(prompt, question_text: 'Please select a pack')
11
+ packs = ParsePackwerk.all.to_h { |t| [t.name, t] }
12
+ prompt.select(
13
+ question_text,
14
+ packs,
15
+ filter: true,
16
+ per_page: 10,
17
+ show_help: :always
18
+ )
19
+ end
20
+
21
+ sig { params(prompt: TTY::Prompt, question_text: String).returns(T::Array[ParsePackwerk::Package]) }
22
+ def self.single_or_all_pack_multi_select(prompt, question_text: 'Please select one or more packs')
23
+ prompt.multi_select(
24
+ question_text,
25
+ ParsePackwerk.all.to_h { |t| [t.name, t] },
26
+ filter: true,
27
+ per_page: 10,
28
+ show_help: :always
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ # typed: strict
2
+
3
+ module UsePackwerk
4
+ module Private
5
+ module InteractiveCli
6
+ class TeamSelector
7
+ extend T::Sig
8
+
9
+ sig { params(prompt: TTY::Prompt, question_text: String).returns(CodeTeams::Team) }
10
+ def self.single_select(prompt, question_text: 'Please select a team owner')
11
+ teams = CodeTeams.all.to_h { |t| [t.name, t] }
12
+ prompt.select(
13
+ question_text,
14
+ teams,
15
+ filter: true,
16
+ per_page: 10,
17
+ show_help: :always
18
+ )
19
+ end
20
+
21
+ sig { params(prompt: TTY::Prompt, question_text: String).returns(T::Array[CodeTeams::Team]) }
22
+ def self.multi_select(prompt, question_text: 'Please select team owners')
23
+ teams = CodeTeams.all.to_h { |t| [t.name, t] }
24
+ prompt.multi_select(
25
+ question_text,
26
+ teams,
27
+ filter: true,
28
+ per_page: 10,
29
+ show_help: :always
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ # typed: strict
2
+
3
+ module UsePackwerk
4
+ module Private
5
+ module InteractiveCli
6
+ module UseCases
7
+ class AddDependency
8
+ extend T::Sig
9
+ extend T::Helpers
10
+ include Interface
11
+
12
+ sig { override.params(prompt: TTY::Prompt).void }
13
+ def perform!(prompt)
14
+ dependent_pack = PackSelector.single_pack_select(prompt, question_text: 'Please select the pack you are adding a dependency to.')
15
+ dependency_pack = PackSelector.single_pack_select(prompt, question_text: "Please select the pack that #{dependent_pack.name} should depend on.")
16
+ UsePackwerk.add_dependency!(
17
+ pack_name: dependent_pack.name,
18
+ dependency_name: dependency_pack.name
19
+ )
20
+ end
21
+
22
+ sig { override.returns(String) }
23
+ def user_facing_name
24
+ 'Add a dependency'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ # typed: strict
2
+
3
+ module UsePackwerk
4
+ module Private
5
+ module InteractiveCli
6
+ module UseCases
7
+ class Create
8
+ extend T::Sig
9
+ extend T::Helpers
10
+ include Interface
11
+
12
+ sig { override.params(prompt: TTY::Prompt).void }
13
+ def perform!(prompt)
14
+ pack_name = prompt.ask('What should the name of your pack be?', value: 'packs/')
15
+ team = TeamSelector.single_select(prompt)
16
+ UsePackwerk.create_pack!(pack_name: pack_name, team: team)
17
+ end
18
+
19
+ sig { override.returns(String) }
20
+ def user_facing_name
21
+ 'Create a new pack'
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,74 @@
1
+ # typed: strict
2
+
3
+ module UsePackwerk
4
+ module Private
5
+ module InteractiveCli
6
+ module UseCases
7
+ class GetInfo
8
+ extend T::Sig
9
+ extend T::Helpers
10
+ include Interface
11
+
12
+ sig { override.returns(String) }
13
+ def user_facing_name
14
+ 'Get info on one or more packs'
15
+ end
16
+
17
+ sig { override.params(prompt: TTY::Prompt).void }
18
+ def perform!(prompt)
19
+ team_or_pack = prompt.select('Do you want info by team or by pack?', ['By team', 'By pack'])
20
+
21
+ if team_or_pack == 'By team'
22
+ teams = TeamSelector.multi_select(prompt)
23
+ selected_packs = ParsePackwerk.all.select do |p|
24
+ teams.map(&:name).include?(CodeOwnership.for_package(p)&.name)
25
+ end
26
+ else
27
+ selected_packs = PackSelector.single_or_all_pack_multi_select(prompt, question_text: 'What pack(s) would you like info on?')
28
+ end
29
+
30
+ inbound_violations = {}
31
+ outbound_violations = {}
32
+ ParsePackwerk.all.each do |p|
33
+ violations_for_pack = ParsePackwerk::DeprecatedReferences.for(p).violations
34
+ violations_for_pack.each do |violation|
35
+ outbound_violations[p.name] ||= []
36
+ outbound_violations[p.name] << violation
37
+ inbound_violations[violation.to_package_name] ||= []
38
+ inbound_violations[violation.to_package_name] << violation
39
+ end
40
+ end
41
+
42
+ puts "You've selected #{selected_packs.count} packs. Wow! Here's all the info."
43
+ all_inbound = T.let([], T::Array[ParsePackwerk::Violation])
44
+ all_outbound = T.let([], T::Array[ParsePackwerk::Violation])
45
+ selected_packs.each do |pack|
46
+ all_inbound += inbound_violations[pack.name] || []
47
+ all_outbound += outbound_violations[pack.name] || []
48
+ end
49
+
50
+ puts "There are #{all_inbound.select(&:privacy?).sum { |v| v.files.count }} total inbound privacy violations"
51
+ puts "There are #{all_inbound.select(&:dependency?).sum { |v| v.files.count }} total inbound dependency violations"
52
+ puts "There are #{all_outbound.select(&:privacy?).sum { |v| v.files.count }} total outbound privacy violations"
53
+ puts "There are #{all_outbound.select(&:dependency?).sum { |v| v.files.count }} total outbound dependency violations"
54
+
55
+ selected_packs.sort_by { |p| -p.directory.glob('**/*.rb').count }.each do |pack|
56
+ puts "\n=========== Info about: #{pack.name}"
57
+ owner = CodeOwnership.for_package(pack)
58
+ puts "Owned by: #{owner.nil? ? 'No one' : owner.name}"
59
+ puts "Size: #{pack.directory.glob('**/*.rb').count} ruby files"
60
+ puts "Public API: #{pack.directory.join('app/public')}"
61
+
62
+ inbound_for_pack = inbound_violations[pack.name] || []
63
+ outbound_for_pack = outbound_violations[pack.name] || []
64
+ puts "There are #{inbound_for_pack.select(&:privacy?).sum { |v| v.files.count }} inbound privacy violations"
65
+ puts "There are #{inbound_for_pack.flatten.select(&:dependency?).sum { |v| v.files.count }} inbound dependency violations"
66
+ puts "There are #{outbound_for_pack.select(&:privacy?).sum { |v| v.files.count }} outbound privacy violations"
67
+ puts "There are #{outbound_for_pack.flatten.select(&:dependency?).sum { |v| v.files.count }} outbound dependency violations"
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,34 @@
1
+ # typed: strict
2
+
3
+ module UsePackwerk
4
+ module Private
5
+ module InteractiveCli
6
+ module UseCases
7
+ module Interface
8
+ extend T::Sig
9
+ extend T::Helpers
10
+
11
+ interface!
12
+
13
+ sig { params(base: Class).void }
14
+ def self.included(base)
15
+ @use_cases ||= T.let(@use_cases, T.nilable(T::Array[Class]))
16
+ @use_cases ||= []
17
+ @use_cases << base
18
+ end
19
+
20
+ sig { returns(T::Array[Interface]) }
21
+ def self.all
22
+ T.unsafe(@use_cases).map(&:new)
23
+ end
24
+
25
+ sig { abstract.params(prompt: TTY::Prompt).void }
26
+ def perform!(prompt); end
27
+
28
+ sig { abstract.returns(String) }
29
+ def user_facing_name; end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ # typed: strict
2
+
3
+ module UsePackwerk
4
+ module Private
5
+ module InteractiveCli
6
+ module UseCases
7
+ class MakePublic
8
+ extend T::Sig
9
+ extend T::Helpers
10
+ include Interface
11
+
12
+ sig { override.returns(String) }
13
+ def user_facing_name
14
+ 'Make files or directories public'
15
+ end
16
+
17
+ sig { override.params(prompt: TTY::Prompt).void }
18
+ def perform!(prompt)
19
+ raw_paths_relative_to_root = prompt.multiline('Please copy in a space or new line separated list of files or directories to make public')
20
+ paths_relative_to_root = T.let([], T::Array[String])
21
+ raw_paths_relative_to_root.each do |path|
22
+ paths_relative_to_root += path.chomp.split
23
+ end
24
+
25
+ UsePackwerk.make_public!(
26
+ paths_relative_to_root: paths_relative_to_root,
27
+ per_file_processors: [UsePackwerk::RubocopPostProcessor.new, UsePackwerk::CodeOwnershipPostProcessor.new]
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ # typed: strict
2
+
3
+ module UsePackwerk
4
+ module Private
5
+ module InteractiveCli
6
+ module UseCases
7
+ class Move
8
+ extend T::Sig
9
+ extend T::Helpers
10
+ include Interface
11
+
12
+ sig { override.params(prompt: TTY::Prompt).void }
13
+ def perform!(prompt)
14
+ pack = PackSelector.single_pack_select(prompt, question_text: 'Please select a destination pack')
15
+ raw_paths_relative_to_root = prompt.multiline('Please copy in a space or new line separated list of files or directories')
16
+ paths_relative_to_root = T.let([], T::Array[String])
17
+ raw_paths_relative_to_root.each do |path|
18
+ paths_relative_to_root += path.chomp.split
19
+ end
20
+
21
+ UsePackwerk.move_to_pack!(
22
+ pack_name: pack.name,
23
+ paths_relative_to_root: paths_relative_to_root,
24
+ per_file_processors: [UsePackwerk::RubocopPostProcessor.new, UsePackwerk::CodeOwnershipPostProcessor.new]
25
+ )
26
+ end
27
+
28
+ sig { override.returns(String) }
29
+ def user_facing_name
30
+ 'Move files'
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ # typed: strict
2
+
3
+ module UsePackwerk
4
+ module Private
5
+ module InteractiveCli
6
+ module UseCases
7
+ class Nest
8
+ extend T::Sig
9
+ extend T::Helpers
10
+ include Interface
11
+
12
+ sig { override.params(prompt: TTY::Prompt).void }
13
+ def perform!(prompt)
14
+ child_pack = PackSelector.single_pack_select(prompt, question_text: 'Please select the pack that will be nested')
15
+ parent_pack = PackSelector.single_pack_select(prompt, question_text: 'Please select the pack that will be the parent')
16
+ UsePackwerk.move_to_parent!(
17
+ parent_name: parent_pack.name,
18
+ pack_name: child_pack.name,
19
+ per_file_processors: [UsePackwerk::RubocopPostProcessor.new, UsePackwerk::CodeOwnershipPostProcessor.new]
20
+ )
21
+ end
22
+
23
+ sig { override.returns(String) }
24
+ def user_facing_name
25
+ 'Nest one pack under another'
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end