hanami-cli 2.1.1 → 2.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +18 -13
  3. data/CHANGELOG.md +15 -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/command.rb +2 -16
  10. data/lib/hanami/cli/commands/app/db/command.rb +116 -0
  11. data/lib/hanami/cli/commands/app/db/create.rb +19 -11
  12. data/lib/hanami/cli/commands/app/db/drop.rb +19 -10
  13. data/lib/hanami/cli/commands/app/db/migrate.rb +19 -13
  14. data/lib/hanami/cli/commands/app/db/prepare.rb +42 -0
  15. data/lib/hanami/cli/commands/app/db/seed.rb +11 -22
  16. data/lib/hanami/cli/commands/app/db/structure/dump.rb +30 -7
  17. data/lib/hanami/cli/commands/app/db/structure/load.rb +52 -0
  18. data/lib/hanami/cli/commands/app/db/utils/database.rb +68 -73
  19. data/lib/hanami/cli/commands/app/db/utils/mysql.rb +2 -2
  20. data/lib/hanami/cli/commands/app/db/utils/postgres.rb +38 -19
  21. data/lib/hanami/cli/commands/app/db/utils/sqlite.rb +58 -10
  22. data/lib/hanami/cli/commands/app/db/version.rb +12 -9
  23. data/lib/hanami/cli/commands/app/generate/action.rb +4 -3
  24. data/lib/hanami/cli/commands/app/generate/command.rb +49 -0
  25. data/lib/hanami/cli/commands/app/generate/component.rb +49 -0
  26. data/lib/hanami/cli/commands/app/generate/migration.rb +27 -0
  27. data/lib/hanami/cli/commands/app/generate/operation.rb +26 -0
  28. data/lib/hanami/cli/commands/app/generate/part.rb +1 -1
  29. data/lib/hanami/cli/commands/app/generate/relation.rb +35 -0
  30. data/lib/hanami/cli/commands/app/generate/repo.rb +46 -0
  31. data/lib/hanami/cli/commands/app/generate/slice.rb +20 -3
  32. data/lib/hanami/cli/commands/app/generate/struct.rb +27 -0
  33. data/lib/hanami/cli/commands/app/install.rb +1 -1
  34. data/lib/hanami/cli/commands/app/middleware.rb +1 -1
  35. data/lib/hanami/cli/commands/app/server.rb +2 -2
  36. data/lib/hanami/cli/commands/app.rb +21 -2
  37. data/lib/hanami/cli/commands/gem/new.rb +78 -14
  38. data/lib/hanami/cli/errors.rb +28 -0
  39. data/lib/hanami/cli/generators/app/action_context.rb +5 -13
  40. data/lib/hanami/cli/generators/app/component/component.erb +8 -0
  41. data/lib/hanami/cli/generators/app/component/slice_component.erb +8 -0
  42. data/lib/hanami/cli/generators/app/component.rb +61 -0
  43. data/lib/hanami/cli/generators/app/component_context.rb +82 -0
  44. data/lib/hanami/cli/generators/app/migration.rb +69 -0
  45. data/lib/hanami/cli/generators/app/operation.rb +48 -0
  46. data/lib/hanami/cli/generators/app/part_context.rb +5 -21
  47. data/lib/hanami/cli/generators/app/relation.rb +44 -0
  48. data/lib/hanami/cli/generators/app/repo.rb +40 -0
  49. data/lib/hanami/cli/generators/app/ruby_file_writer.rb +149 -0
  50. data/lib/hanami/cli/generators/app/slice/operation.erb +7 -0
  51. data/lib/hanami/cli/generators/app/slice/relation.erb +8 -0
  52. data/lib/hanami/cli/generators/app/slice/{slice.erb → repo.erb} +3 -1
  53. data/lib/hanami/cli/generators/app/slice/struct.erb +8 -0
  54. data/lib/hanami/cli/generators/app/slice.rb +14 -6
  55. data/lib/hanami/cli/generators/app/slice_context.rb +9 -2
  56. data/lib/hanami/cli/generators/app/struct.rb +39 -0
  57. data/lib/hanami/cli/generators/app/view_context.rb +4 -16
  58. data/lib/hanami/cli/generators/constants.rb +39 -0
  59. data/lib/hanami/cli/generators/context.rb +48 -0
  60. data/lib/hanami/cli/generators/gem/app/action.erb +3 -0
  61. data/lib/hanami/cli/generators/gem/app/env.erb +4 -0
  62. data/lib/hanami/cli/generators/gem/app/gemfile.erb +11 -0
  63. data/lib/hanami/cli/generators/gem/app/gitignore.erb +1 -1
  64. data/lib/hanami/cli/generators/gem/app/operation.erb +13 -0
  65. data/lib/hanami/cli/generators/gem/app/relation.erb +10 -0
  66. data/lib/hanami/cli/generators/gem/app/repo.erb +10 -0
  67. data/lib/hanami/cli/generators/gem/app/struct.erb +10 -0
  68. data/lib/hanami/cli/generators/gem/app.rb +19 -0
  69. data/lib/hanami/cli/ruby_file_generator.rb +123 -0
  70. data/lib/hanami/cli/version.rb +1 -1
  71. metadata +39 -16
  72. data/lib/hanami/cli/commands/app/db/create_migration.rb +0 -32
  73. data/lib/hanami/cli/commands/app/db/reset.rb +0 -28
  74. data/lib/hanami/cli/commands/app/db/rollback.rb +0 -81
  75. data/lib/hanami/cli/commands/app/db/sample_data.rb +0 -42
  76. data/lib/hanami/cli/commands/app/db/setup.rb +0 -26
  77. data/lib/hanami/cli/commands/app/db/utils/database_config.rb +0 -60
  78. 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: bc90cef87d08c779e3936a2431b93b647f43242c43cea6f85dc3fb22269c4647
4
- data.tar.gz: 9eb4424fbdb88f535712951deaddc08874e76085b42fb8fd6d2715a3c3874af8
3
+ metadata.gz: eda4f18125d25c640cbb75e50a7e636b93e29badd50f6540b37c6fc55bb7cb98
4
+ data.tar.gz: 2d0f39b520d19a39866ccc354d40c1e9536f9b2c77d2ead33f340ddc64d899ef
5
5
  SHA512:
6
- metadata.gz: b081dcb657e85809a9cd58e02ceeb4de28253e48e41ee030cae580c6ebb58a947255214a535bd9cf7f1061f7ee685749c8804da2e2ac2c8f203f81487ac88753
7
- data.tar.gz: c524a51060f38143552ff8601511856348b88124f3597d55d4043a54791e356a45ac45ffbbd268b14f0a04f87caf7baa63d7d56750a6b7299c0f6e34d469216e
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,21 @@
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
+
5
20
  ## v2.1.1 - 2024-03-19
6
21
 
7
22
  ### Fixed
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.
@@ -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
@@ -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