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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +18 -13
  3. data/CHANGELOG.md +21 -0
  4. data/Gemfile +4 -2
  5. data/README.md +11 -7
  6. data/docker-compose.yml +9 -0
  7. data/hanami-cli.gemspec +2 -2
  8. data/lib/hanami/cli/command.rb +1 -1
  9. data/lib/hanami/cli/commands/app/assets/command.rb +1 -1
  10. data/lib/hanami/cli/commands/app/command.rb +2 -16
  11. data/lib/hanami/cli/commands/app/db/command.rb +116 -0
  12. data/lib/hanami/cli/commands/app/db/create.rb +19 -11
  13. data/lib/hanami/cli/commands/app/db/drop.rb +19 -10
  14. data/lib/hanami/cli/commands/app/db/migrate.rb +19 -13
  15. data/lib/hanami/cli/commands/app/db/prepare.rb +42 -0
  16. data/lib/hanami/cli/commands/app/db/seed.rb +11 -22
  17. data/lib/hanami/cli/commands/app/db/structure/dump.rb +30 -7
  18. data/lib/hanami/cli/commands/app/db/structure/load.rb +52 -0
  19. data/lib/hanami/cli/commands/app/db/utils/database.rb +68 -73
  20. data/lib/hanami/cli/commands/app/db/utils/mysql.rb +2 -2
  21. data/lib/hanami/cli/commands/app/db/utils/postgres.rb +38 -19
  22. data/lib/hanami/cli/commands/app/db/utils/sqlite.rb +58 -10
  23. data/lib/hanami/cli/commands/app/db/version.rb +12 -9
  24. data/lib/hanami/cli/commands/app/generate/action.rb +4 -3
  25. data/lib/hanami/cli/commands/app/generate/command.rb +49 -0
  26. data/lib/hanami/cli/commands/app/generate/component.rb +49 -0
  27. data/lib/hanami/cli/commands/app/generate/migration.rb +27 -0
  28. data/lib/hanami/cli/commands/app/generate/operation.rb +26 -0
  29. data/lib/hanami/cli/commands/app/generate/part.rb +1 -1
  30. data/lib/hanami/cli/commands/app/generate/relation.rb +35 -0
  31. data/lib/hanami/cli/commands/app/generate/repo.rb +46 -0
  32. data/lib/hanami/cli/commands/app/generate/slice.rb +20 -3
  33. data/lib/hanami/cli/commands/app/generate/struct.rb +27 -0
  34. data/lib/hanami/cli/commands/app/install.rb +1 -1
  35. data/lib/hanami/cli/commands/app/middleware.rb +1 -1
  36. data/lib/hanami/cli/commands/app/server.rb +2 -2
  37. data/lib/hanami/cli/commands/app.rb +21 -2
  38. data/lib/hanami/cli/commands/gem/new.rb +78 -14
  39. data/lib/hanami/cli/errors.rb +28 -0
  40. data/lib/hanami/cli/generators/app/action/slice_action.erb +1 -1
  41. data/lib/hanami/cli/generators/app/action_context.rb +5 -13
  42. data/lib/hanami/cli/generators/app/component/component.erb +8 -0
  43. data/lib/hanami/cli/generators/app/component/slice_component.erb +8 -0
  44. data/lib/hanami/cli/generators/app/component.rb +61 -0
  45. data/lib/hanami/cli/generators/app/component_context.rb +82 -0
  46. data/lib/hanami/cli/generators/app/migration.rb +69 -0
  47. data/lib/hanami/cli/generators/app/operation.rb +48 -0
  48. data/lib/hanami/cli/generators/app/part_context.rb +5 -21
  49. data/lib/hanami/cli/generators/app/relation.rb +44 -0
  50. data/lib/hanami/cli/generators/app/repo.rb +40 -0
  51. data/lib/hanami/cli/generators/app/ruby_file_writer.rb +149 -0
  52. data/lib/hanami/cli/generators/app/slice/operation.erb +7 -0
  53. data/lib/hanami/cli/generators/app/slice/relation.erb +8 -0
  54. data/lib/hanami/cli/generators/app/slice/{slice.erb → repo.erb} +3 -1
  55. data/lib/hanami/cli/generators/app/slice/struct.erb +8 -0
  56. data/lib/hanami/cli/generators/app/slice.rb +14 -6
  57. data/lib/hanami/cli/generators/app/slice_context.rb +9 -2
  58. data/lib/hanami/cli/generators/app/struct.rb +39 -0
  59. data/lib/hanami/cli/generators/app/view_context.rb +4 -16
  60. data/lib/hanami/cli/generators/constants.rb +39 -0
  61. data/lib/hanami/cli/generators/context.rb +48 -0
  62. data/lib/hanami/cli/generators/gem/app/action.erb +3 -0
  63. data/lib/hanami/cli/generators/gem/app/env.erb +4 -0
  64. data/lib/hanami/cli/generators/gem/app/gemfile.erb +11 -0
  65. data/lib/hanami/cli/generators/gem/app/gitignore.erb +1 -1
  66. data/lib/hanami/cli/generators/gem/app/operation.erb +13 -0
  67. data/lib/hanami/cli/generators/gem/app/relation.erb +10 -0
  68. data/lib/hanami/cli/generators/gem/app/repo.erb +10 -0
  69. data/lib/hanami/cli/generators/gem/app/struct.erb +10 -0
  70. data/lib/hanami/cli/generators/gem/app.rb +19 -0
  71. data/lib/hanami/cli/ruby_file_generator.rb +123 -0
  72. data/lib/hanami/cli/version.rb +1 -1
  73. metadata +39 -16
  74. data/lib/hanami/cli/commands/app/db/create_migration.rb +0 -32
  75. data/lib/hanami/cli/commands/app/db/reset.rb +0 -28
  76. data/lib/hanami/cli/commands/app/db/rollback.rb +0 -81
  77. data/lib/hanami/cli/commands/app/db/sample_data.rb +0 -42
  78. data/lib/hanami/cli/commands/app/db/setup.rb +0 -26
  79. data/lib/hanami/cli/commands/app/db/utils/database_config.rb +0 -60
  80. data/lib/hanami/cli/generators/app/slice/repository.erb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0885d4f1e10f7f8bd8691c04524be0f6353de0b0a7ce19c2ecf42ae31c8f8cd
