elasticgraph-local 0.17.1.4

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.
@@ -0,0 +1,538 @@
1
+ # Copyright 2024 Block, Inc.
2
+ #
3
+ # Use of this source code is governed by an MIT-style
4
+ # license that can be found in the LICENSE file or at
5
+ # https://opensource.org/licenses/MIT.
6
+ #
7
+ # frozen_string_literal: true
8
+
9
+ require "elastic_graph/admin/rake_tasks"
10
+ require "elastic_graph/local/docker_runner"
11
+ require "elastic_graph/schema_definition/rake_tasks"
12
+ require "rake/tasklib"
13
+ require "shellwords"
14
+
15
+ module ElasticGraph
16
+ # Provides support for developing and running ElasticGraph applications locally.
17
+ module Local
18
+ # Defines tasks for local development. These tasks include:
19
+ #
20
+ # - Running OpenSearch and/or Elasticsearch locally (`(elasticsearch|opensearch):[env]:(boot|daemon|halt)`)
21
+ # - Managing schema artifacts (`schema_artifacts:(check|dump)`)
22
+ # - Configuring OpenSearch/Elasticsearch locally (`clusters:configure:(dry_run|perform)`)
23
+ # - Indexing fake data (`index_fake_data:[type]`)
24
+ # - Booting an ElasticGraph application locally (`boot_locally`)
25
+ #
26
+ # @note All tasks (besides the `schema_artifacts` tasks) require `docker` and `docker-compose` to be available on your machine.
27
+ class RakeTasks < ::Rake::TaskLib
28
+ # When enabled, ElasticGraph will configure the index mappings so that the datastore indexes a `_size` field in each index document.
29
+ # ElasticGraph itself does not do anything with this field, but it will be available for your use in any direct queries (e.g. via
30
+ # Kibana).
31
+ #
32
+ # Defaults to `false` since it requires a plugin.
33
+ #
34
+ # @note Enabling this requires the [mapper-size plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/8.15/mapper-size.html)
35
+ # to be installed on your datastore cluster. You are responsible for ensuring that is installed if you enable this feature. If you
36
+ # enable this and the plugin is not installed, you will get errors!
37
+ #
38
+ # @return [Boolean] whether or not the `_size` field should be indexed on each indexed type
39
+ #
40
+ # @example Enable indexing document sizes
41
+ # ElasticGraph::Local::RakeTasks.new(
42
+ # local_config_yaml: "config/settings/local.yaml",
43
+ # path_to_schema: "config/schema.rb"
44
+ # ) do |tasks|
45
+ # tasks.index_document_sizes = true
46
+ # end
47
+ #
48
+ # @dynamic index_document_sizes, index_document_sizes=
49
+ attr_accessor :index_document_sizes
50
+
51
+ # The form of names for schema elements (fields, arguments, directives) generated by ElasticGraph, either `:snake_case` or
52
+ # `:camelCase`. For example, if set to `:camelCase`, ElasticGraph will generate a `groupedBy` field, but if set to `:snake_case`,
53
+ # ElasticGraph will generate a `grouped_by` field.
54
+ #
55
+ # Defaults to `:camelCase` since most GraphQL schemas use that casing.
56
+ #
57
+ # @return [:camelCase, :snake_case] which form to use
58
+ #
59
+ # @example Use `snake_case` names instead of `camelCase`
60
+ # ElasticGraph::Local::RakeTasks.new(
61
+ # local_config_yaml: "config/settings/local.yaml",
62
+ # path_to_schema: "config/schema.rb"
63
+ # ) do |tasks|
64
+ # tasks.schema_element_name_form = :snake_case
65
+ # end
66
+ #
67
+ # @dynamic schema_element_name_form, schema_element_name_form=
68
+ attr_accessor :schema_element_name_form
69
+
70
+ # Overrides for specific names of schema elements (fields, arguments, directives) generated by ElasticGraph. For example, to rename
71
+ # the `gt` filter field to `greaterThan`, set to `{gt: "greaterThan"}`.
72
+ #
73
+ # Defaults to an empty hash.
74
+ #
75
+ # @return [Hash<Symbol, String>] overrides for specific field, argument, or directive names
76
+ #
77
+ # @example Spell out comparison operators instead of using shortened forms
78
+ # ElasticGraph::Local::RakeTasks.new(
79
+ # local_config_yaml: "config/settings/local.yaml",
80
+ # path_to_schema: "config/schema.rb"
81
+ # ) do |tasks|
82
+ # tasks.schema_element_name_overrides = {
83
+ # gt: "greaterThan",
84
+ # gte: "greaterThanOrEqualTo",
85
+ # lt: "lessThan",
86
+ # lte: "lessThanOrEqualTo"
87
+ # }
88
+ # end
89
+ #
90
+ # @dynamic schema_element_name_overrides, schema_element_name_overrides=
91
+ attr_accessor :schema_element_name_overrides
92
+
93
+ # Overrides for the naming formats used by ElasticGraph for derived GraphQL type names. For example, to use `Metrics` instead of
94
+ # `AggregatedValues` as the suffix for the generated types supporting getting aggregated metrid values, set to
95
+ # `{AggregatedValues: "%{base}Metrics"}`. See {SchemaDefinition::SchemaElements::TypeNamer::DEFAULT_FORMATS} for the available
96
+ # formats.
97
+ #
98
+ # Defaults to an empty hash.
99
+ #
100
+ # @example Change the `AggregatedValues` type suffix to `Metrics`
101
+ # ElasticGraph::Local::RakeTasks.new(
102
+ # local_config_yaml: "config/settings/local.yaml",
103
+ # path_to_schema: "config/schema.rb"
104
+ # ) do |tasks|
105
+ # tasks.derived_type_name_formats = {AggregatedValues: "Metrics"}
106
+ # end
107
+ #
108
+ # @dynamic derived_type_name_formats, derived_type_name_formats=
109
+ attr_accessor :derived_type_name_formats
110
+
111
+ # Overrides for the names of specific GraphQL types. For example, to rename the `JsonSafeLong` scalar to `BigInt`, set to
112
+ # `{JsonSafeLong: "BigInt}`.
113
+ #
114
+ # Defaults to an empty hash.
115
+ #
116
+ # @return [Hash<Symbol, String>] overrides for specific type names
117
+ #
118
+ # @example Rename `JsonSafeLong` to `BigInt`
119
+ # ElasticGraph::Local::RakeTasks.new(
120
+ # local_config_yaml: "config/settings/local.yaml",
121
+ # path_to_schema: "config/schema.rb"
122
+ # ) do |tasks|
123
+ # tasks.type_name_overrides = {JsonSafeLong: "BigInt"}
124
+ # end
125
+ #
126
+ # @dynamic type_name_overrides, type_name_overrides=
127
+ attr_accessor :type_name_overrides
128
+
129
+ # Overrides for the names of specific GraphQL enum values for specific enum types. For example, to rename the `DayOfWeek.MONDAY`
130
+ # enum to `DayOfWeek.MON`, set to `{DayOfWeek: {MONDAY: "MON"}}`.
131
+ #
132
+ # Defaults to an empty hash.
133
+ #
134
+ # @return [Hash<Symbol, Hash<Symbol, String>>] overrides for the names of specific enum values for specific enum types
135
+ #
136
+ # @example Shorten the names of the `DayOfWeek` enum values
137
+ # ElasticGraph::Local::RakeTasks.new(
138
+ # local_config_yaml: "config/settings/local.yaml",
139
+ # path_to_schema: "config/schema.rb"
140
+ # ) do |tasks|
141
+ # tasks.enum_value_overrides_by_type = {
142
+ # DayOfWeek: {
143
+ # MONDAY: "MON",
144
+ # TUESDAY: "TUE",
145
+ # WEDNESDAY: "WED",
146
+ # THURSDAY: "THU",
147
+ # FRIDAY: "FRI",
148
+ # SATURDAY: "SAT",
149
+ # SUNDAY: "SUN"
150
+ # }
151
+ # }
152
+ # end
153
+ #
154
+ # @dynamic enum_value_overrides_by_type, enum_value_overrides_by_type=
155
+ attr_accessor :enum_value_overrides_by_type
156
+
157
+ # List of Ruby modules to extend onto the {SchemaDefinition::API} instance. Designed to support ElasticGraph extensions (such as
158
+ # `elasticgraph-apollo`). Defaults to an empty list.
159
+ #
160
+ # @return [Array<Module>] list of extension modules
161
+ #
162
+ # @example Extension that defines a `@since` directive and offers a `since` API on fields
163
+ # module SinceExtension
164
+ # # `self.extended` is a standard Ruby hook that gets called when a module is extended onto an object.
165
+ # # The argument is the object the module was extended onto (a `SchemaDefinition::API` instance in this case).
166
+ # def self.extended(api)
167
+ # # Define our `@since` directive
168
+ # api.raw_sdl "directive @since(date: Date!) on FIELD_DEFINITION"
169
+ #
170
+ # # In order to hook into fields, extend the `SchemaDefinition::Factory` with a module. The factory is used
171
+ # # for creation of all schema definition objects.
172
+ # api.factory.extend FactoryExtension
173
+ # end
174
+ #
175
+ # module FactoryExtension
176
+ # # Hook into the creation of all `SchemaDefinition::Field` objects so that we can extend each field
177
+ # # instance with our `FieldExtension` module.
178
+ # def new_field(*args, **options)
179
+ # super(*args, **options) do |field|
180
+ # field.extend FieldExtension
181
+ # yield field if block_given?
182
+ # end
183
+ # end
184
+ # end
185
+ #
186
+ # # Offer a `f.since date` API on fields.
187
+ # module FieldExtension
188
+ # def since(date)
189
+ # directive "since", date: date
190
+ # end
191
+ # end
192
+ # end
193
+ #
194
+ # ElasticGraph::Local::RakeTasks.new(
195
+ # local_config_yaml: "config/settings/local.yaml",
196
+ # path_to_schema: "config/schema.rb"
197
+ # ) do |tasks|
198
+ # tasks.schema_definition_extension_modules = [SinceExtension]
199
+ # end
200
+ #
201
+ # @dynamic schema_definition_extension_modules, schema_definition_extension_modules=
202
+ attr_accessor :schema_definition_extension_modules
203
+
204
+ # Whether or not to enforce the requirement that the JSON schema version is incremented every time
205
+ # dumping the JSON schemas results in a changed artifact. Defaults to `true`.
206
+ #
207
+ # @note Generally speaking, you will want this to be `true` for any ElasticGraph application that is in
208
+ # production as the versioning of JSON schemas is what supports safe schema evolution as it allows
209
+ # ElasticGraph to identify which version of the JSON schema the publishing system was operating on
210
+ # when it published an event.
211
+ #
212
+ # It can be useful to set it to `false` before your application is in production, as you do not want
213
+ # to be forced to bump the version after every single schema change while you are building an initial
214
+ # prototype.
215
+ #
216
+ # @return [Boolean] whether to require `json_schema_version` to be incremented on changes that impact `json_schemas.yaml`
217
+ # @see SchemaDefinition::API#json_schema_version
218
+ #
219
+ # @example Disable enforcement during initial prototyping
220
+ # ElasticGraph::Local::RakeTasks.new(
221
+ # local_config_yaml: "config/settings/local.yaml",
222
+ # path_to_schema: "config/schema.rb"
223
+ # ) do |tasks|
224
+ # # TODO: remove this once we're past the prototyping stage
225
+ # tasks.enforce_json_schema_version = false
226
+ # end
227
+ #
228
+ # @dynamic enforce_json_schema_version, enforce_json_schema_version=
229
+ attr_accessor :enforce_json_schema_version
230
+
231
+ # List of Elasticsearch versions you want to be able to boot. Rake tasks will be defined for each version to support booting and
232
+ # halting Elasticsearch locally. Defaults to the versions of Elasticsearch that are exercised by the ElasticGraph test suite, as
233
+ # defined by `lib/elastic_graph/local/tested_database_versions.yaml`:
234
+ #
235
+ # {include:file:elasticgraph-local/lib/elastic_graph/local/tested_database_versions.yaml}
236
+ #
237
+ # @return [Array<String>] list of Elasticsearch versions
238
+ # @see #opensearch_versions
239
+ #
240
+ # @example Disable Elasticsearch tasks for a project that uses OpenSearch
241
+ # ElasticGraph::Local::RakeTasks.new(
242
+ # local_config_yaml: "config/settings/local.yaml",
243
+ # path_to_schema: "config/schema.rb"
244
+ # ) do |tasks|
245
+ # tasks.elasticsearch_versions = []
246
+ # end
247
+ #
248
+ # @dynamic elasticsearch_versions, elasticsearch_versions=
249
+ attr_accessor :elasticsearch_versions
250
+
251
+ # List of OpenSearch versions you want to be able to boot. Rake tasks will be defined for each version to support booting and
252
+ # halting OpenSearch locally. Defaults to the versions of OpenSearch that are exercised by the ElasticGraph test suite, as
253
+ # defined by `lib/elastic_graph/local/tested_database_versions.yaml`:
254
+ #
255
+ # {include:file:elasticgraph-local/lib/elastic_graph/local/tested_database_versions.yaml}
256
+ #
257
+ # @return [Array<String>] list of OpenSearch versions
258
+ # @see #elasticsearch_versions
259
+ #
260
+ # @example Disable OpenSearch tasks for a project that uses Elasticsearch
261
+ # ElasticGraph::Local::RakeTasks.new(
262
+ # local_config_yaml: "config/settings/local.yaml",
263
+ # path_to_schema: "config/schema.rb"
264
+ # ) do |tasks|
265
+ # tasks.opensearch_versions = []
266
+ # end
267
+ #
268
+ # @dynamic opensearch_versions, opensearch_versions=
269
+ attr_accessor :opensearch_versions
270
+
271
+ # Hash mapping environments (e.g. `:test`, `:dev`, etc) to port numbers for use when booting Elasticsearch or OpenSearch. The hash
272
+ # automatically includes an entry for the `:local` environment, using a port number extracted from `local_config_yaml`.
273
+ #
274
+ # @note When booting Elasticsearch/OpenSearch, Kibana (or its OpenSearch equivalent, "OpenSearch Dashboards") will also get booted,
275
+ # selecting the port by adding `10000` to the configured port.
276
+ #
277
+ # @return [Hash<Symbol, Integer>] mapping from environment name to port number
278
+ #
279
+ # @example Define what port to use to boot the datastore for the `:test` environment
280
+ # ElasticGraph::Local::RakeTasks.new(
281
+ # local_config_yaml: "config/settings/local.yaml",
282
+ # path_to_schema: "config/schema.rb"
283
+ # ) do |tasks|
284
+ # tasks.env_port_mapping = {test: 9999}
285
+ # end
286
+ #
287
+ # @dynamic env_port_mapping, env_port_mapping=
288
+ attr_accessor :env_port_mapping
289
+
290
+ # IO for printing output (defaults to stdout).
291
+ #
292
+ # @return [IO] IO object used for printing output.
293
+ #
294
+ # @dynamic output, output=
295
+ attr_accessor :output
296
+
297
+ # Maximum time (in seconds) to wait for the datastore to boot when booting it as a daemon. Defaults to 120.
298
+ #
299
+ # @return [Integer] maximum time in seconds to wait when booting Elasticsearch/OpenSearch as a daemon
300
+ #
301
+ # @dynamic daemon_timeout, daemon_timeout=
302
+ attr_accessor :daemon_timeout
303
+
304
+ # Offset we add to a port number for the UI (e.g. Kibana or OpenSearch Dashboards).
305
+ #
306
+ # Example: if Elasticsearch/OpenSearch is running on port 9876, the UI for it will run on port 19876.
307
+ UI_PORT_OFFSET = 10_000
308
+
309
+ # As per https://en.wikipedia.org/wiki/Registered_port, valid user port numbers are 1024 to 49151, but
310
+ # with our UI offset we need to truncate the range further.
311
+ #
312
+ # @private
313
+ VALID_PORT_RANGE = 1024..(49151 - UI_PORT_OFFSET)
314
+
315
+ # Register a callback for use when indexing a batch fake data. An `index_fake_data:[type]` rake task will be generated for each
316
+ # registered callback.
317
+ #
318
+ # @param type [Symbol] type of data batch. Can be the name of a GraphQL type or any other name you want to give a batch of fake data
319
+ # @yield [Array<Hash<String, Object>>, Array<Hash<Symbol, Object>>] list the block should append to when generating data
320
+ # @yieldreturn [void]
321
+ #
322
+ # @example Register a callback to generate fake `campaigns` data
323
+ # ElasticGraph::Local::RakeTasks.new(
324
+ # local_config_yaml: "config/settings/local.yaml",
325
+ # path_to_schema: "config/schema.rb"
326
+ # ) do |tasks|
327
+ # tasks.define_fake_data_batch_for :campaigns do |batch|
328
+ # batch.concat(FactoryBot.build_list(:campaigns))
329
+ # end
330
+ # end
331
+ def define_fake_data_batch_for(type, &block)
332
+ @fake_data_batch_generator_by_type[type] = block
333
+ end
334
+
335
+ # @note This method uses keyword args for all required arguments. Optional task settings are instead specified using the block.
336
+ # @param local_config_yaml [String, Pathname] path to the settings YAML file for the local/development environment
337
+ # @param path_to_schema [String, Pathname] path to the Ruby schema definition file--either the only file that defines the schema
338
+ # (using `ElasticGraph.define_schema`) or the "main" schema definition file, which loads other files which further define parts of
339
+ # the schema.
340
+ # @yield [RakeTasks] instance for further configuration
341
+ # @yieldreturn [void]
342
+ def initialize(local_config_yaml:, path_to_schema:)
343
+ @local_config_yaml = local_config_yaml.to_s
344
+
345
+ self.index_document_sizes = false
346
+ self.schema_element_name_form = :camelCase
347
+ self.schema_element_name_overrides = {}
348
+ self.derived_type_name_formats = {}
349
+ self.type_name_overrides = {}
350
+ self.enum_value_overrides_by_type = {}
351
+ self.schema_definition_extension_modules = []
352
+ self.enforce_json_schema_version = true
353
+ self.env_port_mapping = {}
354
+ self.output = $stdout
355
+ self.daemon_timeout = 120
356
+
357
+ database_versions = ::YAML.load_file("#{__dir__}/tested_database_versions.yaml")
358
+ self.elasticsearch_versions = database_versions.fetch("elasticsearch")
359
+ self.opensearch_versions = database_versions.fetch("opensearch")
360
+
361
+ @fake_data_batch_generator_by_type = {}
362
+
363
+ yield self if block_given?
364
+
365
+ # Default the local port from the local_config_yaml file.
366
+ self.env_port_mapping = {"local" => local_datastore_port}.merge(env_port_mapping || {})
367
+ if (invalid_port_mapping = env_port_mapping.reject { |env, port| VALID_PORT_RANGE.cover?(port) }).any?
368
+ raise "`env_port_mapping` has invalid ports: #{invalid_port_mapping.inspect}. Valid ports must be in the #{VALID_PORT_RANGE} range."
369
+ end
370
+
371
+ # Load admin and schema def rake tasks...
372
+ Admin::RakeTasks.from_yaml_file(local_config_yaml, output: output)
373
+ SchemaDefinition::RakeTasks.new(
374
+ index_document_sizes: index_document_sizes,
375
+ path_to_schema: path_to_schema,
376
+ schema_artifacts_directory: local_config.fetch("schema_artifacts").fetch("directory"),
377
+ schema_element_name_form: schema_element_name_form,
378
+ schema_element_name_overrides: schema_element_name_overrides,
379
+ derived_type_name_formats: derived_type_name_formats,
380
+ type_name_overrides: type_name_overrides,
381
+ enum_value_overrides_by_type: enum_value_overrides_by_type,
382
+ extension_modules: schema_definition_extension_modules,
383
+ enforce_json_schema_version: enforce_json_schema_version,
384
+ output: output
385
+ )
386
+
387
+ # ...then define a bunch of our own.
388
+ define_docker_tasks("Elasticsearch", "Kibana", elasticsearch_versions, /license \[[^\]]+\] mode \[[^\]]+\] - valid/)
389
+ define_docker_tasks("OpenSearch", "OpenSearch Dashboards", opensearch_versions, /o\.o\.n\.Node.+started/)
390
+ define_other_tasks
391
+ end
392
+
393
+ private
394
+
395
+ def define_docker_tasks(description, ui_variant, versions, ready_log_line)
396
+ variant = description.downcase.to_sym
397
+ namespace variant do
398
+ env_port_mapping.each do |env, port|
399
+ namespace env do
400
+ versions.each do |version|
401
+ namespace version do
402
+ define_docker_tasks_for_version(description, variant, ui_variant, port: port, version: version, env: env, ready_log_line: ready_log_line)
403
+ end
404
+ end
405
+
406
+ if (max_version = versions.max_by { |v| Gem::Version.create(v) })
407
+ define_docker_tasks_for_version(description, variant, ui_variant, port: port, version: max_version, env: env, ready_log_line: ready_log_line)
408
+ end
409
+ end
410
+ end
411
+ end
412
+ end
413
+
414
+ def define_docker_tasks_for_version(description, variant, ui_variant, port:, version:, env:, ready_log_line:)
415
+ ui_port = port + UI_PORT_OFFSET
416
+
417
+ docker_runner = DockerRunner.new(
418
+ variant,
419
+ port: port,
420
+ ui_port: port + UI_PORT_OFFSET,
421
+ version: version,
422
+ env: env,
423
+ ready_log_line: ready_log_line,
424
+ output: output,
425
+ daemon_timeout: daemon_timeout
426
+ )
427
+
428
+ desc "Boots #{description} #{version} for the #{env} environment on port #{port} (and #{ui_variant} on port #{ui_port})"
429
+ task(:boot) { docker_runner.boot }
430
+
431
+ desc "Boots #{description} #{version} as a background daemon for the #{env} environment on port #{port} (and #{ui_variant} on port #{ui_port})"
432
+ task(:daemon) do |t|
433
+ docker_runner.boot_as_daemon(halt_command: "rake #{t.name.sub(/:\w+\z/, ":halt")}")
434
+ end
435
+
436
+ desc "Halts the #{description} #{version} daemon for the #{env} environment"
437
+ task(:halt) { docker_runner.halt }
438
+ end
439
+
440
+ def define_other_tasks
441
+ index_fake_data_tasks = @fake_data_batch_generator_by_type.keys.map do |type|
442
+ "index_fake_data:#{type}"
443
+ end
444
+
445
+ database_to_boot =
446
+ if elasticsearch_versions.empty? && opensearch_versions.empty?
447
+ raise "Both `elasticsearch_versions` and `opensearch_versions` are empty, but we need at least one of them to have a version in order to provide the boot tasks."
448
+ elsif elasticsearch_versions.empty?
449
+ "OpenSearch"
450
+ else
451
+ "Elasticsearch"
452
+ end
453
+
454
+ desc "Boots ElasticGraph locally from scratch: boots #{database_to_boot}, configures it, indexes fake data, and boots GraphiQL"
455
+ task :boot_locally, [:port, :rackup_args, :no_open] => ["#{database_to_boot.downcase}:local:daemon", *index_fake_data_tasks, "boot_graphiql"]
456
+
457
+ desc "Boots ElasticGraph locally with the GraphiQL UI, and opens it in a browser."
458
+ task :boot_graphiql, [:port, :rackup_args, :no_open] => :ensure_datastore_ready_for_indexing_and_querying do |task, args|
459
+ args.with_defaults(port: 9393, rackup_args: "", no_open: false)
460
+ port = args.fetch(:port)
461
+
462
+ # :nocov: -- we can't test `open` behavior through a test, and simplecov can't detect coverage in a subprocess.
463
+ unless args.fetch(:no_open)
464
+ fork do
465
+ sleep 3 # give the app a bit of time to boot before we try to open it.
466
+ sh "open http://localhost:#{port}/"
467
+ end
468
+ end
469
+ # :nocov:
470
+
471
+ sh "ELASTICGRAPH_YAML_FILE=#{@local_config_yaml.shellescape} bundle exec rackup #{::File.join(__dir__.to_s, "config.ru").shellescape} --port #{port} #{args.fetch(:rackup_args)}"
472
+ end
473
+
474
+ namespace :index_fake_data do
475
+ @fake_data_batch_generator_by_type.each do |type, generator|
476
+ desc "Indexes num_batches of #{type} fake data into the local datastore"
477
+ task type, [:num_batches] => :ensure_datastore_ready_for_indexing_and_querying do |task, args|
478
+ require "elastic_graph/local/local_indexer"
479
+ args.with_defaults(num_batches: 1)
480
+ LocalIndexer.new(@local_config_yaml, generator, output: output).index_fake_data(Integer(args[:num_batches]))
481
+ end
482
+ end
483
+ end
484
+
485
+ task :ensure_local_datastore_running do
486
+ unless /200 OK/.match?(`curl -is localhost:#{local_datastore_port}`)
487
+ if elasticsearch_versions.empty?
488
+ raise <<~EOS
489
+ OpenSearch is not running locally. You need to start it in another terminal using this command:
490
+
491
+ bundle exec rake opensearch:local:boot
492
+ EOS
493
+ elsif opensearch_versions.empty?
494
+ raise <<~EOS
495
+ Elasticsearch is not running locally. You need to start it in another terminal using this command:
496
+
497
+ bundle exec rake elasticsearch:local:boot
498
+ EOS
499
+ else
500
+ raise <<~EOS
501
+ Neither Elasticsearch nor OpenSearch are running locally. You need to start one of them in another terminal using one of these commands:
502
+
503
+ bundle exec rake elasticsearch:local:boot
504
+ bundle exec rake opensearch:local:boot
505
+ EOS
506
+ end
507
+ end
508
+ end
509
+
510
+ task ensure_datastore_ready_for_indexing_and_querying: [
511
+ :ensure_local_datastore_running,
512
+ "schema_artifacts:dump",
513
+ "clusters:configure:perform"
514
+ ]
515
+
516
+ namespace "clusters:configure" do
517
+ %i[dry_run perform].each do |subtask|
518
+ desc "(after first dumping the schema artifacts)"
519
+ task subtask => [:ensure_local_datastore_running, "schema_artifacts:dump"]
520
+ end
521
+ end
522
+ end
523
+
524
+ def local_datastore_port
525
+ @local_datastore_port ||= local_config
526
+ .fetch("datastore")
527
+ .fetch("clusters")
528
+ .fetch("main")
529
+ .fetch("url")[/localhost:(\d+)$/, 1]
530
+ .then { |port_str| Integer(port_str) }
531
+ end
532
+
533
+ def local_config
534
+ @local_config ||= ::YAML.safe_load_file(@local_config_yaml, aliases: true)
535
+ end
536
+ end
537
+ end
538
+ end
@@ -0,0 +1,8 @@
1
+ # @markup text
2
+ # This file determines the versions the ElasticGraph CI build tests against, and is also
3
+ # used to provide the default versions offered by the `elasticgraph-local` rake tasks.
4
+ elasticsearch:
5
+ - 8.14.1 # latest version as of 2024-07-02.
6
+ opensearch:
7
+ - 2.15.0 # latest version as of 2024-07-02.
8
+ - 2.7.0 # lowest version ElasticGraph currently supports