Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Experimental] Interactive CLI #24

Merged
merged 3 commits into from
Oct 13, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,6 @@ Style/AccessorGrouping:

Style/NumericPredicate:
Enabled: false

Layout/BlockEndNewline:
Enabled: false
25 changes: 23 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
PATH
remote: .
specs:
use_packwerk (0.56.0)
use_packwerk (0.57.0)
code_ownership
colorize
package_protections
parse_packwerk
sorbet-runtime
thor
tty-prompt

GEM
remote: https://rubygems.org/
Expand All @@ -34,17 +35,20 @@ GEM
json (2.6.2)
method_source (1.0.0)
minitest (5.16.3)
package_protections (2.2.1)
package_protections (2.5.1)
activesupport
parse_packwerk
rubocop
rubocop-packs
rubocop-sorbet
sorbet-runtime
parallel (1.22.1)
parse_packwerk (0.12.1)
sorbet-runtime
parser (3.1.2.0)
ast (~> 2.4.1)
pastel (0.8.0)
tty-color (~> 0.5)
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
Expand Down Expand Up @@ -85,6 +89,12 @@ GEM
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.21.0)
parser (>= 3.1.1.0)
rubocop-packs (0.0.10)
activesupport
parse_packwerk
rubocop
rubocop-sorbet
sorbet-runtime
rubocop-rspec (2.13.2)
rubocop (~> 1.33)
rubocop-sorbet (0.6.11)
Expand Down Expand Up @@ -116,13 +126,24 @@ GEM
thor (>= 1.2.0)
yard-sorbet
thor (1.2.1)
tty-color (0.6.0)
tty-cursor (0.7.1)
tty-prompt (0.23.1)
pastel (~> 0.8)
tty-reader (~> 0.8)
tty-reader (0.9.0)
tty-cursor (~> 0.7)
tty-screen (~> 0.8)
wisper (~> 2.0)
tty-screen (0.8.1)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
unicode-display_width (2.2.0)
unparser (0.6.5)
diff-lcs (~> 1.3)
parser (>= 3.1.0)
webrick (1.7.0)
wisper (2.0.1)
yard (0.9.27)
webrick (~> 1.7.0)
yard-sorbet (0.6.1)
Expand Down
5 changes: 5 additions & 0 deletions bin/packs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env ruby
# typed: strict

require_relative '../lib/use_packwerk'
UsePackwerk.start_interactive_mode!
14 changes: 11 additions & 3 deletions lib/use_packwerk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,30 @@ module UsePackwerk
packs
], T::Array[String])

sig { void }
def self.start_interactive_mode!
Private::InteractiveCli.start!
end

sig do
params(
pack_name: String,
enforce_privacy: T::Boolean,
enforce_dependencies: T.nilable(T::Boolean)
enforce_dependencies: T.nilable(T::Boolean),
team: T.nilable(CodeTeams::Team)
).void
end
def self.create_pack!(
pack_name:,
enforce_privacy: true,
enforce_dependencies: nil
enforce_dependencies: nil,
team: nil
)
Private.create_pack!(
pack_name: pack_name,
enforce_privacy: enforce_privacy,
enforce_dependencies: enforce_dependencies
enforce_dependencies: enforce_dependencies,
team: team
)
end

Expand Down
15 changes: 9 additions & 6 deletions lib/use_packwerk/private.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

require 'use_packwerk/private/file_move_operation'
require 'use_packwerk/private/pack_relationship_analyzer'
require 'use_packwerk/private/interactive_cli'

module UsePackwerk
module Private
Expand Down Expand Up @@ -44,18 +45,19 @@ def self.replace_in_file(file:, find:, replace_with:)
params(
pack_name: String,
enforce_privacy: T::Boolean,
enforce_dependencies: T.nilable(T::Boolean)
enforce_dependencies: T.nilable(T::Boolean),
team: T.nilable(CodeTeams::Team)
).void
end
def self.create_pack!(pack_name:, enforce_privacy:, enforce_dependencies:)
def self.create_pack!(pack_name:, enforce_privacy:, enforce_dependencies:, team:)
Logging.section('👋 Hi!') do
intro = UsePackwerk.config.user_event_logger.before_create_pack(pack_name)
Logging.print_bold_green(intro)
end

pack_name = Private.clean_pack_name(pack_name)

package = create_pack_if_not_exists!(pack_name: pack_name, enforce_privacy: enforce_privacy, enforce_dependencies: enforce_dependencies)
package = create_pack_if_not_exists!(pack_name: pack_name, enforce_privacy: enforce_privacy, enforce_dependencies: enforce_dependencies, team: team)
add_public_directory(package)
add_readme_todo(package)

Expand Down Expand Up @@ -334,10 +336,11 @@ def self.add_readme_todo(package)
params(
pack_name: String,
enforce_privacy: T::Boolean,
enforce_dependencies: T.nilable(T::Boolean)
enforce_dependencies: T.nilable(T::Boolean),
team: T.nilable(CodeTeams::Team)
).returns(ParsePackwerk::Package)
end
def self.create_pack_if_not_exists!(pack_name:, enforce_privacy:, enforce_dependencies:)
def self.create_pack_if_not_exists!(pack_name:, enforce_privacy:, enforce_dependencies:, team: nil)
if PERMITTED_PACK_LOCATIONS.none? { |permitted_location| pack_name.start_with?(permitted_location) }
raise StandardError, "UsePackwerk only supports packages in the the following directories: #{PERMITTED_PACK_LOCATIONS.inspect}. Please make sure to pass in the name of the pack including the full directory path, e.g. `packs/my_pack`."
end
Expand All @@ -351,7 +354,7 @@ def self.create_pack_if_not_exists!(pack_name:, enforce_privacy:, enforce_depend
enforce_privacy: enforce_privacy,
dependencies: [],
metadata: {
'owner' => 'MyTeam'
'owner' => team.nil? ? 'MyTeam' : team.name
},
name: pack_name
)
Expand Down
48 changes: 48 additions & 0 deletions lib/use_packwerk/private/interactive_cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# typed: strict