4
- data.tar.gz: d6c27d7571896e9f93d2ab41206e50f922fdfecc892ccf3d2328f9123c6d2348
3
+ metadata.gz: eda4f18125d25c640cbb75e50a7e636b93e29badd50f6540b37c6fc55bb7cb98
4
+ data.tar.gz: 2d0f39b520d19a39866ccc354d40c1e9536f9b2c77d2ead33f340ddc64d899ef
5
5
  SHA512:
6
- metadata.gz: 74180e374ac3836550e622af10dc998bc5356d3a745c2b0731ef2f03e2bc06f639ab5c375d7d53e7dc67fe40672eb80c38b77bb5cc6111d52d9a20da415de222
7
- data.tar.gz: 94596b8dd6f53f2dc6d53f37bfcec37b5002324ef85715c9791b94ebb0fa198884c8acf7d339752e9bb11b0da9f8fbddb4fa5f89ec62fb49944af8cc8732087d
6
+ metadata.gz: 07052611a88815d7ffc2e228d77b62a65cc708283688c13e3509d3004a186b264d4271e104e8e3dea4dfae52958ccf9e385bc1a95c5c9b732e985538c82bfc7f
7
+ data.tar.gz: e6d3c5e3290fb2c19b6a301e11b20d70eb376a5c4da42ed69f7ceafa1590f5b14955b4cc9ce8bc0ad155e1db0ec3851aae06da43849d43441fe282cd94dd9860
@@ -27,15 +27,9 @@ jobs:
27
27
  - "3.3"
28
28
  - "3.2"
29
29
  - "3.1"
30
- - "3.0"
30
+ env:
31
+ POSTGRES_BASE_URL: postgres://postgres:password@localhost:5432/hanami_cli_test
31
32
  steps:
