hanami-cli 2.0.3 → 2.1.0.beta2

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/Gemfile +3 -2
  4. data/LICENSE.md +1 -1
  5. data/README.md +1 -1
  6. data/hanami-cli.gemspec +1 -1
  7. data/lib/hanami/cli/bundler.rb +21 -7
  8. data/lib/hanami/cli/command.rb +4 -4
  9. data/lib/hanami/cli/commands/app/assets/command.rb +82 -0
  10. data/lib/hanami/cli/commands/app/assets/compile.rb +32 -0
  11. data/lib/hanami/cli/commands/app/assets/watch.rb +36 -0
  12. data/lib/hanami/cli/commands/app/assets.rb +16 -0
  13. data/lib/hanami/cli/commands/app/command.rb +2 -2
  14. data/lib/hanami/cli/commands/app/db/rollback.rb +30 -6
  15. data/lib/hanami/cli/commands/app/db/utils/database.rb +5 -1
  16. data/lib/hanami/cli/commands/app/dev.rb +57 -0
  17. data/lib/hanami/cli/commands/app/generate/action.rb +5 -4
  18. data/lib/hanami/cli/commands/app/generate/view.rb +57 -0
  19. data/lib/hanami/cli/commands/app/generate.rb +2 -2
  20. data/lib/hanami/cli/commands/app/install.rb +44 -1
  21. data/lib/hanami/cli/commands/app.rb +9 -0
  22. data/lib/hanami/cli/commands/gem/new.rb +41 -7
  23. data/lib/hanami/cli/errors.rb +30 -0
  24. data/lib/hanami/cli/files.rb +8 -2
  25. data/lib/hanami/cli/generators/app/action/action.erb +5 -1
  26. data/lib/hanami/cli/generators/app/action/slice_action.erb +5 -1
  27. data/lib/hanami/cli/generators/app/action/slice_template.html.erb +1 -0
  28. data/lib/hanami/cli/generators/app/action/slice_view.erb +10 -0
  29. data/lib/hanami/cli/generators/app/action/template.html.erb +1 -2
  30. data/lib/hanami/cli/generators/app/action/view.erb +2 -5
  31. data/lib/hanami/cli/generators/app/action.rb +34 -22
  32. data/lib/hanami/cli/generators/app/action_context.rb +1 -1
  33. data/lib/hanami/cli/generators/app/slice/app_css.erb +5 -0
  34. data/lib/hanami/cli/generators/app/slice/app_js.erb +1 -0
  35. data/lib/hanami/cli/generators/app/slice/app_layout.erb +18 -0
  36. data/lib/hanami/cli/generators/app/slice/helpers.erb +10 -0
  37. data/lib/hanami/cli/generators/app/slice/view.erb +0 -2
  38. data/lib/hanami/cli/generators/app/slice.rb +15 -6
  39. data/lib/hanami/cli/generators/app/slice_context.rb +18 -0
  40. data/lib/hanami/cli/generators/app/view/app_template.html.erb +1 -0
  41. data/lib/hanami/cli/generators/app/view/app_view.erb +10 -0
  42. data/lib/hanami/cli/generators/app/view/slice_template.html.erb +1 -0
  43. data/lib/hanami/cli/generators/app/view/slice_view.erb +10 -0
  44. data/lib/hanami/cli/generators/app/view.rb +89 -0
  45. data/lib/hanami/cli/generators/app/view_context.rb +100 -0
  46. data/lib/hanami/cli/generators/context.rb +53 -4
  47. data/lib/hanami/cli/generators/gem/app/404.html +11 -0
  48. data/lib/hanami/cli/generators/gem/app/500.html +11 -0
  49. data/lib/hanami/cli/generators/gem/app/app_css.erb +5 -0
  50. data/lib/hanami/cli/generators/gem/app/app_js.erb +1 -0
  51. data/lib/hanami/cli/generators/gem/app/app_layout.erb +18 -0
  52. data/lib/hanami/cli/generators/gem/app/favicon.ico +0 -0
  53. data/lib/hanami/cli/generators/gem/app/gemfile.erb +14 -6
  54. data/lib/hanami/cli/generators/gem/app/gitignore.erb +4 -0
  55. data/lib/hanami/cli/generators/gem/app/helpers.erb +10 -0
  56. data/lib/hanami/cli/generators/gem/app/procfile.erb +4 -0
  57. data/lib/hanami/cli/generators/gem/app/puma.erb +5 -3
  58. data/lib/hanami/cli/generators/gem/app/view.erb +9 -0
  59. data/lib/hanami/cli/generators/gem/app.rb +15 -1
  60. data/lib/hanami/cli/interactive_system_call.rb +64 -0
  61. data/lib/hanami/cli/system_call.rb +8 -2
  62. data/lib/hanami/cli/url.rb +1 -1
  63. data/lib/hanami/cli/version.rb +1 -1
  64. metadata +35 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bcebd7bee28802b90462073bbc9def8c6f1c13b7fc032cc8f20859b082310a4
