use_packs 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +71 -0
- data/bin/packs +10 -0
- data/bin/rubocop +29 -0
- data/bin/tapioca +29 -0
- data/lib/use_packs/cli.rb +127 -0
- data/lib/use_packs/code_ownership_post_processor.rb +58 -0
- data/lib/use_packs/configuration.rb +61 -0
- data/lib/use_packs/default_user_event_logger.rb +7 -0
- data/lib/use_packs/logging.rb +37 -0
- data/lib/use_packs/per_file_processor_interface.rb +18 -0
- data/lib/use_packs/private/file_move_operation.rb +80 -0
- data/lib/use_packs/private/interactive_cli/pack_selector.rb +34 -0
- data/lib/use_packs/private/interactive_cli/team_selector.rb +35 -0
- data/lib/use_packs/private/interactive_cli/use_cases/add_dependency.rb +30 -0
- data/lib/use_packs/private/interactive_cli/use_cases/check.rb +25 -0
- data/lib/use_packs/private/interactive_cli/use_cases/create.rb +27 -0
- data/lib/use_packs/private/interactive_cli/use_cases/get_info.rb +74 -0
- data/lib/use_packs/private/interactive_cli/use_cases/interface.rb +34 -0
- data/lib/use_packs/private/interactive_cli/use_cases/lint_package_yml.rb +26 -0
- data/lib/use_packs/private/interactive_cli/use_cases/make_public.rb +34 -0
- data/lib/use_packs/private/interactive_cli/use_cases/move.rb +36 -0
- data/lib/use_packs/private/interactive_cli/use_cases/nest.rb +31 -0
- data/lib/use_packs/private/interactive_cli/use_cases/query.rb +51 -0
- data/lib/use_packs/private/interactive_cli/use_cases/regenerate_rubocop_todo.rb +26 -0
- data/lib/use_packs/private/interactive_cli/use_cases/rename.rb +34 -0
- data/lib/use_packs/private/interactive_cli/use_cases/update_deprecations.rb +25 -0
- data/lib/use_packs/private/interactive_cli/use_cases/validate.rb +25 -0
- data/lib/use_packs/private/interactive_cli/use_cases/visualize.rb +44 -0
- data/lib/use_packs/private/interactive_cli.rb +52 -0
- data/lib/use_packs/private/pack_relationship_analyzer.rb +135 -0
- data/lib/use_packs/private/packwerk_wrapper/offenses_aggregator_formatter.rb +34 -0
- data/lib/use_packs/private/packwerk_wrapper.rb +71 -0
- data/lib/use_packs/private.rb +453 -0
- data/lib/use_packs/rubocop_post_processor.rb +67 -0
- data/lib/use_packs/spring_command.rb +28 -0
- data/lib/use_packs/user_event_logger.rb +259 -0
- data/lib/use_packs.rb +298 -0
- metadata +351 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module UsePacks
|
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
|
+
UsePacks.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 UsePacks
|
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 UsePacks
|
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,26 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module UsePacks
|
4
|
+
module Private
|
5
|
+
module InteractiveCli
|
6
|
+
module UseCases
|
7
|
+
class LintPackageYml
|
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
|
+
packs = PackSelector.single_or_all_pack_multi_select(prompt, question_text: 'Please select the packs you want to lint package.yml files for')
|
15
|
+
UsePacks.lint_package_yml_files!(packs)
|
16
|
+
end
|
17
|
+
|
18
|
+
sig { override.returns(String) }
|
19
|
+
def user_facing_name
|
20
|
+
'Lint packs/*/package.yml for one or more packs'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module UsePacks
|
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
|
+
UsePacks.make_public!(
|
26
|
+
paths_relative_to_root: paths_relative_to_root,
|
27
|
+
per_file_processors: [UsePacks::RubocopPostProcessor.new, UsePacks::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 UsePacks
|
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
|
+
UsePacks.move_to_pack!(
|
22
|
+
pack_name: pack.name,
|
23
|
+
paths_relative_to_root: paths_relative_to_root,
|
24
|
+
per_file_processors: [UsePacks::RubocopPostProcessor.new, UsePacks::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 UsePacks
|
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
|
+
UsePacks.move_to_parent!(
|
17
|
+
parent_name: parent_pack.name,
|
18
|
+
pack_name: child_pack.name,
|
19
|
+
per_file_processors: [UsePacks::RubocopPostProcessor.new, UsePacks::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
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module UsePacks
|
4
|
+
module Private
|
5
|
+
module InteractiveCli
|
6
|
+
module UseCases
|
7
|
+
#
|
8
|
+
# We have not yet pulled QueryPackwerk into open source, so we cannot include it in this CLI yet
|
9
|
+
#
|
10
|
+
class Query
|
11
|
+
extend T::Sig
|
12
|
+
extend T::Helpers
|
13
|
+
include Interface
|
14
|
+
|
15
|
+
sig { override.returns(String) }
|
16
|
+
def user_facing_name
|
17
|
+
'Query violations about a pack'
|
18
|
+
end
|
19
|
+
|
20
|
+
sig { override.params(prompt: TTY::Prompt).void }
|
21
|
+
def perform!(prompt)
|
22
|
+
selection = prompt.select('For one pack or all packs?', ['One pack', 'All packs'])
|
23
|
+
if selection == 'All packs'
|
24
|
+
# Probably should just make `list_top_dependency_violations` take in an array of things
|
25
|
+
# Better yet we might just want to replace these functions with `QueryPackwerk`
|
26
|
+
selected_pack = nil
|
27
|
+
else
|
28
|
+
selected_pack = PackSelector.single_pack_select(prompt).name
|
29
|
+
end
|
30
|
+
|
31
|
+
limit = prompt.ask('Specify the limit of constants to analyze', default: 10, convert: :integer)
|
32
|
+
|
33
|
+
selection = prompt.select('Are you interested in dependency or privacy violations?', %w[Dependency Privacy], default: 'Privacy')
|
34
|
+
|
35
|
+
if selection == 'Dependency'
|
36
|
+
UsePacks.list_top_dependency_violations(
|
37
|
+
pack_name: selected_pack,
|
38
|
+
limit: limit
|
39
|
+
)
|
40
|
+
else
|
41
|
+
UsePacks.list_top_privacy_violations(
|
42
|
+
pack_name: selected_pack,
|
43
|
+
limit: limit
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module UsePacks
|
4
|
+
module Private
|
5
|
+
module InteractiveCli
|
6
|
+
module UseCases
|
7
|
+
class RegenerateRubocopTodo
|
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
|
+
packs = PackSelector.single_or_all_pack_multi_select(prompt, question_text: "Please select the packs you want to regenerate `#{RuboCop::Packs::PACK_LEVEL_RUBOCOP_TODO_YML}` for")
|
15
|
+
RuboCop::Packs.regenerate_todo(packs: packs)
|
16
|
+
end
|
17
|
+
|
18
|
+
sig { override.returns(String) }
|
19
|
+
def user_facing_name
|
20
|
+
"Regenerate packs/*/#{RuboCop::Packs::PACK_LEVEL_RUBOCOP_TODO_YML} for one or more packs"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module UsePacks
|
4
|
+
module Private
|
5
|
+
module InteractiveCli
|
6
|
+
module UseCases
|
7
|
+
class Rename
|
8
|
+
extend T::Sig
|
9
|
+
extend T::Helpers
|
10
|
+
include Interface
|
11
|
+
|
12
|
+
sig { override.returns(String) }
|
13
|
+
def user_facing_name
|
14
|
+
'Rename a pack'
|
15
|
+
end
|
16
|
+
|
17
|
+
sig { override.params(prompt: TTY::Prompt).void }
|
18
|
+
def perform!(prompt)
|
19
|
+
prompt.warn(<<~WARNING)
|
20
|
+
We do not yet have an automated API for this.
|
21
|
+
|
22
|
+
Follow these steps:
|
23
|
+
1. Rename the `packs/your_pack` directory to the name of the new pack, `packs/new_pack_name
|
24
|
+
2. Replace references to `- packs/your_pack` in `package.yml` files with `- packs/new_pack_name`
|
25
|
+
3. Rerun `bin/packwerk update-deprecations` to update violations
|
26
|
+
4. Run `bin/codeownership validate` to update ownership information
|
27
|
+
5. Please let us know if anything is missing.
|
28
|
+
WARNING
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module UsePacks
|
4
|
+
module Private
|
5
|
+
module InteractiveCli
|
6
|
+
module UseCases
|
7
|
+
class UpdateDeprecations
|
8
|
+
extend T::Sig
|
9
|
+
extend T::Helpers
|
10
|
+
include Interface
|
11
|
+
|
12
|
+
sig { override.returns(String) }
|
13
|
+
def user_facing_name
|
14
|
+
'Run bin/packwerk update-deprecations'
|
15
|
+
end
|
16
|
+
|
17
|
+
sig { override.params(prompt: TTY::Prompt).void }
|
18
|
+
def perform!(prompt)
|
19
|
+
system('bin/packwerk update-deprecations')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module UsePacks
|
4
|
+
module Private
|
5
|
+
module InteractiveCli
|
6
|
+
module UseCases
|
7
|
+
class Validate
|
8
|
+
extend T::Sig
|
9
|
+
extend T::Helpers
|
10
|
+
include Interface
|
11
|
+
|
12
|
+
sig { override.returns(String) }
|
13
|
+
def user_facing_name
|
14
|
+
'Run bin/packwerk validate (detects cycles)'
|
15
|
+
end
|
16
|
+
|
17
|
+
sig { override.params(prompt: TTY::Prompt).void }
|
18
|
+
def perform!(prompt)
|
19
|
+
system('bin/packwerk validate')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
require 'visualize_packwerk'
|
4
|
+
|
5
|
+
module UsePacks
|
6
|
+
module Private
|
7
|
+
module InteractiveCli
|
8
|
+
module UseCases
|
9
|
+
class Visualize
|
10
|
+
extend T::Sig
|
11
|
+
extend T::Helpers
|
12
|
+
include Interface
|
13
|
+
|
14
|
+
sig { override.params(prompt: TTY::Prompt).void }
|
15
|
+
def perform!(prompt)
|
16
|
+
teams_or_packs = prompt.select('Do you want the graph nodes to be teams or packs?', %w[Teams Packs])
|
17
|
+
|
18
|
+
if teams_or_packs == 'Teams'
|
19
|
+
teams = TeamSelector.multi_select(prompt)
|
20
|
+
VisualizePackwerk.team_graph!(teams)
|
21
|
+
else
|
22
|
+
by_name_or_by_owner = prompt.select('Do you select packs by name or by owner?', ['By name', 'By owner'])
|
23
|
+
if by_name_or_by_owner == 'By owner'
|
24
|
+
teams = TeamSelector.multi_select(prompt)
|
25
|
+
selected_packs = ParsePackwerk.all.select do |p|
|
26
|
+
teams.map(&:name).include?(CodeOwnership.for_package(p)&.name)
|
27
|
+
end
|
28
|
+
else
|
29
|
+
selected_packs = PackSelector.single_or_all_pack_multi_select(prompt)
|
30
|
+
end
|
31
|
+
|
32
|
+
VisualizePackwerk.package_graph!(selected_packs)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { override.returns(String) }
|
37
|
+
def user_facing_name
|
38
|
+
'Visualize pack relationships'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
# https://github.com/piotrmurach/tty-prompt
|
4
|
+
require 'tty-prompt'
|
5
|
+
|
6
|
+
require 'use_packs/private/interactive_cli/team_selector'
|
7
|
+
require 'use_packs/private/interactive_cli/pack_selector'
|
8
|
+
require 'use_packs/private/interactive_cli/use_cases/interface'
|
9
|
+
require 'use_packs/private/interactive_cli/use_cases/create'
|
10
|
+
require 'use_packs/private/interactive_cli/use_cases/move'
|
11
|
+
require 'use_packs/private/interactive_cli/use_cases/add_dependency'
|
12
|
+
require 'use_packs/private/interactive_cli/use_cases/get_info'
|
13
|
+
require 'use_packs/private/interactive_cli/use_cases/query'
|
14
|
+
require 'use_packs/private/interactive_cli/use_cases/make_public'
|
15
|
+
require 'use_packs/private/interactive_cli/use_cases/nest'
|
16
|
+
require 'use_packs/private/interactive_cli/use_cases/rename'
|
17
|
+
require 'use_packs/private/interactive_cli/use_cases/check'
|
18
|
+
require 'use_packs/private/interactive_cli/use_cases/update_deprecations'
|
19
|
+
require 'use_packs/private/interactive_cli/use_cases/validate'
|
20
|
+
require 'use_packs/private/interactive_cli/use_cases/regenerate_rubocop_todo'
|
21
|
+
require 'use_packs/private/interactive_cli/use_cases/lint_package_yml'
|
22
|
+
require 'use_packs/private/interactive_cli/use_cases/visualize'
|
23
|
+
|
24
|
+
module UsePacks
|
25
|
+
module Private
|
26
|
+
module InteractiveCli
|
27
|
+
extend T::Sig
|
28
|
+
|
29
|
+
sig { params(prompt: T.nilable(TTY::Prompt)).void }
|
30
|
+
def self.start!(prompt: nil)
|
31
|
+
prompt ||= TTY::Prompt.new(interrupt: lambda {
|
32
|
+
puts "\n\nGoodbye! I hope you have a good day."
|
33
|
+
exit 1 })
|
34
|
+
help_text = '(Press ↑/↓ arrow to move, Enter to select and letters to filter)'
|
35
|
+
choice = prompt.select('Hello! What would you like to do?',
|
36
|
+
cycle: true,
|
37
|
+
filter: true,
|
38
|
+
help: help_text,
|
39
|
+
show_help: :always,
|
40
|
+
per_page: 15) do |menu|
|
41
|
+
menu.enum '.'
|
42
|
+
|
43
|
+
UseCases::Interface.all.each do |use_case|
|
44
|
+
menu.choice use_case.user_facing_name, use_case
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
choice.perform!(prompt)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module UsePacks
|
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 = UsePacks.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 = UsePacks.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
|