hanami-cli 2.1.0 → 2.2.0.beta1
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 +4 -4
- data/.github/workflows/ci.yml +18 -13
- data/CHANGELOG.md +21 -0
- data/Gemfile +4 -2
- data/README.md +11 -7
- data/docker-compose.yml +9 -0
- data/hanami-cli.gemspec +2 -2
- data/lib/hanami/cli/command.rb +1 -1
- data/lib/hanami/cli/commands/app/assets/command.rb +1 -1
- data/lib/hanami/cli/commands/app/command.rb +2 -16
- data/lib/hanami/cli/commands/app/db/command.rb +116 -0
- data/lib/hanami/cli/commands/app/db/create.rb +19 -11
- data/lib/hanami/cli/commands/app/db/drop.rb +19 -10
- data/lib/hanami/cli/commands/app/db/migrate.rb +19 -13
- data/lib/hanami/cli/commands/app/db/prepare.rb +42 -0
- data/lib/hanami/cli/commands/app/db/seed.rb +11 -22
- data/lib/hanami/cli/commands/app/db/structure/dump.rb +30 -7
- data/lib/hanami/cli/commands/app/db/structure/load.rb +52 -0
- data/lib/hanami/cli/commands/app/db/utils/database.rb +68 -73
- data/lib/hanami/cli/commands/app/db/utils/mysql.rb +2 -2
- data/lib/hanami/cli/commands/app/db/utils/postgres.rb +38 -19
- data/lib/hanami/cli/commands/app/db/utils/sqlite.rb +58 -10
- data/lib/hanami/cli/commands/app/db/version.rb +12 -9
- data/lib/hanami/cli/commands/app/generate/action.rb +4 -3
- data/lib/hanami/cli/commands/app/generate/command.rb +49 -0
- data/lib/hanami/cli/commands/app/generate/component.rb +49 -0
- data/lib/hanami/cli/commands/app/generate/migration.rb +27 -0
- data/lib/hanami/cli/commands/app/generate/operation.rb +26 -0
- data/lib/hanami/cli/commands/app/generate/part.rb +1 -1
- data/lib/hanami/cli/commands/app/generate/relation.rb +35 -0
- data/lib/hanami/cli/commands/app/generate/repo.rb +46 -0
- data/lib/hanami/cli/commands/app/generate/slice.rb +20 -3
- data/lib/hanami/cli/commands/app/generate/struct.rb +27 -0
- data/lib/hanami/cli/commands/app/install.rb +1 -1
- data/lib/hanami/cli/commands/app/middleware.rb +1 -1
- data/lib/hanami/cli/commands/app/server.rb +2 -2
- data/lib/hanami/cli/commands/app.rb +21 -2
- data/lib/hanami/cli/commands/gem/new.rb +78 -14
- data/lib/hanami/cli/errors.rb +28 -0
- data/lib/hanami/cli/generators/app/action/slice_action.erb +1 -1
- data/lib/hanami/cli/generators/app/action_context.rb +5 -13
- data/lib/hanami/cli/generators/app/component/component.erb +8 -0
- data/lib/hanami/cli/generators/app/component/slice_component.erb +8 -0
- data/lib/hanami/cli/generators/app/component.rb +61 -0
- data/lib/hanami/cli/generators/app/component_context.rb +82 -0
- data/lib/hanami/cli/generators/app/migration.rb +69 -0
- data/lib/hanami/cli/generators/app/operation.rb +48 -0
- data/lib/hanami/cli/generators/app/part_context.rb +5 -21
- data/lib/hanami/cli/generators/app/relation.rb +44 -0
- data/lib/hanami/cli/generators/app/repo.rb +40 -0
- data/lib/hanami/cli/generators/app/ruby_file_writer.rb +149 -0
- data/lib/hanami/cli/generators/app/slice/operation.erb +7 -0
- data/lib/hanami/cli/generators/app/slice/relation.erb +8 -0
- data/lib/hanami/cli/generators/app/slice/{slice.erb → repo.erb} +3 -1
- data/lib/hanami/cli/generators/app/slice/struct.erb +8 -0
- data/lib/hanami/cli/generators/app/slice.rb +14 -6
- data/lib/hanami/cli/generators/app/slice_context.rb +9 -2
- data/lib/hanami/cli/generators/app/struct.rb +39 -0
- data/lib/hanami/cli/generators/app/view_context.rb +4 -16
- data/lib/hanami/cli/generators/constants.rb +39 -0
- data/lib/hanami/cli/generators/context.rb +48 -0
- data/lib/hanami/cli/generators/gem/app/action.erb +3 -0
- data/lib/hanami/cli/generators/gem/app/env.erb +4 -0
- data/lib/hanami/cli/generators/gem/app/gemfile.erb +11 -0
- data/lib/hanami/cli/generators/gem/app/gitignore.erb +1 -1
- data/lib/hanami/cli/generators/gem/app/operation.erb +13 -0
- data/lib/hanami/cli/generators/gem/app/relation.erb +10 -0
- data/lib/hanami/cli/generators/gem/app/repo.erb +10 -0
- data/lib/hanami/cli/generators/gem/app/struct.erb +10 -0
- data/lib/hanami/cli/generators/gem/app.rb +19 -0
- data/lib/hanami/cli/ruby_file_generator.rb +123 -0
- data/lib/hanami/cli/version.rb +1 -1
- metadata +39 -16
- data/lib/hanami/cli/commands/app/db/create_migration.rb +0 -32
- data/lib/hanami/cli/commands/app/db/reset.rb +0 -28
- data/lib/hanami/cli/commands/app/db/rollback.rb +0 -81
- data/lib/hanami/cli/commands/app/db/sample_data.rb +0 -42
- data/lib/hanami/cli/commands/app/db/setup.rb +0 -26
- data/lib/hanami/cli/commands/app/db/utils/database_config.rb +0 -60
- data/lib/hanami/cli/generators/app/slice/repository.erb +0 -10
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module CLI
|
5
|
+
module Commands
|
6
|
+
module App
|
7
|
+
module DB
|
8
|
+
# @api private
|
9
|
+
module Structure
|
10
|
+
# @api private
|
11
|
+
class Load < DB::Command
|
12
|
+
STRUCTURE_PATH = File.join("config", "db", "structure.sql").freeze
|
13
|
+
private_constant :STRUCTURE_PATH
|
14
|
+
|
15
|
+
desc "Loads database from config/db/structure.sql file"
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
def call(app: false, slice: nil, command_exit: method(:exit), **)
|
19
|
+
exit_codes = []
|
20
|
+
|
21
|
+
databases(app: app, slice: slice).each do |database|
|
22
|
+
structure_path = database.slice.root.join(STRUCTURE_PATH)
|
23
|
+
next unless structure_path.exist?
|
24
|
+
|
25
|
+
relative_structure_path = structure_path.relative_path_from(database.slice.app.root)
|
26
|
+
|
27
|
+
measure("#{database.name} structure loaded from #{relative_structure_path}") do
|
28
|
+
catch :load_failed do
|
29
|
+
result = database.exec_load_command
|
30
|
+
exit_codes << result.exit_code if result.respond_to?(:exit_code)
|
31
|
+
|
32
|
+
unless result.successful?
|
33
|
+
out.puts result.err
|
34
|
+
throw :load_failed, false
|
35
|
+
end
|
36
|
+
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
exit_codes.each do |code|
|
43
|
+
break command_exit.(code) if code > 0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "uri"
|
4
4
|
|
5
5
|
module Hanami
|
6
6
|
module CLI
|
@@ -9,15 +9,14 @@ module Hanami
|
|
9
9
|
module DB
|
10
10
|
module Utils
|
11
11
|
# @api private
|
12
|
+
# @since 2.2.0
|
12
13
|
class Database
|
13
|
-
|
14
|
-
|
14
|
+
MIGRATIONS_DIR = "config/db/migrate"
|
15
|
+
private_constant :MIGRATIONS_DIR
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# @api private
|
20
|
-
SCHEME_MAP = {
|
17
|
+
DATABASE_CLASS_RESOLVER = Hash.new { |_, key|
|
18
|
+
raise "#{key} is not a supported db scheme"
|
19
|
+
}.update(
|
21
20
|
"sqlite" => -> {
|
22
21
|
require_relative("sqlite")
|
23
22
|
Sqlite
|
@@ -34,84 +33,66 @@ module Hanami
|
|
34
33
|
require_relative("mysql")
|
35
34
|
Mysql
|
36
35
|
}
|
37
|
-
|
38
|
-
|
39
|
-
# @api private
|
40
|
-
def self.[](app)
|
41
|
-
database_url =
|
42
|
-
if app.key?(:settings) && app[:settings].respond_to?(:database_url)
|
43
|
-
app[:settings].database_url
|
44
|
-
else
|
45
|
-
ENV.fetch("DATABASE_URL")
|
46
|
-
end
|
36
|
+
).freeze
|
47
37
|
|
48
|
-
|
38
|
+
def self.[](slice, system_call:)
|
39
|
+
provider = slice.container.providers[:db]
|
40
|
+
raise "this is not a db slice" unless provider
|
49
41
|
|
50
|
-
|
51
|
-
|
52
|
-
|
42
|
+
database_scheme = provider.source.database_url.then { URI(_1).scheme }
|
43
|
+
database_class = DATABASE_CLASS_RESOLVER[database_scheme].call
|
44
|
+
database_class.new(slice: slice, system_call: system_call)
|
45
|
+
end
|
46
|
+
|
47
|
+
attr_reader :slice
|
53
48
|
|
54
|
-
|
49
|
+
attr_reader :system_call
|
55
50
|
|
56
|
-
|
51
|
+
def initialize(slice:, system_call:)
|
52
|
+
@slice = slice
|
53
|
+
@system_call = system_call
|
57
54
|
end
|
58
55
|
|
59
|
-
|
60
|
-
|
61
|
-
@app = app
|
62
|
-
@config = config
|
56
|
+
def name
|
57
|
+
database_uri.path.sub(%r{^/}, "")
|
63
58
|
end
|
64
59
|
|
65
|
-
|
66
|
-
|
67
|
-
raise Hanami::CLI::NotImplementedError
|
60
|
+
def database_url
|
61
|
+
slice.container.providers[:db].source.database_url
|
68
62
|
end
|
69
63
|
|
70
|
-
|
71
|
-
|
72
|
-
raise Hanami::CLI::NotImplementedError
|
64
|
+
def database_uri
|
65
|
+
@database_uri ||= URI(database_url)
|
73
66
|
end
|
74
67
|
|
75
|
-
|
76
|
-
|
77
|
-
raise Hanami::CLI::NotImplementedError
|
68
|
+
def gateway
|
69
|
+
slice["db.config"].gateways[:default]
|
78
70
|
end
|
79
71
|
|
80
|
-
|
81
|
-
|
82
|
-
raise Hanami::CLI::NotImplementedError
|
72
|
+
def connection
|
73
|
+
gateway.connection
|
83
74
|
end
|
84
75
|
|
85
|
-
|
86
|
-
|
87
|
-
app.root
|
76
|
+
def exec_create_command
|
77
|
+
raise Hanami::CLI::NotImplementedError
|
88
78
|
end
|
89
79
|
|
90
|
-
|
91
|
-
|
92
|
-
@rom_config ||=
|
93
|
-
begin
|
94
|
-
app.prepare(:persistence)
|
95
|
-
app.container["persistence.config"]
|
96
|
-
end
|
80
|
+
def exec_drop_command
|
81
|
+
raise Hanami::CLI::NotImplementedError
|
97
82
|
end
|
98
83
|
|
99
|
-
|
100
|
-
|
101
|
-
config.db_name
|
84
|
+
def exists?
|
85
|
+
raise Hanami::CLI::NotImplementedError
|
102
86
|
end
|
103
87
|
|
104
|
-
|
105
|
-
|
106
|
-
rom_config.gateways[:default]
|
88
|
+
def exec_dump_command
|
89
|
+
raise Hanami::CLI::NotImplementedError
|
107
90
|
end
|
108
91
|
|
109
|
-
|
110
|
-
|
111
|
-
gateway.connection
|
92
|
+
def exec_load_command
|
93
|
+
raise Hanami::CLI::NotImplementedError
|
112
94
|
end
|
113
95
|
|
114
|
-
# @api private
|
115
96
|
def run_migrations(**options)
|
116
97
|
require "rom/sql"
|
117
98
|
ROM::SQL.with_gateway(gateway) do
|
@@ -119,24 +100,19 @@ module Hanami
|
|
119
100
|
end
|
120
101
|
end
|
121
102
|
|
122
|
-
# @api private
|
123
103
|
def migrator
|
124
|
-
@migrator ||=
|
125
|
-
|
126
|
-
require "rom/sql"
|
127
|
-
ROM::SQL::Migration::Migrator.new(connection, path: File.join(root_path, "db/migrate"))
|
128
|
-
end
|
129
|
-
end
|
104
|
+
@migrator ||= begin
|
105
|
+
slice.prepare :db
|
130
106
|
|
131
|
-
|
132
|
-
|
133
|
-
|
107
|
+
require "rom/sql"
|
108
|
+
ROM::SQL::Migration::Migrator.new(connection, path: migrations_path)
|
109
|
+
end
|
134
110
|
end
|
135
111
|
|
136
|
-
private
|
137
|
-
|
138
112
|
def sequel_migrator
|
139
113
|
@sequel_migrator ||= begin
|
114
|
+
slice.prepare :db
|
115
|
+
|
140
116
|
require "sequel"
|
141
117
|
Sequel.extension :migration
|
142
118
|
|
@@ -147,8 +123,27 @@ module Hanami
|
|
147
123
|
end
|
148
124
|
end
|
149
125
|
|
126
|
+
def applied_migrations
|
127
|
+
sequel_migrator.applied_migrations
|
128
|
+
end
|
129
|
+
|
150
130
|
def migrations_path
|
151
|
-
|
131
|
+
slice.root.join(MIGRATIONS_DIR)
|
132
|
+
end
|
133
|
+
|
134
|
+
def migrations_dir?
|
135
|
+
migrations_path.directory?
|
136
|
+
end
|
137
|
+
|
138
|
+
def structure_file
|
139
|
+
slice.root.join("config/db/structure.sql")
|
140
|
+
end
|
141
|
+
|
142
|
+
def schema_migrations_sql_dump
|
143
|
+
sql = +"INSERT INTO schema_migrations (filename) VALUES\n"
|
144
|
+
sql << applied_migrations.map { |v| "('#{v}')" }.join(",\n")
|
145
|
+
sql << ";"
|
146
|
+
sql
|
152
147
|
end
|
153
148
|
end
|
154
149
|
end
|
@@ -16,12 +16,12 @@ module Hanami
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# @api private
|
19
|
-
def
|
19
|
+
def exec_dump_command
|
20
20
|
raise Hanami::CLI::NotImplementedError
|
21
21
|
end
|
22
22
|
|
23
23
|
# @api private
|
24
|
-
def
|
24
|
+
def exec_load_command
|
25
25
|
raise Hanami::CLI::NotImplementedError
|
26
26
|
end
|
27
27
|
end
|
@@ -11,49 +11,68 @@ module Hanami
|
|
11
11
|
module DB
|
12
12
|
module Utils
|
13
13
|
# @api private
|
14
|
+
# @since 2.2.0
|
14
15
|
class Postgres < Database
|
15
16
|
# @api private
|
16
|
-
|
17
|
-
|
17
|
+
# @since 2.2.0
|
18
|
+
def exec_create_command
|
19
|
+
return true if exists?
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
system(cli_env_vars, "createdb #{escaped_name}")
|
21
|
+
system_call.call("createdb #{escaped_name}", env: cli_env_vars)
|
22
22
|
end
|
23
23
|
|
24
24
|
# @api private
|
25
|
-
|
26
|
-
|
25
|
+
# @since 2.2.0
|
26
|
+
def exec_drop_command
|
27
|
+
return true unless exists?
|
28
|
+
|
29
|
+
system_call.call("dropdb #{escaped_name}", env: cli_env_vars)
|
27
30
|
end
|
28
31
|
|
29
32
|
# @api private
|
30
|
-
|
31
|
-
|
33
|
+
# @since 2.2.0
|
34
|
+
def exists?
|
35
|
+
result = system_call.call("psql -t -A -c '\\list #{escaped_name}'", env: cli_env_vars)
|
36
|
+
result.successful? && result.out.include?("#{name}|") # start_with?
|
32
37
|
end
|
33
38
|
|
34
39
|
# @api private
|
35
|
-
|
36
|
-
|
40
|
+
# @since 2.2.0
|
41
|
+
def exec_dump_command
|
42
|
+
system_call.call(
|
43
|
+
"pg_dump --schema-only --no-privileges --no-owner --file #{structure_file} #{escaped_name}",
|
44
|
+
env: cli_env_vars
|
45
|
+
)
|
37
46
|
end
|
38
47
|
|
39
48
|
# @api private
|
49
|
+
# @since 2.2.0
|
50
|
+
def exec_load_command
|
51
|
+
system_call.call(
|
52
|
+
"psql --set ON_ERROR_STOP=1 --quiet --no-psqlrc --output #{File::NULL} --file #{structure_file} #{escaped_name}",
|
53
|
+
env: cli_env_vars
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
40
57
|
def escaped_name
|
41
58
|
Shellwords.escape(name)
|
42
59
|
end
|
43
60
|
|
44
|
-
# @api private
|
45
61
|
def cli_env_vars
|
46
62
|
@cli_env_vars ||= {}.tap do |vars|
|
47
|
-
vars["PGHOST"] =
|
48
|
-
vars["PGPORT"] =
|
49
|
-
vars["PGUSER"] =
|
50
|
-
vars["PGPASSWORD"] =
|
63
|
+
vars["PGHOST"] = database_uri.host.to_s if database_uri.host
|
64
|
+
vars["PGPORT"] = database_uri.port.to_s if database_uri.port
|
65
|
+
vars["PGUSER"] = database_uri.user.to_s if database_uri.user
|
66
|
+
vars["PGPASSWORD"] = database_uri.password.to_s if database_uri.password
|
51
67
|
end
|
52
68
|
end
|
53
69
|
|
54
|
-
|
55
|
-
|
56
|
-
|
70
|
+
def schema_migrations_sql_dump
|
71
|
+
search_path = slice["db.gateway"].connection
|
72
|
+
.fetch("SHOW search_path").to_a.first
|
73
|
+
.fetch(:search_path)
|
74
|
+
|
75
|
+
+"SET search_path TO #{search_path};\n\n" << super
|
57
76
|
end
|
58
77
|
end
|
59
78
|
end
|
@@ -9,32 +9,80 @@ module Hanami
|
|
9
9
|
module DB
|
10
10
|
module Utils
|
11
11
|
# @api private
|
12
|
+
# @since 2.2.0
|
12
13
|
class Sqlite < Database
|
13
14
|
# @api private
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
# @since 2.2.0
|
16
|
+
Failure = Struct.new(:err) do
|
17
|
+
def successful?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def exit_code
|
22
|
+
1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
# @since 2.2.0
|
28
|
+
def exec_create_command
|
29
|
+
return true if exists?
|
30
|
+
|
31
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
32
|
+
|
33
|
+
system_call.call(%(sqlite3 #{file_path} "VACUUM;"))
|
17
34
|
end
|
18
35
|
|
19
36
|
# @api private
|
20
|
-
|
21
|
-
|
37
|
+
# @since 2.2.0
|
38
|
+
def exec_drop_command
|
39
|
+
begin
|
40
|
+
File.unlink(file_path) if exists?
|
41
|
+
rescue => e
|
42
|
+
# Mimic a system_call result
|
43
|
+
return Failure.new(e.message)
|
44
|
+
end
|
45
|
+
|
22
46
|
true
|
23
47
|
end
|
24
48
|
|
25
49
|
# @api private
|
26
|
-
|
27
|
-
|
50
|
+
# @since 2.2.0
|
51
|
+
def exists?
|
52
|
+
File.exist?(file_path)
|
53
|
+
end
|
54
|
+
|
55
|
+
# @api private
|
56
|
+
# @since 2.2.0
|
57
|
+
def exec_dump_command
|
58
|
+
system_call.call(%(sqlite3 #{file_path} ".schema --indent --nosys" > #{structure_file}))
|
28
59
|
end
|
29
60
|
|
30
61
|
# @api private
|
31
|
-
|
32
|
-
|
62
|
+
# @since 2.2.0
|
63
|
+
def exec_load_command
|
64
|
+
system_call.call("sqlite3 #{file_path} < #{structure_file}")
|
33
65
|
end
|
34
66
|
|
35
67
|
# @api private
|
68
|
+
# @since 2.2.0
|
69
|
+
def name
|
70
|
+
# Sequel expects sqlite:// URIs to operate the same as file:// URIs: 2 slashes for
|
71
|
+
# a relative path, 3 for an absolute path. In the case of 2 slashes, the first part
|
72
|
+
# of the path is considered by Ruby's `URI` as the `#host`.
|
73
|
+
@name ||= "#{database_uri.host}#{database_uri.path}"
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
36
78
|
def file_path
|
37
|
-
@file_path ||=
|
79
|
+
@file_path ||= begin
|
80
|
+
if File.absolute_path?(name)
|
81
|
+
name
|
82
|
+
else
|
83
|
+
slice.app.root.join(name).to_s
|
84
|
+
end
|
85
|
+
end
|
38
86
|
end
|
39
87
|
end
|
40
88
|
end
|
@@ -1,24 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../../app/command"
|
4
|
-
|
5
3
|
module Hanami
|
6
4
|
module CLI
|
7
5
|
module Commands
|
8
6
|
module App
|
9
7
|
module DB
|
10
8
|
# @api private
|
11
|
-
class Version <
|
9
|
+
class Version < DB::Command
|
12
10
|
desc "Print schema version"
|
13
11
|
|
14
|
-
option :target, desc: "Target migration number", aliases: ["-t"]
|
15
|
-
|
16
12
|
# @api private
|
17
|
-
def call(
|
18
|
-
|
19
|
-
|
13
|
+
def call(app: false, slice: nil, **)
|
14
|
+
databases(app: app, slice: slice).each do |database|
|
15
|
+
unless database.migrations_dir?
|
16
|
+
out.puts "=> Cannot find version for slice #{database.slice.slice_name.to_s.inspect}: missing config/db/migrate/ dir"
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
20
|
+
migration = database.applied_migrations.last
|
21
|
+
version = migration ? File.basename(migration, ".*") : "not available"
|
20
22
|
|
21
|
-
|
23
|
+
out.puts "=> #{database.name} current schema version is #{version}"
|
24
|
+
end
|
22
25
|
end
|
23
26
|
end
|
24
27
|
end
|
@@ -32,13 +32,13 @@ module Hanami
|
|
32
32
|
option \
|
33
33
|
:skip_view,
|
34
34
|
required: false,
|
35
|
-
type: :
|
35
|
+
type: :flag,
|
36
36
|
default: DEFAULT_SKIP_VIEW,
|
37
37
|
desc: "Skip view and template generation"
|
38
38
|
option \
|
39
39
|
:skip_tests,
|
40
40
|
required: false,
|
41
|
-
type: :
|
41
|
+
type: :flag,
|
42
42
|
default: DEFAULT_SKIP_TESTS,
|
43
43
|
desc: "Skip test generation"
|
44
44
|
option :slice, required: false, desc: "Slice name"
|
@@ -85,7 +85,8 @@ module Hanami
|
|
85
85
|
skip_view: DEFAULT_SKIP_VIEW,
|
86
86
|
skip_tests: DEFAULT_SKIP_TESTS, # rubocop:disable Lint/UnusedMethodArgument
|
87
87
|
slice: nil,
|
88
|
-
context: nil,
|
88
|
+
context: nil,
|
89
|
+
**
|
89
90
|
)
|
90
91
|
slice = inflector.underscore(Shellwords.shellescape(slice)) if slice
|
91
92
|
name = naming.action_name(name)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/inflector"
|
4
|
+
require "dry/files"
|
5
|
+
require "shellwords"
|
6
|
+
require_relative "../../../naming"
|
7
|
+
require_relative "../../../errors"
|
8
|
+
|
9
|
+
module Hanami
|
10
|
+
module CLI
|
11
|
+
module Commands
|
12
|
+
module App
|
13
|
+
module Generate
|
14
|
+
# @since 2.2.0
|
15
|
+
# @api private
|
16
|
+
class Command < App::Command
|
17
|
+
option :slice, required: false, desc: "Slice name"
|
18
|
+
|
19
|
+
attr_reader :generator
|
20
|
+
private :generator
|
21
|
+
|
22
|
+
# @since 2.2.0
|
23
|
+
# @api private
|
24
|
+
def initialize(
|
25
|
+
fs:,
|
26
|
+
inflector:,
|
27
|
+
**opts
|
28
|
+
)
|
29
|
+
super
|
30
|
+
@generator = generator_class.new(fs: fs, inflector: inflector, out: out)
|
31
|
+
end
|
32
|
+
|
33
|
+
def generator_class
|
34
|
+
# Must be implemented by subclasses, with class that takes:
|
35
|
+
# fs:, inflector:, out:
|
36
|
+
end
|
37
|
+
|
38
|
+
# @since 2.2.0
|
39
|
+
# @api private
|
40
|
+
def call(name:, slice: nil, **)
|
41
|
+
normalized_slice = inflector.underscore(slice) if slice
|
42
|
+
generator.call(app.namespace, name, normalized_slice)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/inflector"
|
4
|
+
require "dry/files"
|
5
|
+
require "shellwords"
|
6
|
+
module Hanami
|
7
|
+
module CLI
|
8
|
+
module Commands
|
9
|
+
module App
|
10
|
+
module Generate
|
11
|
+
# @api private
|
12
|
+
# @since 2.2.0
|
13
|
+
class Component < App::Command
|
14
|
+
argument :name, required: true, desc: "Component name"
|
15
|
+
option :slice, required: false, desc: "Slice name"
|
16
|
+
|
17
|
+
example [
|
18
|
+
%(operations.create_user (MyApp::Operations::CreateUser)),
|
19
|
+
%(operations.user.create (MyApp::Operations::Create::User)),
|
20
|
+
%(operations.create_user --slice=admin (Admin::Operations::CreateUser)),
|
21
|
+
%(Operations::CreateUser (MyApp::Operations::CreateUser)),
|
22
|
+
]
|
23
|
+
attr_reader :generator
|
24
|
+
private :generator
|
25
|
+
|
26
|
+
# @api private
|
27
|
+
# @since 2.2.0
|
28
|
+
def initialize(
|
29
|
+
fs:, inflector:,
|
30
|
+
generator: Generators::App::Component.new(fs: fs, inflector: inflector),
|
31
|
+
**opts
|
32
|
+
)
|
33
|
+
@generator = generator
|
34
|
+
super(fs: fs, inflector: inflector, **opts)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @api private
|
38
|
+
# @since 2.2.0
|
39
|
+
def call(name:, slice: nil, **)
|
40
|
+
slice = inflector.underscore(Shellwords.shellescape(slice)) if slice
|
41
|
+
|
42
|
+
generator.call(app.namespace, name, slice)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module CLI
|
5
|
+
module Commands
|
6
|
+
module App
|
7
|
+
module Generate
|
8
|
+
# @since 2.2.0
|
9
|
+
# @api private
|
10
|
+
class Migration < Command
|
11
|
+
argument :name, required: true, desc: "Migration name"
|
12
|
+
|
13
|
+
example [
|
14
|
+
%(create_posts),
|
15
|
+
%(add_published_at_to_posts),
|
16
|
+
%(create_users --slice=admin),
|
17
|
+
]
|
18
|
+
|
19
|
+
def generator_class
|
20
|
+
Generators::App::Migration
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module CLI
|
5
|
+
module Commands
|
6
|
+
module App
|
7
|
+
module Generate
|
8
|
+
# @since 2.2.0
|
9
|
+
# @api private
|
10
|
+
class Operation < Command
|
11
|
+
argument :name, required: true, desc: "Operation name"
|
12
|
+
|
13
|
+
example [
|
14
|
+
%(books.add (MyApp::Books::Add)),
|
15
|
+
%(books.add --slice=admin (Admin::Books::Add)),
|
16
|
+
]
|
17
|
+
|
18
|
+
def generator_class
|
19
|
+
Generators::App::Operation
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|