4
- data.tar.gz: fd38025e1fa7a2b5c6650710e16076fefa8f8697a1b3bba3035eedaa9ce612b4
3
+ metadata.gz: 85a528645e9205c15ccdf4b81cc32a3fb0789a8a7f07c56554c1b8b0e66b9e91
4
+ data.tar.gz: 5937fd333d11a7f5131d0298dc609c8a92e233249bc0b2e9e8f28705977f20b4
5
5
  SHA512:
6
- metadata.gz: bdebf6ac07bfad66d9a7d37050ce6b91c7d29abc781c44807a0efdc8c7085db42ed7afcbf5b5b32f264213499e59d31754823a670eb43d71acee1be39dd0b5c2
7
- data.tar.gz: 56a41e42c83896516b0b20d7aea8864743c9a96508fd520d226de683d59de612a85cd99e83f7ed50bf39cfa87564152afb903bbfdc6d4d8e48ed9eb1904705e1
6
+ metadata.gz: df19a905d03fec4665ce80dd89730dee6337312e32e0e923e9424a387d66b8f9605e8392a5a73bd4627251b96c57b4a95f4df32062d8a53d42041d69841c10d6
7
+ data.tar.gz: e4931266c0517de1bb33bc0f862c73da58366d6d5707c0eacf48fd38b08b8d7ae767e8fd7c81f1f048b96ffda5977674e556e281c51ab1f2a4eb30c6ceaa7ade
data/CHANGELOG.md CHANGED
@@ -2,6 +2,39 @@
2
2
 
3
3
  Hanami Command Line Interface
4
4
 
5
+ ## v2.1.0.beta2 - 2023-10-04
6
+
7
+ ### Added
8
+
9
+ - [Luca Guidi] `hanami new` generates `Procfile.dev`
10
+ - [Luca Guidi] `hanami new` generates basic app assets, if `hanami-assets` is bundled by the app
11
+ - [Luca Guidi] `hanami new` accepts `--head` to generate the app using Hanami HEAD version from GitHub
12
+ - [Luca Guidi] `hanami generate slice` generates basic slice assets, if `hanami-assets` is bundled by the app
13
+ - [Ryan Bigg] `hanami generate action` generates corresponding view, if `hanami-view` is bundled by the app
14
+ - [Luca Guidi] `hanami assets compile` to compile assets at the deploy time
15
+ - [Luca Guidi] `hanami assets watch` to watch and compile assets at the development time
16
+ - [Luca Guidi] `hanami dev` to start the processes in `Procfile.dev`
17
+
18
+ ### Fixed
19
+
20
+ - [Luca Guidi] `hanami new` generates a `Gemfile` with `hanami-webconsole` in `:development` group
21
+ - [Luca Guidi] `hanami new` generates a `Gemfile` with versioned `hanami-webconsole`, `hanami-rspec`, and `hanami-reloader`
22
+
23
+ ## v2.1.0.beta1 - 2023-06-29
24
+
25
+ ### Added
26
+
27
+ - [Tim Riley] `hanami new` to generate default views, templates, and helpers
28
+ - [Tim Riley] `hanami generate slice` to generate default views, templates, and helpers
29
+ - [Tim Riley] `hanami generate action` to generate associated view and template
30
+ - [Tim Riley] Introduced `hanami generate view`
31
+ - [Tim Riley] `hanami new` to generate `Gemfile` with `hanami-view` and `hanami-webconsole` gems
32
+ - [Tim Riley] `hanami new` to generate default error pages for `404` and `500` HTTP errors
33
+
34
+ ### Fixed
35
+
36
+ - [Philip Arndt] `hanami server` to start only one Puma worker by default
37
+
5
38
  ## v2.0.3 - 2023-02-01