# https://github.com/piotrmurach/tty-prompt
require 'tty-prompt'

require 'use_packwerk/private/interactive_cli/team_selector'
require 'use_packwerk/private/interactive_cli/pack_selector'
require 'use_packwerk/private/interactive_cli/use_cases/interface'
require 'use_packwerk/private/interactive_cli/use_cases/create'
require 'use_packwerk/private/interactive_cli/use_cases/move'
require 'use_packwerk/private/interactive_cli/use_cases/add_dependency'
require 'use_packwerk/private/interactive_cli/use_cases/get_info'
require 'use_packwerk/private/interactive_cli/use_cases/query'
require 'use_packwerk/private/interactive_cli/use_cases/make_public'
require 'use_packwerk/private/interactive_cli/use_cases/nest'
require 'use_packwerk/private/interactive_cli/use_cases/rename'
require 'use_packwerk/private/interactive_cli/use_cases/update_deprecations'
require 'use_packwerk/private/interactive_cli/use_cases/validate'

module UsePackwerk
module Private
module InteractiveCli
extend T::Sig

sig { void }
def self.start!
prompt = TTY::Prompt.new(interrupt: lambda {
puts "\n\nGoodbye! I hope you have a good day."
exit 1 })
help_text = '(Press ↑/↓ arrow to move, Enter to select and letters to filter)'
choice = prompt.select('Hello! What would you like to do?',
cycle: true,
filter: true,
help: help_text,
show_help: :always,
per_page: 15) do |menu|
menu.enum '.'

UseCases::Interface.all.each do |use_case|
menu.choice use_case.user_facing_name, use_case
end
end

choice.perform!(prompt)
end
end
end
end
34 changes: 34 additions & 0 deletions lib/use_packwerk/private/interactive_cli/pack_selector.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# typed: strict

module UsePackwerk
module Private
module InteractiveCli
class PackSelector
extend T::Sig

sig { params(prompt: TTY::Prompt, question_text: String).returns(ParsePackwerk::Package) }
def self.single_pack_select(prompt, question_text: 'Please select a pack')
packs = ParsePackwerk.all.to_h { |t| [t.name, t] }
prompt.select(
question_text,
packs,
filter: true,
per_page: 10,
show_help: :always
)
end

sig { params(prompt: TTY::Prompt, question_text: String).returns(T::Array[ParsePackwerk::Package]) }
def self.single_or_all_pack_multi_select(prompt, question_text: 'Please select one or more packs')
prompt.multi_select(
question_text,
ParsePackwerk.all.to_h { |t| [t.name, t] },
filter: true,
per_page: 10,
show_help: :always
)
end
end
end
end
end
35 changes: 35 additions & 0 deletions lib/use_packwerk/private/interactive_cli/team_selector.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# typed: strict

module UsePackwerk
module Private
module InteractiveCli
class TeamSelector
extend T::Sig

sig { params(prompt: TTY::Prompt, question_text: String).returns(CodeTeams::Team) }
def self.single_select(prompt, question_text: 'Please select a team owner')
teams = CodeTeams.all.to_h { |t| [t.name, t] }
prompt.select(
question_text,
teams,
filter: true,
per_page: 10,
show_help: :always
)
end

sig { params(prompt: TTY::Prompt, question_text: String).returns(T::Array[CodeTeams::Team]) }
def self.multi_select(prompt, question_text: 'Please select team owners')
teams = CodeTeams.all.to_h { |t| [t.name, t] }
prompt.multi_select(
question_text,
teams,
filter: true,
per_page: 10,
show_help: :always
)
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# typed: strict

module UsePackwerk
module Private
module InteractiveCli
module UseCases
class AddDependency
extend T::Sig
extend T::Helpers
include Interface

sig { override.params(prompt: TTY::Prompt).void }
def perform!(prompt)
dependent_pack = PackSelector.single_pack_select(prompt, question_text: 'Please select the pack you are adding a dependency to.')
dependency_pack = PackSelector.single_pack_select(prompt, question_text: "Please select the pack that #{dependent_pack.name} should depend on.")
UsePackwerk.add_dependency!(
pack_name: dependent_pack.name,
dependency_name: dependency_pack.name
)
end

sig { override.returns(String) }
def user_facing_name
'Add a dependency'
end
end
end
end
end
end
27 changes: 27 additions & 0 deletions lib/use_packwerk/private/interactive_cli/use_cases/create.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# typed: strict

module UsePackwerk
module Private
module InteractiveCli
module UseCases
class Create
extend T::Sig
extend T::Helpers
include Interface

sig { override.params(prompt: TTY::Prompt).void }
def perform!(prompt)
pack_name = prompt.ask('What should the name of your pack be?', value: 'packs/')
team = TeamSelector.single_select(prompt)
UsePackwerk.create_pack!(pack_name: pack_name, team: team)
end

sig { override.returns(String) }
def user_facing_name
'Create a new pack'
end
end
end
end
end
end
Loading