hanami-cli 2.1.0.beta1 → 2.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/Gemfile +5 -2
  4. data/hanami-cli.gemspec +1 -1
  5. data/lib/hanami/cli/bundler.rb +19 -5
  6. data/lib/hanami/cli/command.rb +4 -4
  7. data/lib/hanami/cli/commands/app/assets/command.rb +69 -0
  8. data/lib/hanami/cli/commands/app/assets/compile.rb +32 -0
  9. data/lib/hanami/cli/commands/app/assets/watch.rb +32 -0
  10. data/lib/hanami/cli/commands/app/assets.rb +16 -0
  11. data/lib/hanami/cli/commands/app/command.rb +2 -2
  12. data/lib/hanami/cli/commands/app/dev.rb +45 -0
  13. data/lib/hanami/cli/commands/app/generate/action.rb +3 -2
  14. data/lib/hanami/cli/commands/app/generate/part.rb +49 -0
  15. data/lib/hanami/cli/commands/app/install.rb +16 -1
  16. data/lib/hanami/cli/commands/app.rb +9 -0
  17. data/lib/hanami/cli/commands/gem/new.rb +57 -7
  18. data/lib/hanami/cli/errors.rb +30 -0
  19. data/lib/hanami/cli/files.rb +8 -2
  20. data/lib/hanami/cli/generators/app/action/action.erb +5 -1
  21. data/lib/hanami/cli/generators/app/action/slice_action.erb +5 -1
  22. data/lib/hanami/cli/generators/app/action.rb +49 -12
  23. data/lib/hanami/cli/generators/app/part/app_base_part.erb +9 -0
  24. data/lib/hanami/cli/generators/app/part/app_part.erb +13 -0
  25. data/lib/hanami/cli/generators/app/part/slice_base_part.erb +9 -0
  26. data/lib/hanami/cli/generators/app/part/slice_part.erb +13 -0
  27. data/lib/hanami/cli/generators/app/part.rb +101 -0
  28. data/lib/hanami/cli/generators/app/part_context.rb +98 -0
  29. data/lib/hanami/cli/generators/app/slice/app_css.erb +5 -0
  30. data/lib/hanami/cli/generators/app/slice/app_js.erb +1 -0
  31. data/lib/hanami/cli/generators/app/slice/app_layout.erb +18 -0
  32. data/lib/hanami/cli/generators/app/slice.rb +9 -3
  33. data/lib/hanami/cli/generators/app/slice_context.rb +18 -0
  34. data/lib/hanami/cli/generators/context.rb +70 -3
  35. data/lib/hanami/cli/generators/gem/app/404.html +76 -5
  36. data/lib/hanami/cli/generators/gem/app/500.html +76 -5
  37. data/lib/hanami/cli/generators/gem/app/app_css.erb +5 -0
  38. data/lib/hanami/cli/generators/gem/app/app_js.erb +1 -0
  39. data/lib/hanami/cli/generators/gem/app/app_layout.erb +18 -0
  40. data/lib/hanami/cli/generators/gem/app/assets.mjs +14 -0
  41. data/lib/hanami/cli/generators/gem/app/dev +8 -0
  42. data/lib/hanami/cli/generators/gem/app/favicon.ico +0 -0
  43. data/lib/hanami/cli/generators/gem/app/gemfile.erb +14 -8
  44. data/lib/hanami/cli/generators/gem/app/gitignore.erb +4 -0
  45. data/lib/hanami/cli/generators/gem/app/package.json.erb +10 -0
  46. data/lib/hanami/cli/generators/gem/app/procfile.erb +4 -0
  47. data/lib/hanami/cli/generators/gem/app/puma.erb +37 -7
  48. data/lib/hanami/cli/generators/gem/app/routes.erb +1 -1
  49. data/lib/hanami/cli/generators/gem/app.rb +21 -4
  50. data/lib/hanami/cli/generators/version.rb +12 -0
  51. data/lib/hanami/cli/interactive_system_call.rb +64 -0
  52. data/lib/hanami/cli/system_call.rb +8 -2
  53. data/lib/hanami/cli/version.rb +1 -1
  54. metadata +28 -6
  55. data/lib/hanami/cli/generators/app/slice/layouts_app.html.erb +0 -1
  56. data/lib/hanami/cli/generators/gem/app/layouts_app.html.erb +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '078a7a10f1196ed8635a9c27ee48ac10178cdcff50d2646138f61b55f79f86a7'