6
39
 
7
40
  ### Added
data/Gemfile CHANGED
@@ -10,9 +10,10 @@ unless ENV["CI"]
10
10
  end
11
11
 
12
12
  gem "hanami", github: "hanami/hanami", branch: "main"
13
- gem "hanami-utils", github: "hanami/utils", branch: "main"
14
- gem "hanami-router", github: "hanami/router", branch: "main"
13
+ gem "hanami-assets", github: "hanami/assets", branch: "main"
15
14
  gem "hanami-controller", github: "hanami/controller", branch: "main"
15
+ gem "hanami-router", github: "hanami/router", branch: "main"
16
+ gem "hanami-utils", github: "hanami/utils", branch: "main"
16
17
 
17
18
  gem "rack"
18
19
 
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2014-2022 Luca Guidi
1
+ Copyright © 2014 Hanami Team
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -44,4 +44,4 @@ Everyone interacting in the `Hanami::CLI` project's codebases, issue trackers, c
44
44
 
45
45
  ## Copyright
46
46
 
47
- Copyright © 2014-2022 Hanami Team – Released under MIT License
47
+ Copyright © 2014 Hanami Team – Released under MIT License
data/hanami-cli.gemspec CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
 
33
33
  spec.add_dependency "bundler", "~> 2.1"
34
34
  spec.add_dependency "dry-cli", "~> 1.0", "< 2"
35
- spec.add_dependency "dry-files", "~> 1.0", ">= 1.0.1", "< 2"
35
+ spec.add_dependency "dry-files", "~> 1.0", ">= 1.0.2", "< 2"
36
36
  spec.add_dependency "dry-inflector", "~> 1.0", "< 2"
37
37
  spec.add_dependency "rake", "~> 13.0"
38
38
  spec.add_dependency "zeitwerk", "~> 2.6"
@@ -3,9 +3,9 @@
3
3
  require "bundler"
4
4
  require "open3"
5
5
  require "etc"
6
- require "dry/files"
7
- require_relative "./system_call"
8
- require_relative "./errors"
6
+ require_relative "files"
7
+ require_relative "system_call"
8
+ require_relative "errors"
9
9
 
10
10
  module Hanami
11
11
  module CLI
@@ -45,12 +45,12 @@ module Hanami
45
45
 
46
46
  # Returns a new bundler.
47
47
  #
48
- # @param fs [Dry::Files] the filesystem interaction object
48
+ # @param fs [Hanami::CLI::Files] the filesystem interaction object
49
49
  # @param system_call [SystemCall] convenience object for making system calls
50
50
  #
51
51
  # @since 2.0.0
52
52
  # @api public
53
- def initialize(fs: Dry::Files.new, system_call: SystemCall.new)
53
+ def initialize(fs: Hanami::CLI::Files.new, system_call: SystemCall.new)
54
54
  @fs = fs
55
55
  @system_call = system_call
56
56
  end
@@ -71,7 +71,7 @@ module Hanami
71
71
  #
72
72
  # @return [SystemCall::Result] the result of the `bundle` command execution
73
73
  #
