use_packwerk 0.55.0 → 0.57.0

Sign up to get free protection for your applications and to get access to all the features.
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