4
- data.tar.gz: 870c056fc5da9f5952daf357ca2861f0e276510c6ca1e63a2f821af76ebdd09a
3
+ metadata.gz: '054178514bf7e420e00cd8da8a148cd4d479609668c180507fadbcd7a086f15d'
4
+ data.tar.gz: 3ef8c388ad8c8734179ce042d3eb966dea6df881b72e7615f0b104a1890106a5
5
5
  SHA512:
6
- metadata.gz: d70ee9d87779f442c25517abfefde102460848e8a29ba9ef30ae28cc2b2593f73027dad42b99e5617820952a84fd22013a8de5d039fb2e6161a64fd2eef706a1
7
- data.tar.gz: 815418cd1c416bea1f7a77c56dff20ed143b582795bbcd79904260509c8c62c7d62a7be76c11305d26dc793dd2c2a13fcba0532c365ad47278212159e40eff69
6
+ metadata.gz: c8e1abc0ded22d56ee2acd5dec6d9f7079c0331d187b1d4ff4b26858faf50ff870016e1adfa6b785673d39b6d0dcf097dca7c1b0526da442e1939ce0952f3799
7
+ data.tar.gz: 8ecc3ceefc10856cbd2f60ec24bd1ecde442764610dbb7d179f064080ac434fa4829374efb05513c67420ab8b76b0280ad594fd566824fdfba0e8d14afc209fb
data/CHANGELOG.md CHANGED
@@ -2,6 +2,43 @@
2
2
 
3
3
  Hanami Command Line Interface
4
4
 
5
+ ## v2.1.0.rc1 - 2023-11-01
6
+
7
+ ### Added
8
+
9
+ - [Tim Riley] `hanami new` to generate `bin/dev` as configuration for `hanami dev`
10
+ - [Luca Guidi] Introducing `hanami generate part` to generate view parts
11
+
12
+ ### Fixed
13
+
14
+ - [Luca Guidi] `hanami new` generates a fully documented Puma configuration in `config/puma.rb`
15
+
16
+ ### Changed
17
+
18
+ - [Tim Riley] `hanami new` generates a `config/assets.mjs` as Assets configuration
19
+ - [Tim Riley] `hanami new` generates a leaner `package.json`
20
+ - [Tim Riley] `hanami new` doesn't generate a default root route anymore
21
+ - [Aaron Moodie & Tim Riley] `hanami new` to generate a redesigned 404 and 500 error pages
22
+ - [Luca Guidi] When generating a RESTful action, skip `create`, if `new` is present, and `update`, if `edit` is present
23
+
24
+ ## v2.1.0.beta2 - 2023-10-04
25
+
26
+ ### Added
27
+
28
+ - [Luca Guidi] `hanami new` generates `Procfile.dev`
29
+ - [Luca Guidi] `hanami new` generates basic app assets, if `hanami-assets` is bundled by the app
30
+ - [Luca Guidi] `hanami new` accepts `--head` to generate the app using Hanami HEAD version from GitHub
31
+ - [Luca Guidi] `hanami generate slice` generates basic slice assets, if `hanami-assets` is bundled by the app
32
+ - [Ryan Bigg] `hanami generate action` generates corresponding view, if `hanami-view` is bundled by the app
33
+ - [Luca Guidi] `hanami assets compile` to compile assets at the deploy time
34
+ - [Luca Guidi] `hanami assets watch` to watch and compile assets at the development time
35
+ - [Luca Guidi] `hanami dev` to start the processes in `Procfile.dev`
36
+
37
+ ### Fixed
38
+
39
+ - [Luca Guidi] `hanami new` generates a `Gemfile` with `hanami-webconsole` in `:development` group
40
+ - [Luca Guidi] `hanami new` generates a `Gemfile` with versioned `hanami-webconsole`, `hanami-rspec`, and `hanami-reloader`
41
+
5
42
  ## v2.1.0.beta1 - 2023-06-29
6
43
 
7
44
  ### Added
data/Gemfile CHANGED
@@ -10,9 +10,12 @@ 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"
17
+
18
+ gem "dry-files", github: "dry-rb/dry-files", branch: "main"
16
19
 
17
20
  gem "rack"
18
21
 
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,7 +3,7 @@
3
3
  require "bundler"
4
4
  require "open3"
5
5
  require "etc"
6
- require "dry/files"
6
+ require_relative "files"
7
7
  require_relative "system_call"
8
8
  require_relative "errors"
9
9
 