32
- - uses: ravsamhq/notify-slack-action@v1
33
- if: always()
34
- with:
35
- status: ${{ job.status }}
36
- notify_when: "failure"
37
- env:
38
- SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
39
33
  - uses: actions/checkout@v1
40
34
  - name: Install package dependencies
41
35
  run: "[ -e $APT_DEPS ] || sudo apt-get install -y --no-install-recommends $APT_DEPS"
@@ -43,10 +37,21 @@ jobs:
43
37
  uses: ruby/setup-ruby@v1
44
38
  with:
45
39
  ruby-version: ${{matrix.ruby}}
46
- - name: Install latest bundler
47
- run: |
48
- gem install bundler --no-document
49
- - name: Bundle install
50
- run: bundle install --jobs 4 --retry 3
40
+ bundler-cache: true
51
41
  - name: Run all tests
52
42
  run: bundle exec rake spec
43
+ services:
44
+ postgres:
45
+ # Use postgres:14 for CLI compatibility with ubuntu-latest, currently ubuntu-22.04
46
+ # See https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md
47
+ image: postgres:14
48
+ env:
49
+ POSTGRES_USER: postgres
50
+ POSTGRES_PASSWORD: password
51
+ options: >-
52
+ --health-cmd pg_isready
53
+ --health-interval 10s
54
+ --health-timeout 5s
55
+ --health-retries 5
56
+ ports:
57
+ - 5432:5432
data/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  Hanami Command Line Interface
4
4
 
5
+ ## v2.2.0.beta1 - 2024-07-16
6
+
7
+ ## Added
8
+
9
+ - [Sean Collins] Generate db files in `hanami new` and `generate slice`
10
+ - [Tim Riley] Add `db` commands: `create`, `drop`, `migrate`, `structure dump` `structure load`, `seed` `prepare`, `version`
11
+ - [Tim Riley] Support SQLite and Postgres for `db` commands
12
+ - [Sean Collins] Add `generate` commands for db components: `generate migration`, `generate relation`, `generate repo`, `generate struct`
13
+ - [Krzysztof] Add `generate component` command
14
+ - [Sean Collins] Add `generate operation` command
15
+
16
+ ## Changed
17
+
18
+ - Drop support for Ruby 3.0
19
+
20
+ ## v2.1.1 - 2024-03-19
21
+
22
+ ### Fixed
23
+
24
+ - [Ryan Bigg] Properly pass INT signal to child processes when interrupting `hanami assets watch` command
25
+
5
26
  ## v2.1.0 - 2024-02-27
6
27
 
7
28
  ### Changed
data/Gemfile CHANGED
@@ -12,13 +12,15 @@ end
12
12
  gem "hanami", github: "hanami/hanami", branch: "main"
13
13
  gem "hanami-assets", github: "hanami/assets", branch: "main"
14
14
  gem "hanami-controller", github: "hanami/controller", branch: "main"
15
+ gem "hanami-db", github: "hanami/db", branch: "main"
15
16
  gem "hanami-router", github: "hanami/router", branch: "main"
16
17
  gem "hanami-utils", github: "hanami/utils", branch: "main"
17
18
 
18
- gem "dry-files", github: "dry-rb/dry-files", branch: "main"
19
-
20
19
  gem "rack"
21
20
 
21
+ gem "pg"
22
+ gem "sqlite3"
23
+
22
24
  gem "hanami-devtools", github: "hanami/devtools", branch: "main"
23
25
 
24
26
  group :test do
data/README.md CHANGED
@@ -1,13 +1,15 @@
1
1
  # Hanami::CLI
2
2
 
3
- CLI commands for [full-stack Hanami applications](`https://github.com/hanami/hanami`).
3
+ This library contains all of the CLI commands for [full-stack Hanami applications](`https://github.com/hanami/hanami`).
4
4
 