74
- # @raise [StandardError] if the `bundle` command does not execute successfully
74
+ # @raise [Hanami::CLI::BundleInstallError] if the `bundle` command does not execute successfully
75
75
  #
76
76
  # @since 2.0.0
77
77
  # @api public
@@ -81,6 +81,20 @@ module Hanami
81
81
  end
82
82
  end
83
83
 
84
+ # Runs the given Hanami CLI command via `bundle exec hanami`
85
+ #
86
+ # @return [SystemCall::Result] the result of the command execution
87
+ #
88
+ # @raise [Hanami::CLI::HanamiExecError] if the does not execute successfully
89
+ #
90
+ # @since 2.1.0
91
+ # @api public
92
+ def hanami_exec(cmd, env: nil, &blk)
93
+ exec("hanami #{cmd}", env: env, &blk).tap do |result|
94
+ raise HanamiExecError.new(cmd, result.err) unless result.successful?
95
+ end
96
+ end
97
+
84
98
  # Executes the given command prefixed by `bundle exec`.
85
99
  #
86
100
  # @return [SystemCall::Result] the result of the command execution
@@ -127,7 +141,7 @@ module Hanami
127
141
 
128
142
  private
129
143
 
130
- # @return [Dry::Files]
144
+ # @return [Hanami::CLI::Files]
131
145
  #
132
146
  # @since 2.0.0
133
147
  # @api public
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/cli"
4
- require "dry/files"
5
4
  require "dry/inflector"
5
+ require_relative "files"
6
6
 
7
7
  module Hanami
8
8
  module CLI
@@ -19,12 +19,12 @@ module Hanami
19
19
  #
20
20
  # @param out [IO] I/O stream for standard command output
21
21
  # @param err [IO] I/O stream for comment errror output
22
- # @param fs [Dry::Files] object for managing file system interactions
22
+ # @param fs [Hanami::CLI::Files] object for managing file system interactions
23
23
  # @param inflector [Dry::Inflector] inflector for any command-level inflections
24
24
  #
25
25
  # @since 2.0.0
26
26
  # @api public
27
- def initialize(out: $stdout, err: $stderr, fs: Dry::Files.new, inflector: Dry::Inflector.new)
27
+ def initialize(out: $stdout, err: $stderr, fs: Hanami::CLI::Files.new, inflector: Dry::Inflector.new)
28
28
  super()
29
29
  @out = out
30
30
  @err = err
@@ -52,7 +52,7 @@ module Hanami
52
52
 
53
53
  # Returns the object for managing file system interactions.
54
54
  #
55
- # @return [Dry::Files]
55
+ # @return [Hanami::CLI::Files]
56
56
  #
57
57
  # @since 2.0.0