@@ -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,69 @@
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)
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
+ [config.package_manager_run_command, "assets"]
43
+ end
44
+
45
+ # @since 2.1.0
46
+ # @api private
47
+ def entry_points
48
+ config.entry_points.map do |entry_point|
49
+ escape(entry_point)
50
+ end.join(" ")
51
+ end
52
+
53
+ # @since 2.1.0
54
+ # @api private
55
+ def destination
56
+ escape(config.destination)
57
+ end
58
+
59
+ # @since 2.1.0
60
+ # @api private
61
+ def escape(str)
62
+ Shellwords.shellescape(str)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ 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,32 @@
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 + ["--", "--watch"]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ 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
 
@@ -0,0 +1,45 @@
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
+ def initialize(interactive_system_call: InteractiveSystemCall.new, **)
19
+ @interactive_system_call = interactive_system_call
20
+ super()
21
+ end
22
+
23
+ # @since 2.1.0
24
+ # @api private
25
+ def call(**)
26
+ bin, args = executable
27
+ interactive_system_call.call(bin, *args)
28
+ end
29
+
30
+ private
31
+
32
+ # @since 2.1.0
33
+ # @api private
34
+ attr_reader :interactive_system_call
35
+
36
+ # @since 2.1.0
37
+ # @api private
38
+ def executable
39
+ [::File.join("bin", "dev")]
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -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,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/inflector"
4
+ require "dry/files"
5
+ require "shellwords"
6
+
7
+ module Hanami
8
+ module CLI
9
+ module Commands
10
+ module App
11
+ module Generate
12
+ # @since 2.1.0
13
+ # @api private
14
+ class Part < App::Command
15
+ argument :name, required: true, desc: "Part name"
16
+ option :slice, required: false, desc: "Slice name"
17
+
18
+ example [
19
+ %(book (MyApp::Views::Parts::Book)),
20
+ %(book --slice=admin (Admin::Views::Parts::Book)),
21
+ ]
22
+ attr_reader :generator
23
+ private :generator
24
+
25
+ # @since 2.0.0
26
+ # @api private
27
+ def initialize(
28
+ fs: Hanami::CLI::Files.new,
29
+ inflector: Dry::Inflector.new,
30
+ generator: Generators::App::Part.new(fs: fs, inflector: inflector),
31
+ **
32
+ )
33
+ @generator = generator
34
+ super(fs: fs)
35
+ end
36
+
37
+ # @since 2.0.0
38
+ # @api private
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
@@ -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,22 @@ 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.0.0
37
+ # @api private
38
+ def call(head: DEFAULT_HEAD, **)
24
39
  end
25
40
  end
26
41
  end
@@ -14,15 +14,24 @@ module Hanami
14
14
  base.module_eval do
15
15
  register "version", Commands::App::Version, aliases: ["v", "-v", "--version"]
16
16
  register "install", Commands::App::Install
17
+ register "dev", Commands::App::Dev
17
18
  register "console", Commands::App::Console, aliases: ["c"]
18
19
  register "server", Commands::App::Server, aliases: ["s"]
19
20
  register "routes", Commands::App::Routes
20
21
  register "middleware", Commands::App::Middleware
21
22
 
23
+ if Hanami.bundled?("hanami-assets")
24
+ register "assets" do |prefix|
25
+ prefix.register "compile", Assets::Compile
26
+ prefix.register "watch", Assets::Watch
27
+ end
28
+ end
29
+
22
30
  register "generate", aliases: ["g"] do |prefix|
23
31
  prefix.register "slice", Generate::Slice
24
32
  prefix.register "action", Generate::Action
25
33
  prefix.register "view", Generate::View
34
+ prefix.register "part", Generate::Part
26
35
  end
27
36
  end
28
37
  end
@@ -10,21 +10,55 @@ module Hanami
10
10
  # @since 2.0.0
11
11
  # @api private
12
12
  class New < Command
13
+ # @since 2.0.0
14
+ # @api private
13
15
  SKIP_INSTALL_DEFAULT = false
14
16
  private_constant :SKIP_INSTALL_DEFAULT
15
17
 
18
+ # @since 2.1.0
19
+ # @api private
20
+ HEAD_DEFAULT = false
21
+ private_constant :HEAD_DEFAULT
22
+
23
+ # @since 2.1.0
24
+ # @api private
25
+ SKIP_ASSETS_DEFAULT = false
26
+ private_constant :SKIP_ASSETS_DEFAULT
27
+
16
28
  desc "Generate a new Hanami app"
17
29
 
