hanami-cli 2.2.0.beta1 → 2.2.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +13 -2
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +38 -2
- data/Gemfile +3 -0
- data/README.md +2 -0
- data/docker-compose.yml +6 -1
- data/lib/hanami/cli/command.rb +1 -1
- data/lib/hanami/cli/commands/app/command.rb +9 -3
- data/lib/hanami/cli/commands/app/console.rb +1 -5
- data/lib/hanami/cli/commands/app/db/command.rb +139 -31
- data/lib/hanami/cli/commands/app/db/create.rb +6 -2
- data/lib/hanami/cli/commands/app/db/drop.rb +6 -2
- data/lib/hanami/cli/commands/app/db/migrate.rb +49 -8
- data/lib/hanami/cli/commands/app/db/prepare.rb +36 -8
- data/lib/hanami/cli/commands/app/db/seed.rb +17 -1
- data/lib/hanami/cli/commands/app/db/structure/dump.rb +11 -6
- data/lib/hanami/cli/commands/app/db/structure/load.rb +9 -5
- data/lib/hanami/cli/commands/app/db/utils/database.rb +44 -14
- data/lib/hanami/cli/commands/app/db/utils/mysql.rb +57 -4
- data/lib/hanami/cli/commands/app/db/utils/postgres.rb +13 -8
- data/lib/hanami/cli/commands/app/db/version.rb +6 -3
- data/lib/hanami/cli/commands/app/generate/action.rb +12 -2
- data/lib/hanami/cli/commands/app/generate/command.rb +13 -2
- data/lib/hanami/cli/commands/app/generate/migration.rb +20 -0
- data/lib/hanami/cli/commands/app/generate/relation.rb +0 -6
- data/lib/hanami/cli/commands/app/generate/repo.rb +3 -7
- data/lib/hanami/cli/commands/app/generate/slice.rb +16 -3
- data/lib/hanami/cli/commands/app.rb +21 -9
- data/lib/hanami/cli/files.rb +22 -0
- data/lib/hanami/cli/generators/app/action.rb +27 -15
- data/lib/hanami/cli/generators/app/migration.rb +8 -9
- data/lib/hanami/cli/generators/app/operation.rb +5 -4
- data/lib/hanami/cli/generators/app/relation.rb +5 -4
- data/lib/hanami/cli/generators/app/repo.rb +5 -4
- data/lib/hanami/cli/generators/app/ruby_file_writer.rb +39 -37
- data/lib/hanami/cli/generators/app/slice.rb +5 -3
- data/lib/hanami/cli/generators/app/slice_context.rb +6 -0
- data/lib/hanami/cli/generators/app/struct.rb +5 -4
- data/lib/hanami/cli/generators/context.rb +4 -4
- data/lib/hanami/cli/generators/gem/app/gitignore.erb +3 -0
- data/lib/hanami/cli/generators/gem/app/operation.erb +0 -4
- data/lib/hanami/cli/generators/gem/app/seeds.erb +15 -0
- data/lib/hanami/cli/generators/gem/app.rb +3 -2
- data/lib/hanami/cli/repl/irb.rb +2 -2
- data/lib/hanami/cli/version.rb +1 -1
- metadata +4 -4
- data/lib/hanami/cli/generators/app/slice/entities.erb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6ace925a2c5186088911d5df3d309d72ee0359e4691f70199c3f53f99db0fc3
|
4
|
+
data.tar.gz: 7fd1959ffcaf64ebc0b95a839a68ed1f052370ed6a7043863068087a1893489d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6133308e48b0623616598a23d1b0fe079b08f31e991791e6ae76867441eec1d25427deef5755e445fd8c3f2f2e294c143eeb58272e278721897ab290c48024cb
|
7
|
+
data.tar.gz: '068ad2b891fa99e16ff6c0be6931e98d708ce3c7bab67e0dd3fd354ef00f4bdb110ad84007592ccc98e65ebbe643f7e4420b0406f8b0b76500968a5571718398'
|
data/.github/workflows/ci.yml
CHANGED
@@ -41,6 +41,17 @@ jobs:
|
|
41
41
|
- name: Run all tests
|
42
42
|
run: bundle exec rake spec
|
43
43
|
services:
|
44
|
+
mysql:
|
45
|
+
image: mysql:latest
|
46
|
+
env:
|
47
|
+
MYSQL_ROOT_PASSWORD: password
|
48
|
+
ports:
|
49
|
+
- 3307:3306
|
50
|
+
options: >-
|
51
|
+
--health-cmd "mysqladmin ping"
|
52
|
+
--health-interval 10s
|
53
|
+
--health-timeout 5s
|
54
|
+
--health-retries 3
|
44
55
|
postgres:
|
45
56
|
# Use postgres:14 for CLI compatibility with ubuntu-latest, currently ubuntu-22.04
|
46
57
|
# See https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md
|
@@ -48,10 +59,10 @@ jobs:
|
|
48
59
|
env:
|
49
60
|
POSTGRES_USER: postgres
|
50
61
|
POSTGRES_PASSWORD: password
|
62
|
+
ports:
|
63
|
+
- 5432:5432
|
51
64
|
options: >-
|
52
65
|
--health-cmd pg_isready
|
53
66
|
--health-interval 10s
|
54
67
|
--health-timeout 5s
|
55
68
|
--health-retries 5
|
56
|
-
ports:
|
57
|
-
- 5432:5432
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,9 +2,45 @@
|
|
2
2
|
|
3
3
|
Hanami Command Line Interface
|
4
4
|
|
5
|
+
## v2.2.0.rc1 - 2024-10-29
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- [Tim Riley, François Beausoleil] Generate a `config/db/seeds.rb` file in new apps (#255, #256)
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
|
13
|
+
- [Tim Riley] Add `--env` and `-e` options to all app commands, for setting the Hanami env (#246)
|
14
|
+
- [Tim Riley] Keep test database in sync by applying `hanami db` commands to both development and test databases when invoked in development environment (#247)
|
15
|
+
- [Kyle Plump] Add `--skip-route` flag to `generate action` and `generate slice` commands (#227)
|
16
|
+
- [Tim Riley] Include a `change do` block in generated migrations (#254)
|
17
|
+
- [Tim Riley] Generate MySQL database URL in `.env` that works with standard Homebrew MySQL installation (#249)
|
18
|
+
- [Tim Riley, Adam Lassek] Remove ROM extension boilerplate in operations generated by `hanami new` and `generate operation` (this is now applied automatically) (#240, #252)
|
19
|
+
- [François Beausoleil] Print a warning when running `db seed` but expected seeds files could not be found (#256)
|
20
|
+
- [Seb Wilgosz] Only register `generate` subcommands if the relevant gems are bundled (#242)
|
21
|
+
- [Anderson Saunders] When both IRB and pry are loaded, use IRB as the default engine for `hanami console` (#182)
|
22
|
+
|
23
|
+
### Fixed
|
24
|
+
|
25
|
+
- [Tim Riley] Fix error dumping structure when there are no migrations (#244)
|
26
|
+
- [Tim Riley] Stop erroneous misconfigured DB warnings from `hanami db` commands when a database is configured once but shared across sliaces (#253)
|
27
|
+
|
28
|
+
## v2.2.0.beta2 - 2024-09-25
|
29
|
+
|
30
|
+
### Added
|
31
|
+
|
32
|
+
- [Tim Riley] MySQL support for `db` commands (#226)
|
33
|
+
- [Tim Riley] Support for multiple gateways in `db` commands (#232, #234, #237, #238)
|
34
|
+
|
35
|
+
### Changed
|
36
|
+
|
37
|
+
- [Kyle Plump, Tim Riley] Delete `.keep` files when generating new files into previously empty directory (#224)
|
38
|
+
- [Sean Collins] Add `db/*.sqlite` to the `.gitignore` in new apps (#210)
|
39
|
+
- [Sean Collins] Print warnings for misconfigured databases when running `db` commands (#211)
|
40
|
+
|
5
41
|
## v2.2.0.beta1 - 2024-07-16
|
6
42
|
|
7
|
-
|
43
|
+
### Added
|
8
44
|
|
9
45
|
- [Sean Collins] Generate db files in `hanami new` and `generate slice`
|
10
46
|
- [Tim Riley] Add `db` commands: `create`, `drop`, `migrate`, `structure dump` `structure load`, `seed` `prepare`, `version`
|
@@ -13,7 +49,7 @@ Hanami Command Line Interface
|
|
13
49
|
- [Krzysztof] Add `generate component` command
|
14
50
|
- [Sean Collins] Add `generate operation` command
|
15
51
|
|
16
|
-
|
52
|
+
### Changed
|
17
53
|
|
18
54
|
- Drop support for Ruby 3.0
|
19
55
|
|
data/Gemfile
CHANGED
@@ -16,8 +16,11 @@ gem "hanami-db", github: "hanami/db", branch: "main"
|
|
16
16
|
gem "hanami-router", github: "hanami/router", branch: "main"
|
17
17
|
gem "hanami-utils", github: "hanami/utils", branch: "main"
|
18
18
|
|
19
|
+
gem "dry-system", github: "dry-rb/dry-system", branch: "main"
|
20
|
+
|
19
21
|
gem "rack"
|
20
22
|
|
23
|
+
gem "mysql2"
|
21
24
|
gem "pg"
|
22
25
|
gem "sqlite3"
|
23
26
|
|
data/README.md
CHANGED
@@ -34,6 +34,8 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
34
34
|
|
35
35
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
36
36
|
|
37
|
+
In order to run all of the tests, you should run `docker compose up` separately, to run a `postgres` server.
|
38
|
+
|
37
39
|
## Contributing
|
38
40
|
|
39
41
|
Bug reports and pull requests are welcome on GitHub at https://github.com/hanami/cli. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/hanami/cli/blob/main/CODE_OF_CONDUCT.md).
|
data/docker-compose.yml
CHANGED
data/lib/hanami/cli/command.rb
CHANGED
@@ -18,8 +18,8 @@ module Hanami
|
|
18
18
|
# @api private
|
19
19
|
ACTION_SEPARATOR = "." # TODO: rename to container key separator
|
20
20
|
|
21
|
-
# Overloads {Hanami::CLI::Commands::App::Command#call} to ensure an appropriate
|
22
|
-
# environment variable is set.
|
21
|
+
# Overloads {Hanami::CLI::Commands::App::Command#call} to ensure an appropriate
|
22
|
+
# `HANAMI_ENV` environment variable is set.
|
23
23
|
#
|
24
24
|
# Uses an `--env` option if provided, then falls back to an already-set `HANAMI_ENV`
|
25
25
|
# environment variable, and defaults to "development" in the absence of both.
|
@@ -27,6 +27,12 @@ module Hanami
|
|
27
27
|
# @since 2.0.0
|
28
28
|
# @api private
|
29
29
|
module Environment
|
30
|
+
# @since 2.2.0
|
31
|
+
# @api private
|
32
|
+
def self.prepended(klass)
|
33
|
+
klass.option :env, desc: "App environment (development, test, production)", aliases: ["e"]
|
34
|
+
end
|
35
|
+
|
30
36
|
# @since 2.0.0
|
31
37
|
# @api private
|
32
38
|
def call(*args, **opts)
|
@@ -37,7 +43,7 @@ module Hanami
|
|
37
43
|
ENV["HANAMI_ENV"] = hanami_env
|
38
44
|
Hanami::Env.load
|
39
45
|
|
40
|
-
super
|
46
|
+
super
|
41
47
|
end
|
42
48
|
end
|
43
49
|
|
@@ -51,11 +51,7 @@ module Hanami
|
|
51
51
|
private
|
52
52
|
|
53
53
|
def resolve_engine(engine, opts)
|
54
|
-
|
55
|
-
ENGINES.fetch(engine).(app, opts)
|
56
|
-
else
|
57
|
-
ENGINES.map { |(_, loader)| loader.(app, opts) }.compact.first
|
58
|
-
end
|
54
|
+
ENGINES.fetch(engine, ENGINES[DEFAULT_ENGINE]).call(app, opts)
|
59
55
|
end
|
60
56
|
end
|
61
57
|
end
|
@@ -17,97 +17,205 @@ module Hanami
|
|
17
17
|
option :app, required: false, type: :flag, default: false, desc: "Use app database"
|
18
18
|
option :slice, required: false, desc: "Use database for slice"
|
19
19
|
|
20
|
+
# @api private
|
20
21
|
attr_reader :system_call
|
21
22
|
|
23
|
+
# @api private
|
24
|
+
attr_reader :test_env_executor
|
25
|
+
|
22
26
|
def initialize(
|
23
27
|
out:, err:,
|
24
28
|
system_call: SystemCall.new,
|
29
|
+
test_env_executor: InteractiveSystemCall.new(out: out, err: err),
|
30
|
+
nested_command: false,
|
25
31
|
**opts
|
26
32
|
)
|
27
33
|
super(out: out, err: err, **opts)
|
28
34
|
@system_call = system_call
|
35
|
+
@test_env_executor = test_env_executor
|
36
|
+
@nested_command = nested_command
|
29
37
|
end
|
30
38
|
|
31
39
|
def run_command(klass, ...)
|
32
40
|
klass.new(
|
33
41
|
out: out,
|
34
|
-
inflector:
|
42
|
+
inflector: inflector,
|
35
43
|
fs: fs,
|
36
44
|
system_call: system_call,
|
45
|
+
test_env_executor: test_env_executor,
|
46
|
+
nested_command: true,
|
37
47
|
).call(...)
|
38
48
|
end
|
39
49
|
|
50
|
+
def nested_command?
|
51
|
+
@nested_command
|
52
|
+
end
|
53
|
+
|
40
54
|
private
|
41
55
|
|
42
|
-
def databases(app: false, slice: nil)
|
43
|
-
if app
|
44
|
-
|
45
|
-
|
46
|
-
[database_for_slice(slice)]
|
47
|
-
else
|
48
|
-
all_databases
|
56
|
+
def databases(app: false, slice: nil, gateway: nil)
|
57
|
+
if gateway && !app && !slice
|
58
|
+
err.puts "When specifying --gateway, an --app or --slice must also be given"
|
59
|
+
exit 1
|
49
60
|
end
|
50
|
-
end
|
51
61
|
|
52
|
-
|
53
|
-
|
62
|
+
databases =
|
63
|
+
if slice
|
64
|
+
[database_for_slice(slice, gateway: gateway)]
|
65
|
+
elsif app
|
66
|
+
[database_for_slice(self.app, gateway: gateway)]
|
67
|
+
else
|
68
|
+
all_databases
|
69
|
+
end
|
70
|
+
|
71
|
+
databases.flatten
|
54
72
|
end
|
55
73
|
|
56
|
-
def database_for_slice(slice)
|
74
|
+
def database_for_slice(slice, gateway: nil)
|
57
75
|
unless slice.is_a?(Class) && slice < Hanami::Slice
|
58
76
|
slice_name = inflector.underscore(Shellwords.shellescape(slice)).to_sym
|
59
77
|
slice = app.slices[slice_name]
|
60
78
|
end
|
61
79
|
|
62
|
-
|
80
|
+
ensure_database_slice slice
|
81
|
+
|
82
|
+
databases = build_databases(slice)
|
83
|
+
|
84
|
+
if gateway
|
85
|
+
databases.fetch(gateway.to_sym) do
|
86
|
+
err.puts %(No gateway "#{gateway}" in #{slice})
|
87
|
+
exit 1
|
88
|
+
end
|
89
|
+
else
|
90
|
+
databases.values
|
91
|
+
end
|
63
92
|
end
|
64
93
|
|
65
|
-
def all_databases
|
94
|
+
def all_databases # rubocop:disable Metrics/AbcSize
|
66
95
|
slices = [app] + app.slices.with_nested
|
67
96
|
|
68
|
-
|
69
|
-
|
70
|
-
next unless
|
97
|
+
slice_gateways_by_database_url = slices.each_with_object({}) { |slice, hsh|
|
98
|
+
db_provider_source = slice.container.providers[:db]&.source
|
99
|
+
next unless db_provider_source
|
71
100
|
|
72
|
-
|
73
|
-
|
74
|
-
|
101
|
+
db_provider_source.database_urls.each do |gateway, url|
|
102
|
+
hsh[url] ||= []
|
103
|
+
hsh[url] << {slice: slice, gateway: gateway}
|
104
|
+
end
|
75
105
|
}
|
76
106
|
|
77
|
-
|
78
|
-
|
107
|
+
slice_gateways_by_database_url.each_with_object([]) { |(url, slice_gateways), arr|
|
108
|
+
slice_gateways_with_config = slice_gateways.select {
|
109
|
+
migrate_dir = _1[:gateway] == :default ? "migrate" : "#{_1[:gateway]}_migrate"
|
79
110
|
|
80
|
-
|
111
|
+
_1[:slice].root.join("config", "db", migrate_dir).directory?
|
112
|
+
}
|
81
113
|
|
82
|
-
|
114
|
+
db_slice_gateway = slice_gateways_with_config.first || slice_gateways.first
|
115
|
+
database = Utils::Database.database_class(url).new(
|
116
|
+
slice: db_slice_gateway.fetch(:slice),
|
117
|
+
gateway_name: db_slice_gateway.fetch(:gateway),
|
118
|
+
system_call: system_call
|
119
|
+
)
|
120
|
+
|
121
|
+
warn_on_misconfigured_database database, slice_gateways_with_config.map { _1.fetch(:slice) }
|
83
122
|
|
84
123
|
arr << database
|
85
124
|
}
|
125
|
+
end
|
86
126
|
|
87
|
-
|
127
|
+
def build_databases(slice)
|
128
|
+
Utils::Database.from_slice(slice: slice, system_call: system_call)
|
88
129
|
end
|
89
130
|
|
90
|
-
def
|
91
|
-
|
131
|
+
def ensure_database_slice(slice)
|
132
|
+
return if slice.container.providers[:db]
|
133
|
+
|
134
|
+
out.puts "#{slice} does not have a :db provider."
|
135
|
+
exit 1
|
92
136
|
end
|
93
137
|
|
94
|
-
def warn_on_misconfigured_database(database, slices)
|
138
|
+
def warn_on_misconfigured_database(database, slices) # rubocop:disable Metrics/AbcSize
|
95
139
|
if slices.length > 1
|
96
140
|
out.puts <<~STR
|
97
141
|
WARNING: Database #{database.name} is configured for multiple config/db/ directories:
|
98
142
|
|
99
143
|
#{slices.map { "- " + _1.root.relative_path_from(_1.app.root).join("config", "db").to_s }.join("\n")}
|
100
144
|
|
101
|
-
|
145
|
+
Using config in #{database.slice.slice_name.to_s.inspect} slice only.
|
102
146
|
|
103
147
|
STR
|
104
|
-
elsif
|
148
|
+
elsif !database.db_config_dir?
|
149
|
+
relative_path = database.slice.root
|
150
|
+
.relative_path_from(database.slice.app.root)
|
151
|
+
.join("config", "db").to_s
|
152
|
+
|
105
153
|
out.puts <<~STR
|
106
|
-
WARNING: Database #{database.name}
|
154
|
+
WARNING: Database #{database.name} expects the folder #{relative_path}/ to exist but it does not.
|
107
155
|
|
108
156
|
STR
|
109
157
|
end
|
110
158
|
end
|
159
|
+
|
160
|
+
# Invokes the currently executing `hanami` CLI command again, but with any `--env` args
|
161
|
+
# removed and the `HANAMI_ENV=test` env var set.
|
162
|
+
#
|
163
|
+
# This is called by certain `db` commands only, and runs only if the Hanami env is
|
164
|
+
# `:development`. This behavior important to streamline the local development
|
165
|
+
# experience, making sure that the test databases are kept in sync with operations run
|
166
|
+
# on the development databases.
|
167
|
+
#
|
168
|
+
# Spawning an entirely new process to change the env is a compromise approach until we
|
169
|
+
# can have an API for reinitializing the DB subsystem in-process with a different env.
|
170
|
+
def re_run_development_command_in_test
|
171
|
+
# Only invoke a new process if we've been called as `hanami`. This avoids awkward
|
172
|
+
# failures when testing commands via RSpec, for which the $0 is "/full/path/to/rspec".
|
173
|
+
return unless $0.end_with?("hanami")
|
174
|
+
|
175
|
+
# If this special env key is set, then a re-run has already been invoked. This would
|
176
|
+
# mean the current command is actually a nested command run by another db command. In
|
177
|
+
# this case, don't trigger a re-runs, because one is already in process.
|
178
|
+
return if nested_command?
|
179
|
+
|
180
|
+
# Re-runs in test are for development-env commands only.
|
181
|
+
return unless Hanami.env == :development
|
182
|
+
|
183
|
+
cmd = $0
|
184
|
+
cmd = "bundle exec #{cmd}" if ENV.key?("BUNDLE_BIN_PATH")
|
185
|
+
|
186
|
+
test_env_executor.call(
|
187
|
+
cmd, *argv_without_env_args,
|
188
|
+
env: {
|
189
|
+
"HANAMI_ENV" => "test",
|
190
|
+
"HANAMI_CLI_DB_COMMAND_RE_RUN_IN_TEST" => "true"
|
191
|
+
}
|
192
|
+
)
|
193
|
+
end
|
194
|
+
|
195
|
+
def re_running_in_test?
|
196
|
+
ENV.key?("HANAMI_CLI_DB_COMMAND_RE_RUN_IN_TEST")
|
197
|
+
end
|
198
|
+
|
199
|
+
# Returns the `ARGV` with every option argument included, but the `-e` or `--env` args
|
200
|
+
# removed.
|
201
|
+
def argv_without_env_args
|
202
|
+
new_argv = ARGV.dup
|
203
|
+
|
204
|
+
env_arg_index = new_argv.index {
|
205
|
+
_1 == "-e" || _1 == "--env" || _1.start_with?("-e=") || _1.start_with?("--env=")
|
206
|
+
}
|
207
|
+
|
208
|
+
if env_arg_index
|
209
|
+
# Remove the env argument
|
210
|
+
env_arg = new_argv.delete_at(env_arg_index)
|
211
|
+
|
212
|
+
# If the env argument is not in combined form ("--env foo" rather than "--env=foo"),
|
213
|
+
# then remove the following argument too
|
214
|
+
new_argv.delete_at(env_arg_index) if ["-e", "--env"].include?(env_arg)
|
215
|
+
end
|
216
|
+
|
217
|
+
new_argv
|
218
|
+
end
|
111
219
|
end
|
112
220
|
end
|
113
221
|
end
|
@@ -9,10 +9,12 @@ module Hanami
|
|
9
9
|
class Create < DB::Command
|
10
10
|
desc "Create databases"
|
11
11
|
|
12
|
-
|
12
|
+
option :gateway, required: false, desc: "Use database for gateway"
|
13
|
+
|
14
|
+
def call(app: false, slice: nil, gateway: nil, command_exit: method(:exit), **)
|
13
15
|
exit_codes = []
|
14
16
|
|
15
|
-
databases(app: app, slice: slice).each do |database|
|
17
|
+
databases(app: app, slice: slice, gateway: gateway).each do |database|
|
16
18
|
result = database.exec_create_command
|
17
19
|
exit_codes << result.exit_code if result.respond_to?(:exit_code)
|
18
20
|
|
@@ -27,6 +29,8 @@ module Hanami
|
|
27
29
|
exit_codes.each do |code|
|
28
30
|
break command_exit.(code) if code > 0
|
29
31
|
end
|
32
|
+
|
33
|
+
re_run_development_command_in_test
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
@@ -9,10 +9,12 @@ module Hanami
|
|
9
9
|
class Drop < DB::Command
|
10
10
|
desc "Delete databases"
|
11
11
|
|
12
|
-
|
12
|
+
option :gateway, required: false, desc: "Use database for gateway"
|
13
|
+
|
14
|
+
def call(app: false, slice: nil, gateway: nil, **)
|
13
15
|
exit_codes = []
|
14
16
|
|
15
|
-
databases(app: app, slice: slice).each do |database|
|
17
|
+
databases(app: app, slice: slice, gateway: gateway).each do |database|
|
16
18
|
result = database.exec_drop_command
|
17
19
|
exit_codes << result.exit_code if result.respond_to?(:exit_code)
|
18
20
|
|
@@ -27,6 +29,8 @@ module Hanami
|
|
27
29
|
exit_codes.each do |code|
|
28
30
|
break exit code if code > 0
|
29
31
|
end
|
32
|
+
|
33
|
+
re_run_development_command_in_test
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
@@ -9,22 +9,38 @@ module Hanami
|
|
9
9
|
class Migrate < DB::Command
|
10
10
|
desc "Migrates database"
|
11
11
|
|
12
|
+
option :gateway, required: false, desc: "Use database for gateway"
|
12
13
|
option :target, desc: "Target migration number", aliases: ["-t"]
|
13
14
|
option :dump, required: false, type: :boolean, default: true,
|
14
|
-
|
15
|
+
desc: "Dump the database structure after migrating"
|
15
16
|
|
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
|
-
|
17
|
+
def call(target: nil, app: false, slice: nil, gateway: nil, dump: true, command_exit: method(:exit), **)
|
18
|
+
databases(app: app, slice: slice, gateway: gateway).each do |database|
|
19
|
+
if migrations_dir_missing?(database)
|
20
|
+
warn_on_missing_migrations_dir(database)
|
21
|
+
elsif no_migrations?(database)
|
22
|
+
warn_on_empty_migrations_dir(database)
|
23
|
+
else
|
24
|
+
migrate_database(database, target: target)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Only dump for the initial command, not a re-run of the command in test env
|
29
|
+
if dump && !re_running_in_test?
|
30
|
+
run_command(
|
31
|
+
Structure::Dump,
|
32
|
+
app: app, slice: slice, gateway: gateway,
|
33
|
+
command_exit: command_exit
|
34
|
+
)
|
19
35
|
end
|
20
36
|
|
21
|
-
|
37
|
+
re_run_development_command_in_test
|
22
38
|
end
|
23
39
|
|
24
40
|
private
|
25
41
|
|
26
42
|
def migrate_database(database, target:)
|
27
|
-
return true unless
|
43
|
+
return true unless database.migrations_dir?
|
28
44
|
|
29
45
|
measure "database #{database.name} migrated" do
|
30
46
|
if target
|
@@ -37,8 +53,33 @@ module Hanami
|
|
37
53
|
end
|
38
54
|
end
|
39
55
|
|
40
|
-
def
|
41
|
-
database.migrations_dir?
|
56
|
+
def migrations_dir_missing?(database)
|
57
|
+
!database.migrations_dir?
|
58
|
+
end
|
59
|
+
|
60
|
+
def no_migrations?(database)
|
61
|
+
database.sequel_migrator.files.empty?
|
62
|
+
end
|
63
|
+
|
64
|
+
def warn_on_missing_migrations_dir(database)
|
65
|
+
out.puts <<~STR
|
66
|
+
WARNING: Database #{database.name} expects migrations to be located within #{relative_migrations_path(database)} but that folder does not exist.
|
67
|
+
|
68
|
+
No database migrations can be run for this database.
|
69
|
+
STR
|
70
|
+
end
|
71
|
+
|
72
|
+
def warn_on_empty_migrations_dir(database)
|
73
|
+
out.puts <<~STR
|
74
|
+
NOTE: Empty database migrations folder (#{relative_migrations_path(database)}) for #{database.name}
|
75
|
+
STR
|
76
|
+
end
|
77
|
+
|
78
|
+
def relative_migrations_path(database)
|
79
|
+
database
|
80
|
+
.migrations_path
|
81
|
+
.relative_path_from(database.slice.app.root)
|
82
|
+
.to_s + "/"
|
42
83
|
end
|
43
84
|
end
|
44
85
|
end
|
@@ -10,11 +10,21 @@ module Hanami
|
|
10
10
|
desc "Prepare databases"
|
11
11
|
|
12
12
|
def call(app: false, slice: nil, **)
|
13
|
-
|
13
|
+
command_exit = -> code { throw :command_exited, code }
|
14
|
+
command_exit_arg = {command_exit: command_exit}
|
14
15
|
|
16
|
+
# Since any slice may have multiple databases, we need to run the steps below in a
|
17
|
+
# particular order to satisfy our ROM/Sequel's migrator, which requires _all_ the
|
18
|
+
# databases in a slice to be created before we can use it.
|
19
|
+
#
|
20
|
+
# So before we do anything else, make sure to create/load every database first.
|
15
21
|
databases(app: app, slice: slice).each do |database|
|
16
|
-
|
17
|
-
|
22
|
+
command_args = {
|
23
|
+
**command_exit_arg,
|
24
|
+
app: database.slice.app?,
|
25
|
+
slice: database.slice,
|
26
|
+
gateway: database.gateway_name.to_s
|
27
|
+
}
|
18
28
|
|
19
29
|
exit_code = catch :command_exited do
|
20
30
|
unless database.exists?
|
@@ -22,17 +32,35 @@ module Hanami
|
|
22
32
|
run_command(DB::Structure::Load, **command_args)
|
23
33
|
end
|
24
34
|
|
25
|
-
run_command(DB::Migrate, **command_args)
|
26
|
-
run_command(DB::Seed, **command_args)
|
27
35
|
nil
|
28
36
|
end
|
29
37
|
|
30
|
-
|
38
|
+
return exit exit_code if exit_code.to_i > 1
|
31
39
|
end
|
32
40
|
|
33
|
-
|
34
|
-
|
41
|
+
# Once all databases are created, the migrator will properly load for each slice, and
|
42
|
+
# we can migrate each database.
|
43
|
+
databases(app: app, slice: slice).each do |database|
|
44
|
+
command_args = {
|
45
|
+
**command_exit_arg,
|
46
|
+
app: database.slice.app?,
|
47
|
+
slice: database.slice,
|
48
|
+
gateway: database.gateway_name.to_s
|
49
|
+
}
|
50
|
+
|
51
|
+
exit_code = catch :command_exited do
|
52
|
+
run_command(DB::Migrate, **command_args)
|
53
|
+
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
return exit exit_code if exit_code.to_i > 1
|
35
58
|
end
|
59
|
+
|
60
|
+
# Finally, load the seeds for the slice overall, which is a once-per-slice operation.
|
61
|
+
run_command(DB::Seed, app: app, slice: slice) unless re_running_in_test?
|
62
|
+
|
63
|
+
re_run_development_command_in_test
|
36
64
|
end
|
37
65
|
end
|
38
66
|
end
|
@@ -13,14 +13,30 @@ module Hanami
|
|
13
13
|
desc "Load seed data"
|
14
14
|
|
15
15
|
def call(app: false, slice: nil, **)
|
16
|
+
# We use `databases` below to discover the databases throughout the app and slices. It
|
17
|
+
# yields every database, so in a slice with multiple gateways, we'll see multiple
|
18
|
+
# databases for the slice.
|
19
|
+
#
|
20
|
+
# Since `db seed` is intended to run over whole slices only (not per-gateway), keep
|
21
|
+
# track of the seeded slices here, so we can avoid seeding a slice multiple times.
|
22
|
+
seeded_slices = []
|
23
|
+
|
16
24
|
databases(app: app, slice: slice).each do |database|
|
25
|
+
next if seeded_slices.include?(database.slice)
|
26
|
+
|
17
27
|
seeds_path = database.slice.root.join(SEEDS_PATH)
|
18
|
-
|
28
|
+
|
29
|
+
unless seeds_path.file?
|
30
|
+
out.puts "no seeds found at #{seeds_path.relative_path_from(database.slice.app.root)}"
|
31
|
+
next
|
32
|
+
end
|
19
33
|
|
20
34
|
relative_seeds_path = seeds_path.relative_path_from(database.slice.app.root)
|
21
35
|
measure "seed data loaded from #{relative_seeds_path}" do
|
22
36
|
load seeds_path.to_s
|
23
37
|
end
|
38
|
+
|
39
|
+
seeded_slices << database.slice
|
24
40
|
end
|
25
41
|
end
|
26
42
|
end
|