58
58
  # @api public
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "shellwords"
4
+ require_relative "../command"
5
+ require_relative "../../../system_call"
6
+
7
+ module Hanami
8
+ module CLI
9
+ module Commands
10
+ module App
11
+ module Assets
12
+ # @since 2.1.0
13
+ # @api private
14
+ class Command < App::Command
15
+ def initialize(config: app.config.assets, system_call: SystemCall.new, **)
16
+ super()
17
+ @system_call = system_call
18
+ @config = config
19
+ end
20
+
21
+ # @since 2.1.0
22
+ # @api private
23
+ def call(**)
24
+ cmd, *args = cmd_with_args
25
+
26
+ system_call.call(cmd, *args, env: env)
27
+ end
28
+
29
+ private
30
+
31
+ # @since 2.1.0
32
+ # @api private
33
+ attr_reader :config
34
+
35
+ # @since 2.1.0
36
+ # @api private
37
+ attr_reader :system_call
38
+
39
+ # @since 2.1.0
40
+ # @api private
41
+ def cmd_with_args
42
+ [
43
+ config.package_manager_executable,
44
+ config.package_manager_command,
45
+ config.executable
46
+ ]
47
+ end
48
+
49
+ # @since 2.1.0
50
+ # @api private
51
+ def env
52
+ ENV.to_h.merge(
53
+ "ESBUILD_ENTRY_POINTS" => entry_points,
54
+ "ESBUILD_OUTDIR" => destination
55
+ )
56
+ end
57
+
58
+ # @since 2.1.0
59
+ # @api private
60
+ def entry_points
61
+ config.entry_points.map do |entry_point|
62
+ escape(entry_point)
63
+ end.join(" ")
64
+ end
65
+
66
+ # @since 2.1.0
67
+ # @api private
68
+ def destination
69
+ escape(config.destination)
70
+ end
71
+
72
+ # @since 2.1.0
73
+ # @api private
74
+ def escape(str)
75
+ Shellwords.shellescape(str)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "command"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Commands
8
+ module App
9
+ module Assets
10
+ # @since 2.1.0
11
+ # @api private
12
+ class Compile < Assets::Command
13
+ desc "Compile assets for deployments"
14
+
15
+ # @since 2.1.0
16
+ # @api private
17
+ def cmd_with_args
18
+ result = super
19
+
20
+ if config.subresource_integrity.any?
21
+ result << "--"
22
+ result << "--sri=#{config.subresource_integrity.join(',')}"
23
+ end
24
+
25
+ result
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "command"
4
+ require_relative "../../../interactive_system_call"
5
+
6
+ module Hanami
7
+ module CLI
8
+ module Commands
9
+ module App
10
+ module Assets
11
+ # @since 2.1.0
12
+ # @api private
13
+ class Watch < Assets::Command
14
+ desc "Start assets watch mode"
15
+
16
+ def initialize(config: app.config.assets, system_call: InteractiveSystemCall.new, **)
17
+ super(config: config, system_call: system_call)
18
+ end
19
+
20
+ private
21
+
22
+ # @since 2.1.0
23
+ # @api private
24
+ def cmd_with_args
25
+ super +
26
+ [
27
+ "--",
28
+ "--watch"
29
+ ]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module CLI
5
+ module Commands
6
+ module App
7
+ # @since 2.1.0
8
+ # @api private
9
+ module Assets
10
+ require_relative "assets/compile"
11
+ require_relative "assets/watch"
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "dry/files"
4
3
  require "hanami/env"
5
4
  require_relative "db/utils/database"
5
+ require_relative "../../files"
6
6
 
7
7
  module Hanami
8
8
  module CLI
@@ -75,7 +75,7 @@ module Hanami
75
75
  klass.new(
76
76
  out: out,
77
77
  inflector: app.inflector,
78
- fs: Dry::Files
78
+ fs: Hanami::CLI::Files,
79
79
  ).call(*args)
80
80
  end
81
81
 
@@ -20,12 +20,20 @@ module Hanami
20
20
  migration_code, migration_name = find_migration(target)
21
21
 
22
22
  if migration_name.nil?
23
- out.puts "==> migration file for target #{target} was not found"
23
+ output = if target
24
+ "==> migration file for target #{target} was not found"
25
+ else
26
+ "==> no migrations to rollback"
27
+ end
28
+
29
+ out.puts output
24
30
  return
25
31
  end
26
32
 
27
33
  measure "database #{database.name} rolled back to #{migration_name}" do
28
34
  database.run_migrations(target: Integer(migration_code))
35
+
36
+ true
29
37
  end
30
38
 
31
39
  run_command Structure::Dump if dump
@@ -33,14 +41,30 @@ module Hanami
33
41
 
34
42
  private
35
43
 
