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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +42 -0
- data/.gitignore +4 -2
- data/.rspec +1 -0
- data/.rubocop.yml +25 -1
- data/CHANGELOG.md +39 -1
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +13 -6
- data/LICENSE.txt +21 -0
- data/README.md +13 -488
- data/Rakefile +8 -15
- data/bin/console +1 -0
- data/exe/hanami +10 -0
- data/hanami-cli.gemspec +24 -18
- data/lib/hanami/cli.rb +10 -121
- data/lib/hanami/cli/bundler.rb +73 -0
- data/lib/hanami/cli/command.rb +16 -355
- data/lib/hanami/cli/command_line.rb +17 -0
- data/lib/hanami/cli/commands.rb +26 -0
- data/lib/hanami/cli/commands/application.rb +63 -0
- data/lib/hanami/cli/commands/db/utils/database.rb +122 -0
- data/lib/hanami/cli/commands/db/utils/database_config.rb +48 -0
- data/lib/hanami/cli/commands/db/utils/mysql.rb +27 -0
- data/lib/hanami/cli/commands/db/utils/postgres.rb +49 -0
- data/lib/hanami/cli/commands/db/utils/sqlite.rb +37 -0
- data/lib/hanami/cli/commands/gem.rb +21 -0
- data/lib/hanami/cli/commands/gem/new.rb +77 -0
- data/lib/hanami/cli/commands/gem/version.rb +18 -0
- data/lib/hanami/cli/commands/monolith.rb +55 -0
- data/lib/hanami/cli/commands/monolith/console.rb +50 -0
- data/lib/hanami/cli/commands/monolith/db/create.rb +25 -0
- data/lib/hanami/cli/commands/monolith/db/create_migration.rb +29 -0
- data/lib/hanami/cli/commands/monolith/db/drop.rb +25 -0
- data/lib/hanami/cli/commands/monolith/db/migrate.rb +40 -0
- data/lib/hanami/cli/commands/monolith/db/reset.rb +26 -0
- data/lib/hanami/cli/commands/monolith/db/rollback.rb +55 -0
- data/lib/hanami/cli/commands/monolith/db/sample_data.rb +40 -0
- data/lib/hanami/cli/commands/monolith/db/seed.rb +40 -0
- data/lib/hanami/cli/commands/monolith/db/setup.rb +24 -0
- data/lib/hanami/cli/commands/monolith/db/structure/dump.rb +25 -0
- data/lib/hanami/cli/commands/monolith/db/version.rb +26 -0
- data/lib/hanami/cli/commands/monolith/generate.rb +14 -0
- data/lib/hanami/cli/commands/monolith/generate/action.rb +62 -0
- data/lib/hanami/cli/commands/monolith/generate/slice.rb +62 -0
- data/lib/hanami/cli/commands/monolith/install.rb +16 -0
- data/lib/hanami/cli/commands/monolith/version.rb +18 -0
- data/lib/hanami/cli/error.rb +8 -0
- data/lib/hanami/cli/generators/context.rb +38 -0
- data/lib/hanami/cli/generators/gem/application.rb +21 -0
- data/lib/hanami/cli/generators/gem/application/monolith.rb +83 -0
- data/lib/hanami/cli/generators/gem/application/monolith/action.erb +21 -0
- data/lib/hanami/cli/generators/gem/application/monolith/application.erb +8 -0
- data/lib/hanami/cli/generators/gem/application/monolith/config_ru.erb +5 -0
- data/lib/hanami/cli/generators/gem/application/monolith/entities.erb +9 -0
- data/lib/hanami/cli/generators/gem/application/monolith/env.erb +0 -0
- data/lib/hanami/cli/generators/gem/application/monolith/functions.erb +13 -0
- data/lib/hanami/cli/generators/gem/application/monolith/gemfile.erb +19 -0
- data/lib/hanami/cli/generators/gem/application/monolith/keep.erb +0 -0
- data/lib/hanami/cli/generators/gem/application/monolith/operation.erb +18 -0
- data/lib/hanami/cli/generators/gem/application/monolith/rakefile.erb +3 -0
- data/lib/hanami/cli/generators/gem/application/monolith/readme.erb +1 -0
- data/lib/hanami/cli/generators/gem/application/monolith/repository.erb +13 -0
- data/lib/hanami/cli/generators/gem/application/monolith/routes.erb +4 -0
- data/lib/hanami/cli/generators/gem/application/monolith/settings.erb +6 -0
- data/lib/hanami/cli/generators/gem/application/monolith/types.erb +10 -0
- data/lib/hanami/cli/generators/gem/application/monolith/validation_contract.erb +14 -0
- data/lib/hanami/cli/generators/gem/application/monolith/view_context.erb +15 -0
- data/lib/hanami/cli/generators/monolith/action.rb +123 -0
- data/lib/hanami/cli/generators/monolith/action/action.erb +13 -0
- data/lib/hanami/cli/generators/monolith/action/template.erb +0 -0
- data/lib/hanami/cli/generators/monolith/action/template.html.erb +2 -0
- data/lib/hanami/cli/generators/monolith/action/view.erb +13 -0
- data/lib/hanami/cli/generators/monolith/action_context.rb +76 -0
- data/lib/hanami/cli/generators/monolith/slice.rb +56 -0
- data/lib/hanami/cli/generators/monolith/slice/action.erb +9 -0
- data/lib/hanami/cli/generators/monolith/slice/entities.erb +9 -0
- data/lib/hanami/cli/generators/monolith/slice/keep.erb +0 -0
- data/lib/hanami/cli/generators/monolith/slice/repository.erb +10 -0
- data/lib/hanami/cli/generators/monolith/slice/routes.erb +2 -0
- data/lib/hanami/cli/generators/monolith/slice/view.erb +9 -0
- data/lib/hanami/cli/generators/monolith/slice_context.rb +33 -0
- data/lib/hanami/cli/repl/core.rb +55 -0
- data/lib/hanami/cli/repl/irb.rb +41 -0
- data/lib/hanami/cli/repl/pry.rb +29 -0
- data/lib/hanami/cli/system_call.rb +51 -0
- data/lib/hanami/cli/url.rb +34 -0
- data/lib/hanami/cli/version.rb +4 -3
- data/lib/hanami/console/context.rb +39 -0
- data/lib/hanami/console/plugins/slice_readers.rb +42 -0
- data/lib/hanami/rake_tasks.rb +52 -0
- metadata +138 -41
- data/.travis.yml +0 -16
- data/lib/hanami/cli/banner.rb +0 -126
- data/lib/hanami/cli/command_registry.rb +0 -213
- data/lib/hanami/cli/errors.rb +0 -32
- data/lib/hanami/cli/option.rb +0 -125
- data/lib/hanami/cli/parser.rb +0 -122
- data/lib/hanami/cli/program_name.rb +0 -19
- data/lib/hanami/cli/registry.rb +0 -328
- data/lib/hanami/cli/usage.rb +0 -88
- data/script/ci +0 -51
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../../application"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module CLI
|
|
7
|
+
module Commands
|
|
8
|
+
module Monolith
|
|
9
|
+
module DB
|
|
10
|
+
module Structure
|
|
11
|
+
class Dump < Application
|
|
12
|
+
desc "Dumps database structure to db/structure.sql file"
|
|
13
|
+
|
|
14
|
+
def call(*)
|
|
15
|
+
measure("#{database.name} structure dumped to db/structure.sql") do
|
|
16
|
+
database.dump_command
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../application"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module CLI
|
|
7
|
+
module Commands
|
|
8
|
+
module Monolith
|
|
9
|
+
module DB
|
|
10
|
+
class Version < Application
|
|
11
|
+
desc "Print schema version"
|
|
12
|
+
|
|
13
|
+
option :target, desc: "Target migration number", aliases: ["-t"]
|
|
14
|
+
|
|
15
|
+
def call(target: nil, **)
|
|
16
|
+
migration = database.applied_migrations.last
|
|
17
|
+
version = migration ? File.basename(migration, ".*") : "not available"
|
|
18
|
+
|
|
19
|
+
out.puts "=> current schema version is #{version}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/cli/command"
|
|
4
|
+
require "hanami/cli/generators/monolith/action"
|
|
5
|
+
require "dry/inflector"
|
|
6
|
+
require "dry/files"
|
|
7
|
+
require "shellwords"
|
|
8
|
+
|
|
9
|
+
module Hanami
|
|
10
|
+
module CLI
|
|
11
|
+
module Commands
|
|
12
|
+
module Monolith
|
|
13
|
+
module Generate
|
|
14
|
+
class Action < Command
|
|
15
|
+
# TODO: ideally the default format should lookup
|
|
16
|
+
# slice configuration (Action's `default_response_format`)
|
|
17
|
+
DEFAULT_FORMAT = "html"
|
|
18
|
+
private_constant :DEFAULT_FORMAT
|
|
19
|
+
|
|
20
|
+
DEFAULT_SKIP_VIEW = false
|
|
21
|
+
private_constant :DEFAULT_SKIP_VIEW
|
|
22
|
+
|
|
23
|
+
argument :slice, required: true, desc: "Slice name"
|
|
24
|
+
argument :name, required: true, desc: "Action name"
|
|
25
|
+
option :url, required: false, type: :string, desc: "Action URL"
|
|
26
|
+
option :http, required: false, type: :string, desc: "Action HTTP method"
|
|
27
|
+
option :format, required: false, type: :string, default: DEFAULT_FORMAT, desc: "Template format"
|
|
28
|
+
option :skip_view, required: false, type: :boolean, default: DEFAULT_SKIP_VIEW,
|
|
29
|
+
desc: "Skip view and template generation"
|
|
30
|
+
|
|
31
|
+
def initialize(fs: Dry::Files.new, inflector: Dry::Inflector.new,
|
|
32
|
+
generator: Generators::Monolith::Action.new(fs: fs, inflector: inflector), **)
|
|
33
|
+
@generator = generator
|
|
34
|
+
super(fs: fs)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# rubocop:disable Metrics/ParameterLists
|
|
38
|
+
def call(slice:, name:, url: nil, http: nil, format: DEFAULT_FORMAT, skip_view: DEFAULT_SKIP_VIEW, **)
|
|
39
|
+
slice = inflector.underscore(Shellwords.shellescape(slice))
|
|
40
|
+
name = inflector.underscore(Shellwords.shellescape(name))
|
|
41
|
+
*controller, action = name.split(ACTION_SEPARATOR)
|
|
42
|
+
|
|
43
|
+
if controller.empty?
|
|
44
|
+
raise ArgumentError.new("cannot parse controller and action name: `#{name}'\n\texample: users.show")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
generator.call(slice, controller, action, url, http, format, skip_view)
|
|
48
|
+
end
|
|
49
|
+
# rubocop:enable Metrics/ParameterLists
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
ACTION_SEPARATOR = "."
|
|
54
|
+
private_constant :ACTION_SEPARATOR
|
|
55
|
+
|
|
56
|
+
attr_reader :generator
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/cli/command"
|
|
4
|
+
require "hanami/cli/generators/monolith/slice"
|
|
5
|
+
require "dry/inflector"
|
|
6
|
+
require "dry/files"
|
|
7
|
+
require "shellwords"
|
|
8
|
+
require "hanami/cli/url"
|
|
9
|
+
|
|
10
|
+
module Hanami
|
|
11
|
+
module CLI
|
|
12
|
+
module Commands
|
|
13
|
+
module Monolith
|
|
14
|
+
module Generate
|
|
15
|
+
class Slice < Command
|
|
16
|
+
argument :name, required: true, desc: "The slice name"
|
|
17
|
+
option :url_prefix, required: false, type: :string, desc: "The slice URL prefix"
|
|
18
|
+
|
|
19
|
+
def initialize(fs: Dry::Files.new, inflector: Dry::Inflector.new,
|
|
20
|
+
generator: Generators::Monolith::Slice.new(fs: fs, inflector: inflector), **)
|
|
21
|
+
@generator = generator
|
|
22
|
+
super(fs: fs)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def call(name:, url_prefix: nil, **)
|
|
26
|
+
require "hanami/setup"
|
|
27
|
+
|
|
28
|
+
app = inflector.underscore(Hanami.application.namespace)
|
|
29
|
+
name = inflector.underscore(Shellwords.shellescape(name))
|
|
30
|
+
url_prefix = sanitize_url_prefix(name, url_prefix)
|
|
31
|
+
|
|
32
|
+
generator.call(app, name, url_prefix)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
DEFAULT_URL_PREFIX = "/"
|
|
38
|
+
private_constant :DEFAULT_URL_PREFIX
|
|
39
|
+
|
|
40
|
+
attr_reader :generator
|
|
41
|
+
|
|
42
|
+
def sanitize_url_prefix(name, url_prefix)
|
|
43
|
+
result = url_prefix
|
|
44
|
+
result = inflector.underscore(Shellwords.shellescape(result)) unless result.nil?
|
|
45
|
+
|
|
46
|
+
result ||= DEFAULT_URL_PREFIX + name
|
|
47
|
+
CLI::URL.call(result)
|
|
48
|
+
rescue ArgumentError
|
|
49
|
+
raise ArgumentError.new("invalid URL prefix: `#{url_prefix}'")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def valid_url?(url)
|
|
53
|
+
return false if url.nil?
|
|
54
|
+
|
|
55
|
+
url.start_with?(DEFAULT_URL_PREFIX)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/cli/command"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module CLI
|
|
7
|
+
module Commands
|
|
8
|
+
module Monolith
|
|
9
|
+
class Version < Command
|
|
10
|
+
def call(*)
|
|
11
|
+
require "hanami/version"
|
|
12
|
+
out.puts "v#{Hanami::VERSION}"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "hanami/version"
|
|
4
|
+
|
|
5
|
+
module Hanami
|
|
6
|
+
module CLI
|
|
7
|
+
module Generators
|
|
8
|
+
class Context
|
|
9
|
+
def initialize(inflector, app)
|
|
10
|
+
@inflector = inflector
|
|
11
|
+
@app = app
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def ctx
|
|
15
|
+
binding
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def hanami_version
|
|
19
|
+
Hanami::Version.gem_requirement
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def classified_app_name
|
|
23
|
+
inflector.classify(app)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def underscored_app_name
|
|
27
|
+
inflector.underscore(app)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
attr_reader :inflector
|
|
33
|
+
|
|
34
|
+
attr_reader :app
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Hanami
|
|
4
|
+
module CLI
|
|
5
|
+
module Generators
|
|
6
|
+
module Gem
|
|
7
|
+
module Application
|
|
8
|
+
class << self
|
|
9
|
+
def call(architecture, fs, inflector, command_line)
|
|
10
|
+
require_relative "./application/#{architecture}"
|
|
11
|
+
|
|
12
|
+
generator_name = inflector.classify(architecture).to_sym
|
|
13
|
+
const_get(generator_name).new(fs: fs, inflector: inflector, command_line: command_line)
|
|
14
|
+
end
|
|
15
|
+
alias_method :[], :call
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "erb"
|
|
4
|
+
require "shellwords"
|
|
5
|
+
require "hanami/cli/generators/context"
|
|
6
|
+
|
|
7
|
+
module Hanami
|
|
8
|
+
module CLI
|
|
9
|
+
module Generators
|
|
10
|
+
module Gem
|
|
11
|
+
module Application
|
|
12
|
+
class Monolith
|
|
13
|
+
def initialize(fs:, inflector:, command_line:)
|
|
14
|
+
super()
|
|
15
|
+
@fs = fs
|
|
16
|
+
@inflector = inflector
|
|
17
|
+
@command_line = command_line
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call(app, slice, slice_url_prefix, context: Context.new(inflector, app), &blk)
|
|
21
|
+
generate_app(app, context)
|
|
22
|
+
blk.call
|
|
23
|
+
generate_slice!(slice, slice_url_prefix)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_reader :fs
|
|
29
|
+
|
|
30
|
+
attr_reader :inflector
|
|
31
|
+
|
|
32
|
+
attr_reader :command_line
|
|
33
|
+
|
|
34
|
+
def generate_app(app, context) # rubocop:disable Metrics/AbcSize
|
|
35
|
+
fs.write(".env", t("env.erb", context))
|
|
36
|
+
|
|
37
|
+
fs.write("README.md", t("readme.erb", context))
|
|
38
|
+
fs.write("Gemfile", t("gemfile.erb", context))
|
|
39
|
+
fs.write("Rakefile", t("rakefile.erb", context))
|
|
40
|
+
fs.write("config.ru", t("config_ru.erb", context))
|
|
41
|
+
|
|
42
|
+
fs.write("config/application.rb", t("application.erb", context))
|
|
43
|
+
fs.write("config/settings.rb", t("settings.erb", context))
|
|
44
|
+
fs.write("config/routes.rb", t("routes.erb", context))
|
|
45
|
+
|
|
46
|
+
fs.write("lib/tasks/.keep", t("keep.erb", context))
|
|
47
|
+
|
|
48
|
+
fs.write("lib/#{app}/entities/.keep", t("keep.erb", context))
|
|
49
|
+
fs.write("lib/#{app}/persistence/relations/.keep", t("keep.erb", context))
|
|
50
|
+
fs.write("lib/#{app}/validation/contract.rb", t("validation_contract.erb", context))
|
|
51
|
+
fs.write("lib/#{app}/view/context.rb", t("view_context.erb", context))
|
|
52
|
+
fs.write("lib/#{app}/action.rb", t("action.erb", context))
|
|
53
|
+
fs.write("lib/#{app}/entities.rb", t("entities.erb", context))
|
|
54
|
+
fs.write("lib/#{app}/functions.rb", t("functions.erb", context))
|
|
55
|
+
fs.write("lib/#{app}/operation.rb", t("operation.erb", context))
|
|
56
|
+
fs.write("lib/#{app}/repository.rb", t("repository.erb", context))
|
|
57
|
+
fs.write("lib/#{app}/types.rb", t("types.erb", context))
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def generate_slice!(slice_name, slice_url_prefix)
|
|
61
|
+
slice_name = Shellwords.shellescape(slice_name)
|
|
62
|
+
slice_url_prefix = Shellwords.shellescape(slice_url_prefix)
|
|
63
|
+
|
|
64
|
+
command_line.call("hanami generate slice #{slice_name} --url-prefix=#{slice_url_prefix}").tap do |result|
|
|
65
|
+
raise "hanami generate slice #{slice_name} failed\n\n\n#{result.err.inspect}" unless result.successful?
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def template(path, context)
|
|
70
|
+
require "erb"
|
|
71
|
+
|
|
72
|
+
ERB.new(
|
|
73
|
+
File.read(__dir__ + "/monolith/#{path}")
|
|
74
|
+
).result(context.ctx)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
alias_method :t, :template
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# auto_register: false
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "json" # required for Hanami::Action::Flash to work
|
|
5
|
+
require "hanami/action"
|
|
6
|
+
require "hanami/action/cookies"
|
|
7
|
+
require "hanami/action/csrf_protection"
|
|
8
|
+
require "hanami/action/session"
|
|
9
|
+
|
|
10
|
+
module <%= classified_app_name %>
|
|
11
|
+
class Action < Hanami::Action
|
|
12
|
+
def self.inherited(klass)
|
|
13
|
+
super
|
|
14
|
+
|
|
15
|
+
# These will need to be sorted by the framework eventually
|
|
16
|
+
klass.include Hanami::Action::Cookies
|
|
17
|
+
klass.include Hanami::Action::Session
|
|
18
|
+
klass.include Hanami::Action::CSRFProtection
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
File without changes
|