5
- **NOTE**: For versions 0.4 and below, there was a general purpose CLI utility library with this same name. That library has since been renamed to [dry-rb/dry-cli](https://github.com/dry-rb/dry-cli). Please update your Gemfiles accordingly.
5
+ **NOTE**: For versions 0.4 and below, there was a general purpose CLI utility library with this name.
6
+ That library has since been renamed to [dry-rb/dry-cli](https://github.com/dry-rb/dry-cli).
7
+ Please update your Gemfiles accordingly.
6
8
 
7
9
  ## Status
8
10
 
9
11
  [![Gem Version](https://badge.fury.io/rb/hanami-cli.svg)](https://badge.fury.io/rb/hanami-cli)
10
- [![CI](https://github.com/hanami/cli/workflows/ci/badge.svg?branch=main)](https://github.com/hanami/cli/actions?query=workflow%3Aci+branch%3Amain)
12
+ [![CI](https://github.com/hanami/cli/actions/workflows/ci.yml/badge.svg)](https://github.com/hanami/cli/actions?query=workflow%3Aci+branch%3Amain)
11
13
  [![Depfu](https://badges.depfu.com/badges/a8545fb67cf32a2c75b6227bc0821027/overview.svg)](https://depfu.com/github/hanami/cli?project=Bundler)
12
14
 
13
15
  ## Contact
@@ -15,12 +17,14 @@ CLI commands for [full-stack Hanami applications](`https://github.com/hanami/han
15
17
  - Home page: http://hanamirb.org
16
18
  - Mailing List: http://hanamirb.org/mailing-list
17
19
  - Bugs/Issues: https://github.com/hanami/cli/issues
18
- - Support: http://stackoverflow.com/questions/tagged/hanami
20
+ - API Doc: http://rubydoc.info/gems/hanami-cli
19
21
  - Chat: http://chat.hanamirb.org
20
22
 
21
- ## Rubies
23
+ ## Installation
22
24
 
23
- **Hanami::RSpec** supports Ruby (MRI) 3.0+
25
+ **Hanami::CLI** supports Ruby (MRI) 3.1+
26
+
27
+ This library is a dependency of the main `hanami` gem, so installing that is the best way to get and use this gem.
24
28
 
25
29
  ## Usage
26
30
 
@@ -44,4 +48,4 @@ Everyone interacting in the `Hanami::CLI` project's codebases, issue trackers, c
44
48
 
45
49
  ## Copyright
46
50
 
47
- Copyright © 2014 Hanami Team – Released under MIT License
51
+ Copyright © 2014–2024 Hanami Team – Released under MIT License
@@ -0,0 +1,9 @@
1
+ version: "2"
2
+ services:
3
+ postgres:
4
+ image: postgres:latest
5
+ ports:
6
+ - 5433:5432
7
+ environment:
8
+ POSTGRES_USER: postgres
9
+ POSTGRES_PASSWORD: password
data/hanami-cli.gemspec CHANGED
@@ -28,10 +28,10 @@ Gem::Specification.new do |spec|
28
28
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
29
  spec.require_paths = ["lib"]
30
30
  spec.metadata["rubygems_mfa_required"] = "true"
31
- spec.required_ruby_version = ">= 3.0"
31
+ spec.required_ruby_version = ">= 3.1"
32
32
 
33
33
  spec.add_dependency "bundler", "~> 2.1"
34
- spec.add_dependency "dry-cli", "~> 1.0", "< 2"
34
+ spec.add_dependency "dry-cli", "~> 1.0", ">= 1.1.0"
35
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"
@@ -27,7 +27,7 @@ module Hanami
27
27
  inflector: Dry::Inflector.new,
28
28
  **opts
29
29
  )
30
- super(out: out, err: err, fs: fs, inflector: inflector, **opts)
30
+ super
31
31
  end
32
32
 
33
33
  # Returns a new command.
@@ -62,7 +62,7 @@ module Hanami
62
62
 
63
63
  Signal.trap("INT") do
64
64
  pids.each do |pid|
65
- Process.kill(sig, pid)
65
+ Process.kill("INT", pid)
66
66
  end
67
67
  end
68
68
 
@@ -71,12 +71,12 @@ module Hanami
71
71
  #
72
72
  # @since 2.0.0
73
73
  # @api public
74
- def run_command(klass, *args)
74
+ def run_command(klass, ...)
75
75
  klass.new(
76
76
  out: out,
77
77
  inflector: app.inflector,
78
78
  fs: Hanami::CLI::Files,
79
- ).call(*args)
79
+ ).call(...)
80
80
  end
81
81
 
82
82
  # Executes a given block and prints string to the `out` stream with details of the time
@@ -111,20 +111,6 @@ module Hanami
111
111
  out.puts "!!! => #{desc.inspect} FAILED"
112
112
  end
113
113
  end
114
-
115
- # This is NOT AVAILABLE as of the 2.0.0 release.
116
- #
117
- # @api private
118
- def database
119
- @database ||= Commands::App::DB::Utils::Database[app]
120
- end
121
-
122
- # This is NOT AVAILABLE as of the 2.0.0 release.
123
- #
124
- # @api private
125
- def database_config
126
- database.config
127
- end
128
114
  end
129
115
  end
130
116
  end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "shellwords"
4
+ require_relative "utils/database"
5
+
6
+ module Hanami
7
+ module CLI
8
+ module Commands
9
+ module App
10
+ module DB
11
+ # Base class for `hanami` CLI commands intended to be executed within an existing Hanami
12
+ # app.
13
+ #
14
+ # @since 2.2.0
15
+ # @api private
16
+ class Command < App::Command
17
+ option :app, required: false, type: :flag, default: false, desc: "Use app database"
18
+ option :slice, required: false, desc: "Use database for slice"
19
+
20
+ attr_reader :system_call
21
+
22
+ def initialize(
23
+ out:, err:,
24
+ system_call: SystemCall.new,
25
+ **opts
26
+ )
27
+ super(out: out, err: err, **opts)
28
+ @system_call = system_call
29
+ end
30
+
31
+ def run_command(klass, ...)
32
+ klass.new(
33
+ out: out,
34
+ inflector: fs,
35
+ fs: fs,
36
+ system_call: system_call,
37
+ ).call(...)
38
+ end
39
+
40
+ private
41
+
42
+ def databases(app: false, slice: nil)
43
+ if app
44
+ [database_for_app]
45
+ elsif slice
46
+ [database_for_slice(slice)]
47
+ else
48
+ all_databases
49
+ end
50
+ end
51
+
52
+ def database_for_app
53
+ build_database(app)
54
+ end
55
+
56
+ def database_for_slice(slice)
57
+ unless slice.is_a?(Class) && slice < Hanami::Slice
58
+ slice_name = inflector.underscore(Shellwords.shellescape(slice)).to_sym
59
+ slice = app.slices[slice_name]
60
+ end
61
+
62
+ build_database(slice)
63
+ end
64
+
65
+ def all_databases
66
+ slices = [app] + app.slices.with_nested
67
+
68
+ slices_by_database_url = slices.each_with_object({}) { |slice, hsh|
69
+ provider = slice.container.providers[:db]
70
+ next unless provider
71
+
72
+ database_url = provider.source.database_url
73
+ hsh[database_url] ||= []
74
+ hsh[database_url] << slice
75
+ }
76
+
77
+ databases = slices_by_database_url.each_with_object([]) { |(url, slices), arr|
78
+ slices_with_config = slices.select { _1.root.join("config", "db").directory? }
79
+
80
+ database = build_database(slices_with_config.first || slices.first)
81
+
82
+ warn_on_misconfigured_database database, slices_with_config
83
+
84
+ arr << database
85
+ }
86
+
87
+ databases
88
+ end
89
+
90
+ def build_database(slice)
91
+ Utils::Database[slice, system_call: system_call]
92
+ end
93
+
94
+ def warn_on_misconfigured_database(database, slices)
95
+ if slices.length > 1
96
+ out.puts <<~STR
97
+ WARNING: Database #{database.name} is configured for multiple config/db/ directories:
98
+
99
+ #{slices.map { "- " + _1.root.relative_path_from(_1.app.root).join("config", "db").to_s }.join("\n")}
100
+
101
+ Migrating database using #{database.slice.slice_name.to_s.inspect} slice only.
102
+
103
+ STR
104
+ elsif slices.length < 1
105
+ out.puts <<~STR
106
+ WARNING: Database #{database.name} has no config/db/ directory.
107
+
108
+ STR
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -1,23 +1,31 @@
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 Create < App::Command
12
- desc "Create database"
9
+ class Create < DB::Command
10
+ desc "Create databases"
11
+
12
+ def call(app: false, slice: nil, command_exit: method(:exit), **)
13
+ exit_codes = []
14
+
15
+ databases(app: app, slice: slice).each do |database|
16
+ result = database.exec_create_command
17
+ exit_codes << result.exit_code if result.respond_to?(:exit_code)
18
+
19
+ if result == true || result.successful?
20
+ out.puts "=> database #{database.name} created"
21
+ else
22
+ out.puts "=> failed to create database #{database.name}"
23
+ out.puts "#{result.err}\n"
24
+ end
25
+ end
13
26
 
14
- # @api private
15
- def call(**)
16
- if database.create_command
17
- out.puts "=> database #{database.name} created"
18
- else
19
- out.puts "=> failed to create database #{database.name}"
20
- exit $?.exitstatus
27
+ exit_codes.each do |code|
28
+ break command_exit.(code) if code > 0
21
29
  end
22
30
  end
23
31
  end
@@ -1,22 +1,31 @@
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 Drop < App::Command
12
- desc "Delete database"
9
+ class Drop < DB::Command
10
+ desc "Delete databases"
11
+
12
+ def call(app: false, slice: nil, **)
13
+ exit_codes = []
14
+
15
+ databases(app: app, slice: slice).each do |database|
16
+ result = database.exec_drop_command
17
+ exit_codes << result.exit_code if result.respond_to?(:exit_code)
18
+
19
+ if result == true || result.successful?
20
+ out.puts "=> database #{database.name} dropped"
21
+ else
22
+ out.puts "=> failed to drop database #{database.name}"
23
+ out.puts "#{result.err}\n"
24
+ end
25
+ end
13
26
 
14
- # @api private
15
- def call(**)
16
- if database.drop_command
17
- out.puts "=> database #{database.name} dropped"
18
- else
19
- out.puts "=> failed to drop #{database.name}"
27
+ exit_codes.each do |code|
28
+ break exit code if code > 0
20
29
  end
21
30
  end
22
31
  end
@@ -1,38 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../../app/command"
4
- require_relative "structure/dump"
5
-
6
3
  module Hanami
7
4
  module CLI
8
5
  module Commands
9
6
  module App
10
7
  module DB
11
8
  # @api private
12
- class Migrate < App::Command
9
+ class Migrate < DB::Command
13
10
  desc "Migrates database"
14
11
 
15
12
  option :target, desc: "Target migration number", aliases: ["-t"]
13
+ option :dump, required: false, type: :boolean, default: true,
14
+ desc: "Dump the database structure after migrating"
16
15
 
17
- # @api private
18
- def call(target: nil, **)
19
- return true if Dir[File.join(app.root, "db/migrate/*.rb")].empty?
16
+ def call(target: nil, app: false, slice: nil, dump: true, command_exit: method(:exit), **)
17
+ databases(app: app, slice: slice).each do |database|
18
+ migrate_database(database, target: target)
19
+ end
20
+
21
+ run_command(Structure::Dump, app: app, slice: slice, command_exit: command_exit) if dump
22
+ end
23
+
24
+ private
25
+
26
+ def migrate_database(database, target:)
27
+ return true unless migrations?(database)
20
28
 
21
29
  measure "database #{database.name} migrated" do
22
30
  if target
23
- run_migrations(target: Integer(target))
31
+ database.run_migrations(target: Integer(target))
24
32
  else
25
- run_migrations
33
+ database.run_migrations
26
34
  end
27
35
 
28
36
  true
29
37
  end
30
38
  end
31
39
 
32
- private
33
-
34
- def run_migrations(**options)
35
- database.run_migrations(**options)
40
+ def migrations?(database)
41
+ database.migrations_dir? && database.sequel_migrator.files.any?
36
42
  end
37
43
  end
38
44
  end
@@ -0,0 +1,42 @@
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
+ class Prepare < DB::Command
10
+ desc "Prepare databases"
11
+
12
+ def call(app: false, slice: nil, **)
13
+ exit_codes = []
14
+
15
+ databases(app: app, slice: slice).each do |database|
16
+ command_exit = -> code { throw :command_exited, code }
17
+ command_args = {slice: database.slice, command_exit: command_exit}
18
+
19
+ exit_code = catch :command_exited do
20
+ unless database.exists?
21
+ run_command(DB::Create, **command_args)
22
+ run_command(DB::Structure::Load, **command_args)
23
+ end
24
+
25
+ run_command(DB::Migrate, **command_args)
26
+ run_command(DB::Seed, **command_args)
27
+ nil
28
+ end
29
+
30
+ exit_codes << exit_code if exit_code
31
+ end
32
+
33
+ exit_codes.each do |code|
34
+ break exit code if code > 0
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,39 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../../app/command"
4
- require_relative "structure/dump"
5
-
6
3
  module Hanami
7
4
  module CLI
8
5
  module Commands
9
6
  module App
10
7
  module DB
11
8
  # @api private
12
- class Seed < App::Command
13
- FILE_PATH = "db/seeds.rb"
9
+ class Seed < DB::Command
10
+ SEEDS_PATH = "config/db/seeds.rb"
11
+ private_constant :SEEDS_PATH
14
12
 
15
13
  desc "Load seed data"
16
14
 
17
- # @api private
18
- def call(**)
19
- if has_file?
20
- measure "seed data loaded from #{FILE_PATH}" do
21
- load full_file_path
15
+ def call(app: false, slice: nil, **)
16
+ databases(app: app, slice: slice).each do |database|
17
+ seeds_path = database.slice.root.join(SEEDS_PATH)
18
+ next unless seeds_path.file?
19
+
20
+ relative_seeds_path = seeds_path.relative_path_from(database.slice.app.root)
21
+ measure "seed data loaded from #{relative_seeds_path}" do
22
+ load seeds_path.to_s
22
23
  end
23
- else
24
- out.puts "=> #{FILE_PATH} not found"
25
24
  end
26
25
  end
27
-
28
- private
29
-
30
- def full_file_path
31
- File.join(app.root, FILE_PATH)
32
- end
33
-
34
- def has_file?
35
- File.exist?(full_file_path)
36
- end
37
26
  end
38
27
  end
39
28
  end
@@ -1,7 +1,5 @@
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
@@ -10,13 +8,38 @@ module Hanami
10
8
  # @api private
11
9
  module Structure
12
10
  # @api private
13
- class Dump < App::Command
14
- desc "Dumps database structure to db/structure.sql file"
11
+ class Dump < DB::Command
12
+ desc "Dumps database structure to config/db/structure.sql file"
15
13
 
16
14
  # @api private
17
- def call(*)
18
- measure("#{database.name} structure dumped to db/structure.sql") do
19
- database.dump_command
15
+ def call(app: false, slice: nil, command_exit: method(:exit), **)
16
+ exit_codes = []
17
+
18
+ databases(app: app, slice: slice).each do |database|
19
+ structure_path = database.slice.root.join("config", "db", "structure.sql")
20
+ relative_structure_path = structure_path.relative_path_from(database.slice.app.root)
21
+
22
+ measure("#{database.name} structure dumped to #{relative_structure_path}") do
23
+ catch :dump_failed do
24
+ result = database.exec_dump_command
25
+ exit_codes << result.exit_code if result.respond_to?(:exit_code)
26
+
27
+ unless result.successful?
28
+ out.puts result.err
29
+ throw :dump_failed, false
30
+ end
31
+
32
+ File.open(structure_path, "a") do |f|
33
+ f.puts "#{database.schema_migrations_sql_dump}\n"
34
+ end
35
+
36
+ true
37
+ end
38
+ end
39
+ end
40
+
41
+ exit_codes.each do |code|
42
+ break command_exit.(code) if code > 0
20
43
  end
21
44
  end
22
45
  end