36
- def find_migration(code)
37
- migration = database.applied_migrations.then { |migrations|
44
+ def find_migration(code) # rubocop:disable Metrics/PerceivedComplexity
45
+ applied_migrations = database.applied_migrations
46
+
47
+ return if applied_migrations.empty?
48
+
49
+ # Rollback to initial state if we have only one migration and
50
+ # no target is specified. In this case the rollback target
51
+ # will be the current migration timestamp minus 1
52
+ if applied_migrations.one? && code.nil?
53
+ migration = applied_migrations.first
54
+
55
+ migration_code = Integer(migration.split("_").first) - 1
56
+ migration_name = "initial state"
57
+
58
+ return [migration_code, migration_name]
59
+ end
60
+
61
+ # Otherwise rollback to target or to previous migration
62
+ migration =
38
63
  if code
39
- migrations.detect { |m| m.split("_").first == code }
64
+ applied_migrations.detect { |m| m.split("_").first == code }
40
65
  else
41
- migrations.last
66
+ applied_migrations[-2]
42
67
  end
43
- }
44
68
 
45
69
  return unless migration
46
70
 
@@ -139,7 +139,11 @@ module Hanami
139
139
  @sequel_migrator ||= begin
140
140
  require "sequel"
141
141
  Sequel.extension :migration
142
- Sequel::TimestampMigrator.new(migrator.connection, migrations_path, {})
142
+
143
+ require "rom/sql"
144
+ ROM::SQL.with_gateway(gateway) do
145
+ Sequel::TimestampMigrator.new(migrator.connection, migrations_path, {})
146
+ end
143
147
  end
144
148
  end
145
149
 
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../interactive_system_call"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Commands
8
+ module App
9
+ # @since 2.1.0
10
+ # @api private
11
+ class Dev < App::Command
12
+ # @since 2.1.0
13
+ # @api private
14
+ desc "Start the application in development mode"
15
+
16
+ # @since 2.1.0
17
+ # @api private
18
+ option :procfile, type: :string, desc: "Path to Procfile", aliases: ["-f"]
19
+
20
+ # @since 2.1.0
21
+ # @api private
22
+ example [
23
+ "-f /path/to/Procfile",
24
+ ]
25
+
26
+ # @since 2.1.0
27
+ # @api private
28
+ def initialize(interactive_system_call: InteractiveSystemCall.new, **)
29
+ @interactive_system_call = interactive_system_call
30
+ super()
31
+ end
32
+
33
+ # @since 2.1.0
34
+ # @api private
35
+ def call(procfile: nil, **)
36
+ bin, args = executable(procfile: procfile)
37
+ interactive_system_call.call(bin, *args)
38
+ end
39
+
40
+ private
41
+
42
+ # @since 2.1.0
43
+ # @api private
44
+ attr_reader :interactive_system_call
45
+
46
+ # @since 2.1.0
47
+ # @api private
48
+ def executable(procfile: nil)
49
+ # TODO: support other implementations of Foreman
50
+ # See: https://github.com/ddollar/foreman#ports
51
+ ["foreman", ["start", "-f", procfile || "Procfile.dev"]]
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -26,8 +26,8 @@ module Hanami
26
26
  option :url, required: false, type: :string, desc: "Action URL"
27
27
  option :http, required: false, type: :string, desc: "Action HTTP method"
28
28
  # option :format, required: false, type: :string, default: DEFAULT_FORMAT, desc: "Template format"
29
- # option :skip_view, required: false, type: :boolean, default: DEFAULT_SKIP_VIEW,
30
- # desc: "Skip view and template generation"
29
+ option :skip_view, required: false, type: :boolean, default: DEFAULT_SKIP_VIEW,
30
+ desc: "Skip view and template generation"
31
31
  option :slice, required: false, desc: "Slice name"
32
32
 
33
33
  # rubocop:disable Layout/LineLength
@@ -60,7 +60,8 @@ module Hanami
60
60
 
61
61
  # @since 2.0.0
62
62
  # @api private
63
- def call(name:, url: nil, http: nil, format: DEFAULT_FORMAT, skip_view: DEFAULT_SKIP_VIEW, slice: nil, **)
63
+ def call(name:, url: nil, http: nil, format: DEFAULT_FORMAT, skip_view: DEFAULT_SKIP_VIEW, slice: nil,
64
+ context: nil, **)
64
65
  slice = inflector.underscore(Shellwords.shellescape(slice)) if slice
65
66
  name = naming.action_name(name)
