hanami-cli 0.2.0 → 2.0.0.alpha2

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +42 -0
  3. data/.gitignore +4 -2
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +25 -1
  6. data/CHANGELOG.md +39 -1
  7. data/CODE_OF_CONDUCT.md +84 -0
  8. data/Gemfile +13 -6
  9. data/LICENSE.txt +21 -0
  10. data/README.md +13 -488
  11. data/Rakefile +8 -15
  12. data/bin/console +1 -0
  13. data/exe/hanami +10 -0
  14. data/hanami-cli.gemspec +24 -18
  15. data/lib/hanami/cli.rb +10 -121
  16. data/lib/hanami/cli/bundler.rb +73 -0
  17. data/lib/hanami/cli/command.rb +16 -355
  18. data/lib/hanami/cli/command_line.rb +17 -0
  19. data/lib/hanami/cli/commands.rb +26 -0
  20. data/lib/hanami/cli/commands/application.rb +63 -0
  21. data/lib/hanami/cli/commands/db/utils/database.rb +122 -0
  22. data/lib/hanami/cli/commands/db/utils/database_config.rb +48 -0
  23. data/lib/hanami/cli/commands/db/utils/mysql.rb +27 -0
  24. data/lib/hanami/cli/commands/db/utils/postgres.rb +49 -0
  25. data/lib/hanami/cli/commands/db/utils/sqlite.rb +37 -0
  26. data/lib/hanami/cli/commands/gem.rb +21 -0
  27. data/lib/hanami/cli/commands/gem/new.rb +77 -0
  28. data/lib/hanami/cli/commands/gem/version.rb +18 -0
  29. data/lib/hanami/cli/commands/monolith.rb +55 -0
  30. data/lib/hanami/cli/commands/monolith/console.rb +50 -0
  31. data/lib/hanami/cli/commands/monolith/db/create.rb +25 -0
  32. data/lib/hanami/cli/commands/monolith/db/create_migration.rb +29 -0
  33. data/lib/hanami/cli/commands/monolith/db/drop.rb +25 -0
  34. data/lib/hanami/cli/commands/monolith/db/migrate.rb +40 -0
  35. data/lib/hanami/cli/commands/monolith/db/reset.rb +26 -0
  36. data/lib/hanami/cli/commands/monolith/db/rollback.rb +55 -0
  37. data/lib/hanami/cli/commands/monolith/db/sample_data.rb +40 -0
  38. data/lib/hanami/cli/commands/monolith/db/seed.rb +40 -0
  39. data/lib/hanami/cli/commands/monolith/db/setup.rb +24 -0
  40. data/lib/hanami/cli/commands/monolith/db/structure/dump.rb +25 -0
  41. data/lib/hanami/cli/commands/monolith/db/version.rb +26 -0
  42. data/lib/hanami/cli/commands/monolith/generate.rb +14 -0
  43. data/lib/hanami/cli/commands/monolith/generate/action.rb +62 -0
  44. data/lib/hanami/cli/commands/monolith/generate/slice.rb +62 -0
  45. data/lib/hanami/cli/commands/monolith/install.rb +16 -0
  46. data/lib/hanami/cli/commands/monolith/version.rb +18 -0
  47. data/lib/hanami/cli/error.rb +8 -0
  48. data/lib/hanami/cli/generators/context.rb +38 -0
  49. data/lib/hanami/cli/generators/gem/application.rb +21 -0
  50. data/lib/hanami/cli/generators/gem/application/monolith.rb +83 -0
  51. data/lib/hanami/cli/generators/gem/application/monolith/action.erb +21 -0
  52. data/lib/hanami/cli/generators/gem/application/monolith/application.erb +8 -0
  53. data/lib/hanami/cli/generators/gem/application/monolith/config_ru.erb +5 -0
  54. data/lib/hanami/cli/generators/gem/application/monolith/entities.erb +9 -0
  55. data/lib/hanami/cli/generators/gem/application/monolith/env.erb +0 -0
  56. data/lib/hanami/cli/generators/gem/application/monolith/functions.erb +13 -0
  57. data/lib/hanami/cli/generators/gem/application/monolith/gemfile.erb +19 -0
  58. data/lib/hanami/cli/generators/gem/application/monolith/keep.erb +0 -0
  59. data/lib/hanami/cli/generators/gem/application/monolith/operation.erb +18 -0
  60. data/lib/hanami/cli/generators/gem/application/monolith/rakefile.erb +3 -0
  61. data/lib/hanami/cli/generators/gem/application/monolith/readme.erb +1 -0
  62. data/lib/hanami/cli/generators/gem/application/monolith/repository.erb +13 -0
  63. data/lib/hanami/cli/generators/gem/application/monolith/routes.erb +4 -0
  64. data/lib/hanami/cli/generators/gem/application/monolith/settings.erb +6 -0
  65. data/lib/hanami/cli/generators/gem/application/monolith/types.erb +10 -0
  66. data/lib/hanami/cli/generators/gem/application/monolith/validation_contract.erb +14 -0
  67. data/lib/hanami/cli/generators/gem/application/monolith/view_context.erb +15 -0
  68. data/lib/hanami/cli/generators/monolith/action.rb +123 -0
  69. data/lib/hanami/cli/generators/monolith/action/action.erb +13 -0
  70. data/lib/hanami/cli/generators/monolith/action/template.erb +0 -0
  71. data/lib/hanami/cli/generators/monolith/action/template.html.erb +2 -0
  72. data/lib/hanami/cli/generators/monolith/action/view.erb +13 -0
  73. data/lib/hanami/cli/generators/monolith/action_context.rb +76 -0
  74. data/lib/hanami/cli/generators/monolith/slice.rb +56 -0
  75. data/lib/hanami/cli/generators/monolith/slice/action.erb +9 -0
  76. data/lib/hanami/cli/generators/monolith/slice/entities.erb +9 -0
  77. data/lib/hanami/cli/generators/monolith/slice/keep.erb +0 -0
  78. data/lib/hanami/cli/generators/monolith/slice/repository.erb +10 -0
  79. data/lib/hanami/cli/generators/monolith/slice/routes.erb +2 -0
  80. data/lib/hanami/cli/generators/monolith/slice/view.erb +9 -0
  81. data/lib/hanami/cli/generators/monolith/slice_context.rb +33 -0
  82. data/lib/hanami/cli/repl/core.rb +55 -0
  83. data/lib/hanami/cli/repl/irb.rb +41 -0
  84. data/lib/hanami/cli/repl/pry.rb +29 -0
  85. data/lib/hanami/cli/system_call.rb +51 -0
  86. data/lib/hanami/cli/url.rb +34 -0
  87. data/lib/hanami/cli/version.rb +4 -3
  88. data/lib/hanami/console/context.rb +39 -0
  89. data/lib/hanami/console/plugins/slice_readers.rb +42 -0
  90. data/lib/hanami/rake_tasks.rb +52 -0
  91. metadata +138 -41
  92. data/.travis.yml +0 -16
  93. data/lib/hanami/cli/banner.rb +0 -126
  94. data/lib/hanami/cli/command_registry.rb +0 -213
  95. data/lib/hanami/cli/errors.rb +0 -32
  96. data/lib/hanami/cli/option.rb +0 -125
  97. data/lib/hanami/cli/parser.rb +0 -122
  98. data/lib/hanami/cli/program_name.rb +0 -19
  99. data/lib/hanami/cli/registry.rb +0 -328
  100. data/lib/hanami/cli/usage.rb +0 -88
  101. data/script/ci +0 -51
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./bundler"
4
+
5
+ module Hanami
6
+ module CLI
7
+ class CommandLine
8
+ def initialize(bundler: CLI::Bundler.new)
9
+ @bundler = bundler
10
+ end
11
+
12
+ def call(command)
13
+ @bundler.exec(command)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ # TODO: move elsewhere
5
+ def self.architecture
6
+ return :monolith if File.exist?("config/application.rb")
7
+ end
8
+
9
+ module CLI
10
+ module Commands
11
+ end
12
+
13
+ def self.register_commands!(architecture = Hanami.architecture)
14
+ commands = case architecture
15
+ when :monolith
16
+ require_relative "commands/monolith"
17
+ Commands::Monolith
18
+ else
19
+ require_relative "commands/gem"
20
+ Commands::Gem
21
+ end
22
+
23
+ extend(commands)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/files"
4
+
5
+ require_relative "db/utils/database"
6
+
7
+ module Hanami
8
+ module CLI
9
+ module Commands
10
+ class Application < Hanami::CLI::Command
11
+ module Environment
12
+ def call(**opts)
13
+ env = opts[:env]
14
+ ENV["HANAMI_ENV"] = env.to_s
15
+ super(**opts)
16
+ end
17
+ end
18
+
19
+ def self.inherited(klass)
20
+ super
21
+ klass.option(:env, required: false, default: "development", desc: "Application's environment")
22
+ klass.prepend(Environment)
23
+ end
24
+
25
+ def application
26
+ @application ||=
27
+ begin
28
+ require "hanami/init"
29
+ Hanami.application
30
+ end
31
+ end
32
+
33
+ def run_command(klass, *args)
34
+ klass.new(
35
+ out: out,
36
+ inflector: application.inflector,
37
+ fs: Dry::Files
38
+ ).call(*args)
39
+ end
40
+
41
+ def measure(desc)
42
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
43
+ result = yield
44
+ stop = Process.clock_gettime(Process::CLOCK_MONOTONIC)
45
+
46
+ if result
47
+ out.puts "=> #{desc} in #{(stop - start).round(4)}s"
48
+ else
49
+ out.puts "!!! => #{desc.inspect} FAILED"
50
+ end
51
+ end
52
+
53
+ def database
54
+ @database ||= Commands::DB::Utils::Database[application]
55
+ end
56
+
57
+ def database_config
58
+ database.config
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "database_config"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Commands
8
+ module DB
9
+ module Utils
10
+ class Database
11
+ attr_reader :application, :config
12
+
13
+ SCHEME_MAP = {
14
+ "sqlite" => -> {
15
+ require_relative("sqlite")
16
+ Sqlite
17
+ },
18
+ "postgres" => -> {
19
+ require_relative("postgres")
20
+ Postgres
21
+ },
22
+ "mysql" => -> {
23
+ require_relative("mysql")
24
+ Mysql
25
+ }
26
+ }.freeze
27
+
28
+ def self.[](application)
29
+ config = DatabaseConfig.new(application.settings.database_url)
30
+
31
+ resolver = SCHEME_MAP.fetch(config.db_type) do
32
+ raise "#{config.db_type} is not a supported db scheme"
33
+ end
34
+
35
+ klass = resolver.()
36
+
37
+ klass.new(application: application, config: config)
38
+ end
39
+
40
+ def initialize(application:, config:)
41
+ @application = application
42
+ @config = config
43
+ end
44
+
45
+ def create_command
46
+ raise NotImplementedError
47
+ end
48
+
49
+ def drop_command
50
+ raise NotImplementedError
51
+ end
52
+
53
+ def dump_command
54
+ raise NotImplementedError
55
+ end
56
+
57
+ def load_command
58
+ raise NotImplementedError
59
+ end
60
+
61
+ def root_path
62
+ application.root
63
+ end
64
+
65
+ def rom_config
66
+ @rom_config ||=
67
+ begin
68
+ application.init_bootable(:persistence)
69
+ application.container["persistence.config"]
70
+ end
71
+ end
72
+
73
+ def name
74
+ config.db_name
75
+ end
76
+
77
+ def applied_migrations
78
+ sequel_migrator.applied_migrations
79
+ end
80
+
81
+ def gateway
82
+ rom_config.gateways[:default]
83
+ end
84
+
85
+ def connection
86
+ gateway.connection
87
+ end
88
+
89
+ def run_migrations(**options)
90
+ require "rom/sql"
91
+ ROM::SQL.with_gateway(gateway) do
92
+ migrator.run(options)
93
+ end
94
+ end
95
+
96
+ def migrator
97
+ @migrator ||=
98
+ begin
99
+ require "rom/sql"
100
+ ROM::SQL::Migration::Migrator.new(connection, path: File.join(root_path, "db/migrate"))
101
+ end
102
+ end
103
+
104
+ def applied_migrations
105
+ sequel_migrator.applied_migrations
106
+ end
107
+
108
+ private
109
+
110
+ def sequel_migrator
111
+ Sequel::TimestampMigrator.new(migrator.connection, migrations_path, {})
112
+ end
113
+
114
+ def migrations_path
115
+ File.join(root_path, "db/migrate")
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Commands
8
+ module DB
9
+ module Utils
10
+ class DatabaseConfig
11
+ attr_reader :uri
12
+
13
+ def initialize(database_url)
14
+ @uri = URI(database_url)
15
+ end
16
+
17
+ def hostname
18
+ uri.hostname
19
+ end
20
+ alias_method :host, :hostname
21
+
22
+ def user
23
+ uri.user
24
+ end
25
+ alias_method :username, :user
26
+
27
+ def password
28
+ uri.password
29
+ end
30
+ alias_method :pass, :password
31
+
32
+ def port
33
+ uri.port
34
+ end
35
+
36
+ def db_name
37
+ @db_name ||= uri.path.gsub(/\A\//, "")
38
+ end
39
+
40
+ def db_type
41
+ uri.scheme
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "database"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Commands
8
+ module DB
9
+ module Utils
10
+ class Mysql < Database
11
+ def create_command
12
+ raise "Not Implemented Yet"
13
+ end
14
+
15
+ def dump_command
16
+ raise "Not Implemented Yet"
17
+ end
18
+
19
+ def load_command
20
+ raise "Not Implemented Yet"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "shellwords"
4
+ require_relative "database"
5
+
6
+ module Hanami
7
+ module CLI
8
+ module Commands
9
+ module DB
10
+ module Utils
11
+ class Postgres < Database
12
+ def create_command
13
+ system(cli_env_vars, "createdb #{escaped_name}")
14
+ end
15
+
16
+ def drop_command
17
+ system(cli_env_vars, "dropdb #{escaped_name}")
18
+ end
19
+
20
+ def dump_command
21
+ system(cli_env_vars, "pg_dump --schema-only --no-owner #{escaped_name} > #{dump_file}")
22
+ end
23
+
24
+ def load_command
25
+ raise "Not Implemented Yet"
26
+ end
27
+
28
+ def escaped_name
29
+ Shellwords.escape(name)
30
+ end
31
+
32
+ def cli_env_vars
33
+ @cli_env_vars ||= {}.tap do |vars|
34
+ vars["PGHOST"] = config.host.to_s
35
+ vars["PGPORT"] = config.port.to_s if config.port
36
+ vars["PGUSER"] = config.user.to_s if config.user
37
+ vars["PGPASSWORD"] = config.pass.to_s if config.pass
38
+ end
39
+ end
40
+
41
+ def dump_file
42
+ "#{root_path}/db/structure.sql"
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "database"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Commands
8
+ module DB
9
+ module Utils
10
+ class Sqlite < Database
11
+ def create_command
12
+ rom_config
13
+ true
14
+ end
15
+
16
+ def drop_command
17
+ file_path.unlink
18
+ true
19
+ end
20
+
21
+ def dump_command
22
+ raise "Not Implemented Yet"
23
+ end
24
+
25
+ def load_command
26
+ raise "Not Implemented Yet"
27
+ end
28
+
29
+ def file_path
30
+ @file_path ||= Pathname("#{root_path}#{config.uri.path}").realpath
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module CLI
5
+ module Commands
6
+ module Gem
7
+ require_relative "gem/version"
8
+ # FIXME: temporary disabled for Hanami v2.0.0.alpha2
9
+ # require_relative "gem/new"
10
+
11
+ def self.extended(base)
12
+ base.module_eval do
13
+ register "version", Version, aliases: ["v", "-v", "--version"]
14
+ # FIXME: temporary disabled for Hanami v2.0.0.alpha2
15
+ # register "new", New
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/cli/command"
4
+ require "hanami/cli/bundler"
5
+ require "hanami/cli/command_line"
6
+ require "hanami/cli/generators/gem/application"
7
+ require "dry/files"
8
+
9
+ module Hanami
10
+ module CLI
11
+ module Commands
12
+ module Gem
13
+ class New < Command
14
+ ARCHITECTURES = %w[monolith micro].freeze
15
+ private_constant :ARCHITECTURES
16
+
17
+ DEFAULT_ARCHITECTURE = ARCHITECTURES.first
18
+ private_constant :DEFAULT_ARCHITECTURE
19
+
20
+ DEFAULT_SLICE_NAME = "main"
21
+ private_constant :DEFAULT_SLICE_NAME
22
+
23
+ DEFAULT_SLICE_URL_PREFIX = "/"
24
+ private_constant :DEFAULT_SLICE_URL_PREFIX
25
+
26
+ argument :app, required: true, desc: "The application name"
27
+
28
+ option :architecture, alias: "arch", default: DEFAULT_ARCHITECTURE,
29
+ values: ARCHITECTURES, desc: "The architecture"
30
+
31
+ option :slice, default: DEFAULT_SLICE_NAME, desc: %(The initial slice name, only for "monolith" architecture)
32
+ option :slice_url_prefix, default: DEFAULT_SLICE_URL_PREFIX,
33
+ desc: %(The initial slice URL prefix, only for "monolith" architecture)
34
+
35
+ def initialize(fs: Dry::Files.new, bundler: CLI::Bundler.new(fs: fs),
36
+ command_line: CLI::CommandLine.new(bundler: bundler), **other)
37
+ @bundler = bundler
38
+ @command_line = command_line
39
+ super(fs: fs, **other)
40
+ end
41
+
42
+ def call(app:, architecture: DEFAULT_ARCHITECTURE, slice: DEFAULT_SLICE_NAME,
43
+ slice_url_prefix: DEFAULT_SLICE_URL_PREFIX, **)
44
+ app = inflector.underscore(app)
45
+
46
+ fs.mkdir(app)
47
+ fs.chdir(app) do
48
+ generator(architecture).call(app, slice, slice_url_prefix) do
49
+ bundler.install!
50
+ run_install_commmand!
51
+ end
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ attr_reader :bundler
58
+ attr_reader :command_line
59
+
60
+ def generator(architecture)
61
+ unless ARCHITECTURES.include?(architecture)
62
+ raise ArgumentError.new("unknown architecture `#{architecture}'")
63
+ end
64
+
65
+ Generators::Gem::Application[architecture, fs, inflector, command_line]
66
+ end
67
+
68
+ def run_install_commmand!
69
+ command_line.call("hanami install").tap do |result|
70
+ raise "hanami install failed\n\n\n#{result.err.inspect}" unless result.successful?
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end