use_packs 0.0.1
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.
- 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
|