66
67
  *controller, action = name.split(ACTION_SEPARATOR)
@@ -69,7 +70,7 @@ module Hanami
69
70
  raise InvalidActionNameError.new(name)
70
71
  end
71
72
 
72
- generator.call(app.namespace, controller, action, url, http, format, skip_view, slice)
73
+ generator.call(app.namespace, controller, action, url, http, format, skip_view, slice, context: context)
73
74
  end
74
75
 
75
76
  # rubocop:enable Metrics/ParameterLists
@@ -0,0 +1,57 @@
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.0.0
15
+ # @api private
16
+ class View < App::Command
17
+ # TODO: make this configurable
18
+ DEFAULT_FORMAT = "html"
19
+ private_constant :DEFAULT_FORMAT
20
+
21
+ # TODO: make engine configurable
22
+
23
+ argument :name, required: true, desc: "View name"
24
+ option :slice, required: false, desc: "Slice name"
25
+
26
+ example [
27
+ %(books.index (MyApp::Actions::Books::Index)),
28
+ %(books.index --slice=admin (Admin::Actions::Books::Index)),
29
+ ]
30
+ attr_reader :generator
31
+ private :generator
32
+
33
+ # @since 2.0.0
34
+ # @api private
35
+ def initialize(
36
+ fs: Hanami::CLI::Files.new,
37
+ inflector: Dry::Inflector.new,
38
+ generator: Generators::App::View.new(fs: fs, inflector: inflector),
39
+ **
40
+ )
41
+ @generator = generator
42
+ super(fs: fs)
43
+ end
44
+
45
+ # @since 2.0.0
46
+ # @api private
47
+ def call(name:, format: DEFAULT_FORMAT, slice: nil, **)
48
+ slice = inflector.underscore(Shellwords.shellescape(slice)) if slice
49
+
50
+ generator.call(app.namespace, name, format, slice)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -7,8 +7,8 @@ module Hanami
7
7
  # @since 2.0.0
8
8
  # @api private
9
9
  module Generate
10
- require_relative "./generate/slice"
11
- require_relative "./generate/action"
10
+ require_relative "generate/slice"
11
+ require_relative "generate/action"
12
12
  end
13
13
  end
14
14
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../../system_call"
4
+
3
5
  module Hanami
4
6
  module CLI
5
7
  module Commands
@@ -18,9 +20,50 @@ module Hanami
18
20
  # @since 2.0.0
19
21
  # @api private
20
22
  class Install < Command
23
+ # @since 2.1.0
24
+ # @api private
25
+ DEFAULT_HEAD = false
26
+ private_constant :DEFAULT_HEAD
27
+
28
+ # @since 2.1.0
29
+ # @api private
21
30
  desc "Install Hanami third-party plugins"
22
31
 
23
- def call(*)
32
+ # @since 2.1.0
33
+ # @api private
34
+ option :head, type: :boolean, desc: "Install head deps", default: DEFAULT_HEAD
35
+
36
+ # @since 2.1.0
37
+ # @api private
38
+ def initialize(system_call: SystemCall.new, **)
39
+ @system_call = system_call
40
+ super()
41
+ end
42
+
43
+ # @since 2.0.0
44
+ # @api private
45
+ def call(head: DEFAULT_HEAD, **)
46
+ install_hanami_assets!(head: head)
47
+ end
48
+
49
+ private
50
+
51
+ # @since 2.1.0
52
+ # @api private
53
+ attr_reader :system_call
54
+
55
+ # @since 2.1.0
56
+ # @api private
57
+ def install_hanami_assets!(head:)
58
+ return unless Hanami.bundled?("hanami-assets")
59
+
60
+ system_call.call("npm", ["init", "-y"])
61
+
62
+ if head
63
+ system_call.call("npm", %w[install https://github.com/hanami/assets-js])
64
+ else
65
+ system_call.call("npm", %w[install hanami-assets])
66
+ end
24
67
  end
25
68
  end
26
69
  end