30
+ # @since 2.0.0
31
+ # @api private
18
32
  argument :app, required: true, desc: "App name"
19
33
 
34
+ # @since 2.0.0
35
+ # @api private
20
36
  option :skip_install, type: :boolean, required: false,
21
37
  default: SKIP_INSTALL_DEFAULT,
22
38
  desc: "Skip app installation (Bundler, third-party Hanami plugins)"
23
39
 
40
+ # @since 2.1.0
41
+ # @api private
42
+ option :head, type: :boolean, required: false,
43
+ default: HEAD_DEFAULT,
44
+ desc: "Use Hanami HEAD version (from GitHub `main` branches)"
45
+
46
+ # @since 2.1.0
47
+ # @api private
48
+ option :skip_assets, type: :boolean, required: false,
49
+ default: SKIP_ASSETS_DEFAULT,
50
+ desc: "Skip assets"
51
+
52
+ # rubocop:disable Layout/LineLength
24
53
  example [
25
- "bookshelf # Generate a new Hanami app in `bookshelf/' directory, using `Bookshelf' namespace", # rubocop:disable Layout/LineLength
26
- "bookshelf --skip-install # Generate a new Hanami app, but it skips Hanami installation"
54
+ "bookshelf # Generate a new Hanami app in `bookshelf/' directory, using `Bookshelf' namespace",
55
+ "bookshelf --head # Generate a new Hanami app, using Hanami HEAD version from GitHub `main' branches",
56
+ "bookshelf --skip-install # Generate a new Hanami app, but it skips Hanami installation",
57
+ "bookshelf --skip-assets # Generate a new Hanami app without assets"
27
58
  ]
59
+ # rubocop:enable Layout/LineLength
60
+
61
+ # rubocop:disable Metrics/ParameterLists
28
62
 
29
63
  # @since 2.0.0
30
64
  # @api private
@@ -33,42 +67,58 @@ module Hanami
33
67
  inflector: Dry::Inflector.new,
34
68
  bundler: CLI::Bundler.new(fs: fs),
35
69
  generator: Generators::Gem::App.new(fs: fs, inflector: inflector),
70
+ system_call: SystemCall.new,
36
71
  **other
37
72
  )
38
73
  @bundler = bundler
39
74
  @generator = generator
75
+ @system_call = system_call
40
76
  super(fs: fs, inflector: inflector, **other)
41
77
  end
42
78
 
79
+ # rubocop:enable Metrics/ParameterLists
80
+
81
+ # rubocop:disable Metrics/AbcSize
82
+
43
83
  # @since 2.0.0
44
84
  # @api private
45
- def call(app:, skip_install: SKIP_INSTALL_DEFAULT, **)
85
+ def call(app:, head: HEAD_DEFAULT, skip_install: SKIP_INSTALL_DEFAULT, skip_assets: SKIP_ASSETS_DEFAULT, **)
46
86
  app = inflector.underscore(app)
47
87
 
48
88
  raise PathAlreadyExistsError.new(app) if fs.exist?(app)
49
89
 
50
90
  fs.mkdir(app)
51
91
  fs.chdir(app) do
52
- generator.call(app) do
92
+ context = Generators::Context.new(inflector, app, head: head, skip_assets: skip_assets)
93
+ generator.call(app, context: context) do
53
94
  if skip_install
54
95
  out.puts "Skipping installation, please enter `#{app}' directory and run `bundle exec hanami install'"
55
96
  else
56
97
  out.puts "Running Bundler install..."
57
98
  bundler.install!
99
+
100
+ unless skip_assets
101
+ out.puts "Running npm install..."
102
+ system_call.call("npm", ["install"])
103
+ end
104
+
58
105
  out.puts "Running Hanami install..."
59
- run_install_commmand!
106
+ run_install_commmand!(head: head)
60
107
  end
61
108
  end
62
109
  end
63
110
  end
111
+ # rubocop:enable Metrics/AbcSize
64
112
 
65
113
  private
66
114
 
67
115
  attr_reader :bundler
68
116
  attr_reader :generator
117
+ attr_reader :system_call
69
118
 
70
- def run_install_commmand!
71
- bundler.exec("hanami install").tap do |result|
119
+ def run_install_commmand!(head:)
120
+ head_flag = head ? " --head" : ""
121
+ bundler.exec("hanami install#{head_flag}").tap do |result|
72
122
  raise HanamiInstallError.new(result.err) unless result.successful?
73
123
  end
74
124
  end