regolith 0.1.19 → 0.1.20

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f4a42e2d4a1c0be079dff218128afc9451aeff7dae6c97f1c93ca5a43eb4ee9
4
- data.tar.gz: 5783be43db0adbe9ac420f14190f4c8959130be1bcf9d94409549fb49bb301bd
3
+ metadata.gz: bc4410cdbfbd1a5f314f784309bc88d2b0d6b9e3bbcda0bd6a3d49e74893ba95
4
+ data.tar.gz: 7b4b961f4c89d92943070dd8f30ee4067bf6a61d5a3e3d73f1ab18ee3face259
5
5
  SHA512:
6
- metadata.gz: 8f82bd5a6ec97d8924eceb852ce49541808dc53483492968e1fbe9885cca0924d9a173f592e391afa95d6755dbe34d1d1eda89268bf9aadfcb5e2980dc2e200c
7
- data.tar.gz: 462938815ddc6d7fbc4a7ea8c225e578538b90e824e13fc28a7dc4f153ba6e7379d72706b2223bef91782d63fbeea9c432f20b9f3f5eb9736d5828afaeb123b7
6
+ metadata.gz: d2373e922caf22b534c57aec574f527805489466cbc229c3187c937c48a5b985781e8632ffbc37fadcf0cbd6ad299f6278c2d661c34b7a00ecdd7c25329a36db
7
+ data.tar.gz: d9e47728449fae4bc0198e2c3dc7e831898d48cd76b7e30a7ac4dad77f662e90e0f93118e02e7ab50505c8b3f084d3bcabcba363fed38a0be30b18eb499f4f1a
data/lib/regolith/cli.rb CHANGED
@@ -1,62 +1,10 @@
1
1
  require 'fileutils'
2
2
  require 'yaml'
3
- require 'psych'
4
3
  require 'erb'
5
4
  require 'timeout'
6
5
  require 'rubygems'
7
- require 'net/http'
8
- require 'uri'
9
- require 'json'
10
- require 'ostruct'
11
- require 'set'
12
- require 'rbconfig'
13
- require 'shellwords'
14
6
 
15
7
  module Regolith
16
- # NOTE: VERSION is defined in lib/regolith/version.rb.
17
- # Do not define Regolith::VERSION here to avoid constant redefinition warnings.
18
-
19
- class << self
20
- # Lightweight configuration with sane defaults
21
- def configuration
22
- @configuration ||= OpenStruct.new(
23
- timeout: 10,
24
- default_port: 3001
25
- )
26
- end
27
-
28
- def service_registry
29
- @service_registry ||= begin
30
- path = find_regolith_config
31
- if path && File.exist?(path)
32
- config = YAML.load_file(path) || {}
33
- config['services'] || {}
34
- else
35
- {}
36
- end
37
- end
38
- end
39
-
40
- def reload_service_registry!
41
- @service_registry = nil
42
- end
43
-
44
- private
45
-
46
- def find_regolith_config
47
- current_dir = Dir.pwd
48
- loop do
49
- config_path = File.join(current_dir, 'config', 'regolith.yml')
50
- return config_path if File.exist?(config_path)
51
-
52
- parent = File.dirname(current_dir)
53
- break if parent == current_dir
54
- current_dir = parent
55
- end
56
- nil
57
- end
58
- end
59
-
60
8
  class CLI
61
9
  def initialize(args)
62
10
  @args = args
@@ -71,47 +19,11 @@ module Regolith
71
19
  create_new_app(@subcommand)
72
20
  when 'generate'
73
21
  generate_resource(@subcommand, @name)
74
- when 'server', 'up'
75
- start_server(parse_flags(@args[1..-1]))
76
- when 'down'
77
- stop_services
78
- when 'restart'
79
- restart_service(@subcommand)
80
- when 'stop'
81
- stop_service(@subcommand)
82
- when 'ps', 'status'
83
- show_status
84
- when 'logs'
85
- show_logs(@subcommand, parse_flags(@args[2..-1]))
86
- when 'exec'
87
- exec_command(@subcommand, @args[2..-1])
88
- when 'shell'
89
- shell_service(@subcommand)
22
+ when 'server'
23
+ start_server
90
24
  when 'console'
91
25
  open_console(@subcommand)
92
- when 'rails'
93
- rails_passthrough(@subcommand, @args[2..-1])
94
- when 'routes'
95
- show_routes(@subcommand)
96
- when 'open'
97
- open_service(@subcommand)
98
- when 'db'
99
- db_command(@subcommand, @name, parse_flags(@args[3..-1]))
100
- when 'test'
101
- run_tests(@subcommand, parse_flags(@args[2..-1]))
102
- when 'health'
103
- health_check
104
- when 'config'
105
- show_config(parse_flags(@args[1..-1]))
106
- when 'prune'
107
- prune_system
108
- when 'rebuild'
109
- rebuild_service(@subcommand)
110
- when 'doctor'
111
- run_doctor
112
- when 'inspect'
113
- inspect_services(parse_flags(@args[1..-1]))
114
- when 'version', '--version', '-v'
26
+ when 'version'
115
27
  puts "Regolith #{Regolith::VERSION}"
116
28
  else
117
29
  show_help
@@ -120,23 +32,6 @@ module Regolith
120
32
 
121
33
  private
122
34
 
123
- def parse_flags(args)
124
- flags = {}
125
- return flags unless args
126
-
127
- args.each do |arg|
128
- if arg.start_with?('--')
129
- key, value = arg[2..-1].split('=', 2)
130
- flags[key.to_sym] = value || true
131
- elsif arg == '-f'
132
- flags[:follow] = true
133
- elsif arg == '--all'
134
- flags[:all] = true
135
- end
136
- end
137
- flags
138
- end
139
-
140
35
  def create_new_app(app_name)
141
36
  unless app_name
142
37
  puts "❌ Error: App name required"
@@ -174,8 +69,6 @@ module Regolith
174
69
  File.write('docker-compose.yml', generate_docker_compose(app_name))
175
70
  File.write('Makefile', generate_makefile)
176
71
  File.write('.bin/regolith', generate_regolith_shim)
177
- File.write('.gitignore', generate_gitignore)
178
- File.write('README.md', generate_readme(app_name))
179
72
  FileUtils.chmod(0755, '.bin/regolith')
180
73
  end
181
74
 
@@ -190,16 +83,9 @@ module Regolith
190
83
  end
191
84
 
192
85
  def generate_service(service_name)
193
- # Validate service name
194
- unless service_name =~ /\A[a-z][a-z0-9_]*\z/
195
- puts "❌ Invalid service name. Use lowercase, digits, and underscores only."
196
- puts "Examples: users, user_profiles, api_gateway"
197
- exit 1
198
- end
199
-
200
86
  puts "🔧 Creating service '#{service_name}'..."
201
87
  config = load_regolith_config
202
- port = next_available_port
88
+ port = 3001 + (config['services']&.size || 0)
203
89
  service_dir = "services/#{service_name}_service"
204
90
 
205
91
  puts " → Generating Rails API app..."
@@ -230,239 +116,110 @@ module Regolith
230
116
  exit 1
231
117
  end
232
118
 
233
- customize_service(service_dir, service_name, port)
119
+ # Overwrite Gemfile before bundle install
120
+ puts "🔧 Overwriting Gemfile to remove sqlite3 and other defaults..."
121
+
122
+ major_minor = `ruby -e 'print RUBY_VERSION.split(".")[0..1].join(".")'`.strip
234
123
 
235
- config['services'][service_name] = {
236
- 'port' => port,
237
- 'root' => "./#{service_dir}"
238
- }
124
+ custom_gemfile = <<~GEMFILE
125
+ source "https://rubygems.org"
239
126
 
240
- save_regolith_config(config)
241
- update_docker_compose(config)
127
+ ruby "~> #{major_minor}.0"
242
128
 
243
- puts " Created service '#{service_name}'"
244
- puts "🚀 Service will run on port #{port}"
245
- puts " Next: regolith generate service <another_service> or regolith server"
246
- end
129
+ gem "rails", "~> 7.2.2.1"
130
+ gem "pg", "~> 1.5"
131
+ gem "puma", ">= 5.0"
132
+ gem "rack-cors"
247
133
 
248
- def next_available_port(start = (Regolith.configuration.respond_to?(:default_port) ? Regolith.configuration.default_port : 3001))
249
- used = load_regolith_config['services'].values.map { |s| s['port'] }.to_set
250
- port = start
251
- port += 1 while used.include?(port)
252
- port
253
- end
134
+ group :development, :test do
135
+ gem "debug", platforms: %i[ mri mswin mswin64 mingw x64_mingw ], require: "debug/prelude"
136
+ gem "brakeman", require: false
137
+ gem "rubocop-rails-omakase", require: false
138
+ end
254
139
 
255
- def customize_service(service_dir, service_name, port)
256
- # Detect Ruby MAJOR.MINOR
257
- major_minor = RUBY_VERSION.split(".")[0..1].join(".")
140
+ gem "regolith", path: "vendor/regolith"
141
+ GEMFILE
258
142
 
259
- # Write Gemfile (no vendoring; pull from RubyGems)
260
- custom_gemfile = generate_gemfile(major_minor)
261
143
  File.write("#{service_dir}/Gemfile", custom_gemfile)
262
144
 
145
+ # Vendor Regolith gem into service for Docker compatibility
146
+ vendor_dir = File.join(service_dir, "vendor")
147
+ FileUtils.mkdir_p(vendor_dir)
148
+ FileUtils.cp_r(File.expand_path("../..", __dir__), File.join(vendor_dir, "regolith"))
149
+ puts "📦 Vendored Regolith gem into #{File.join(service_dir, 'vendor', 'regolith')}"
150
+
263
151
  puts " → Running bundle install..."
264
152
  Dir.chdir(service_dir) do
265
153
  unless system("bundle install")
266
154
  puts "❌ bundle install failed"
267
- puts "→ You may be missing system libraries like libyaml-dev build-essential"
155
+ puts "→ You may be missing system libraries like libyaml-dev libsqlite3-dev build-essential pkg-config"
156
+ puts "→ Try: sudo apt install -y libyaml-dev libsqlite3-dev build-essential pkg-config"
268
157
  exit 1
269
158
  end
270
159
  end
271
160
 
272
161
  patch_rails_app(service_dir, service_name, port)
273
- end
274
-
275
- def generate_gemfile(ruby_version)
276
- <<~GEMFILE
277
- source "https://rubygems.org"
278
-
279
- ruby "~> #{ruby_version}.0"
280
162
 
281
- gem "rails", "~> 7.2.2.1"
282
- gem "pg", "~> 1.5"
283
- gem "puma", ">= 5.0"
284
- gem "rack-cors"
285
- gem "bootsnap", require: false
286
-
287
- group :development, :test do
288
- gem "debug", platforms: %i[mri mswin mswin64 mingw x64_mingw], require: "debug/prelude"
289
- gem "brakeman", require: false
290
- gem "rubocop-rails-omakase", require: false
291
- end
163
+ config['services'][service_name] = {
164
+ 'port' => port,
165
+ 'root' => "./#{service_dir}"
166
+ }
167
+ save_regolith_config(config)
168
+ update_docker_compose(config)
292
169
 
293
- gem "regolith"
294
- GEMFILE
170
+ puts "✅ Created service '#{service_name}'"
171
+ puts "🚀 Service running on port #{port}"
172
+ puts "→ Next: regolith generate service <another_service> or regolith server"
295
173
  end
296
174
 
297
175
  def patch_rails_app(service_dir, service_name, port)
298
- create_initializers(service_dir, service_name)
299
- create_health_controller(service_dir)
300
- add_health_route(service_dir)
301
- File.write("#{service_dir}/Dockerfile", generate_dockerfile)
302
- patch_application_rb(service_dir, service_name, port)
303
- end
304
-
305
- def create_initializers(service_dir, service_name)
306
176
  initializer_dir = "#{service_dir}/config/initializers"
307
177
  FileUtils.mkdir_p(initializer_dir)
308
-
309
178
  File.write("#{initializer_dir}/regolith.rb", generate_regolith_initializer(service_name))
310
- File.write("#{initializer_dir}/cors.rb", generate_cors_initializer)
311
- end
312
-
313
- def create_health_controller(service_dir)
314
- controller_dir = "#{service_dir}/app/controllers/regolith"
315
- FileUtils.mkdir_p(controller_dir)
316
-
317
- File.write("#{controller_dir}/health_controller.rb", generate_health_controller)
318
- end
319
-
320
- def add_health_route(service_dir)
321
- routes_path = File.join(service_dir, "config/routes.rb")
322
- content = File.read(routes_path)
323
-
324
- # Try to inject before the final end, or append if no clear structure
325
- if content.sub!(/end\s*\z/, " get '/health', to: 'regolith/health#show'\nend\n")
326
- File.write(routes_path, content)
327
- else
328
- # Fallback: append inside the draw block
329
- File.open(routes_path, "a") { |f| f.puts "get '/health', to: 'regolith/health#show'" }
330
- end
331
- end
179
+ File.write("#{service_dir}/Dockerfile", generate_dockerfile)
332
180
 
333
- def patch_application_rb(service_dir, service_name, port)
334
181
  app_rb_path = "#{service_dir}/config/application.rb"
335
182
  app_rb_content = File.read(app_rb_path)
336
183
 
337
184
  cors_config = <<~RUBY
338
185
 
339
186
  # Regolith configuration
187
+ config.middleware.insert_before 0, Rack::Cors do
188
+ allow do
189
+ origins '*'
190
+ resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head]
191
+ end
192
+ end
193
+
340
194
  config.regolith_service_name = '#{service_name}'
341
195
  config.regolith_service_port = #{port}
342
196
  RUBY
343
197
 
344
- app_rb_content.gsub!(/(\n end\n\z)/, "#{cors_config}\1")
198
+ app_rb_content.gsub!(/class Application < Rails::Application.*?
199
+ end/m) do |match|
200
+ match.gsub(/(\n end)$/, "#{cors_config}\1")
201
+ end
202
+
345
203
  File.write(app_rb_path, app_rb_content)
346
204
  end
347
205
 
348
- # Service management commands
349
- def start_server(_flags = {})
206
+ def start_server
350
207
  unless File.exist?('docker-compose.yml')
351
208
  puts "❌ Error: Not in a Regolith app directory"
352
209
  exit 1
353
210
  end
354
211
 
355
212
  puts "🚀 Starting Regolith services..."
356
-
357
213
  config = load_regolith_config
358
- show_service_info(config)
359
-
360
- exec_compose('up', '--build')
361
- end
362
-
363
- def stop_services
364
- puts "🛑 Stopping all services..."
365
- exec_compose('down', '-v')
366
- end
367
-
368
- def restart_service(service_name = nil)
369
- if service_name
370
- ensure_service_exists!(service_name)
371
- puts "🔄 Restarting service '#{service_name}'..."
372
- exec_compose('restart', service_name)
373
- else
374
- puts "🔄 Restarting all services..."
375
- exec_compose('restart')
376
- end
377
- end
378
-
379
- def stop_service(service_name = nil)
380
- if service_name
381
- ensure_service_exists!(service_name)
382
- puts "⏹ Stopping service '#{service_name}'..."
383
- exec_compose('stop', service_name)
384
- else
385
- puts "⏹ Stopping all services..."
386
- exec_compose('stop')
387
- end
388
- end
389
-
390
- def show_status
391
- puts "📊 Service Status:"
392
- puts
393
-
394
- # Try different format options for maximum compatibility
395
- success = system_compose('ps', '--format', 'table') ||
396
- system_compose('ps', '--format', 'json') ||
397
- system_compose('ps')
398
-
399
- # Show summary counts and health check for exit code
400
- if success
401
- config = load_regolith_config
402
- service_count = config['services'].size
403
- ports = config['services'].values.map { |s| s['port'] }.sort
404
-
405
- puts
406
- puts "📋 Summary: #{service_count} services configured"
407
- puts "🚪 Ports: #{ports.join(', ')}" if ports.any?
408
-
409
- # Check health for proper exit code
410
- healthy_services = 0
411
- config['services'].each do |name, service_config|
412
- port = service_config['port']
413
- status = check_service_health(port)
414
- healthy_services += 1 if status[:healthy]
415
- end
416
-
417
- if healthy_services < service_count
418
- puts "⚠️ #{service_count - healthy_services} services unhealthy"
419
- exit 1
420
- end
421
- end
422
- end
423
-
424
- def show_logs(service_name = nil, flags = {})
425
- args = ['logs']
426
- args << '--follow' if flags[:follow] || flags[:f]
427
- args << service_name if service_name
428
-
429
- exec_compose(*args)
430
- end
431
-
432
- def exec_command(service_name, command_args)
433
- ensure_service_exists!(service_name)
434
-
435
- if command_args.empty?
436
- command_args = ['bash']
437
- end
438
214
 
439
- exec_compose('exec', service_name, *command_args)
440
- end
441
-
442
- def shell_service(service_name)
443
- unless service_name
444
- puts "❌ Error: Service name required"
445
- puts "Usage: regolith shell <service_name>"
446
- exit 1
215
+ config['services'].each do |name, service|
216
+ puts "🚀 #{name}_service running at http://localhost:#{service['port']}"
447
217
  end
448
218
 
449
- ensure_service_exists!(service_name)
450
- puts "🐚 Opening shell for #{service_name}_service..."
451
- exec_compose('exec', service_name, 'bash')
452
- end
453
-
454
- # Rails integration commands
455
- def rails_passthrough(service_name, rails_args)
456
- ensure_service_exists!(service_name)
219
+ puts "🧭 Service registry loaded from config/regolith.yml"
220
+ puts ""
457
221
 
458
- if rails_args.empty?
459
- puts "❌ Error: Rails command required"
460
- puts "Usage: regolith rails <service> <command>"
461
- exit 1
462
- end
463
-
464
- exec_compose('exec', service_name, 'bash', '-lc',
465
- "bundle exec rails #{Shellwords.join(rails_args)}")
222
+ exec("docker-compose up --build")
466
223
  end
467
224
 
468
225
  def open_console(service_name)
@@ -472,300 +229,19 @@ module Regolith
472
229
  exit 1
473
230
  end
474
231
 
475
- ensure_service_exists!(service_name)
476
- puts "🧪 Opening Rails console for #{service_name}_service..."
477
- exec_compose('exec', service_name, 'rails', 'console')
478
- end
479
-
480
- def open_service(service_name)
481
- unless service_name
482
- puts "❌ Error: Service name required"
483
- puts "Usage: regolith open <service_name>"
484
- exit 1
485
- end
486
-
487
- ensure_service_exists!(service_name)
488
- config = load_regolith_config
489
- port = config['services'][service_name]['port']
490
- url = "http://localhost:#{port}"
491
-
492
- puts "🌐 Opening #{url}..."
493
-
494
- # Cross-platform open command
495
- case RbConfig::CONFIG['host_os']
496
- when /mswin|mingw|cygwin/
497
- system(%{start "" "#{url}"})
498
- when /darwin/
499
- system("open #{url}")
500
- else
501
- system("xdg-open #{url}") || puts("Visit: #{url}")
502
- end
503
- end
504
-
505
- # Database commands
506
- def db_command(action, target, flags = {})
507
- case action
508
- when 'create', 'migrate', 'seed', 'reset', 'setup', 'drop'
509
- each_target_service(target, flags) do |service|
510
- puts "🗄 Running db:#{action} for #{service}..."
511
- success = system_compose('exec', service, 'bash', '-lc', "bundle exec rails db:#{action}")
512
-
513
- unless success
514
- puts "❌ db:#{action} failed for #{service} (exit code: #{$?.exitstatus})"
515
- exit 1 unless flags[:continue_on_failure]
516
- end
517
- end
518
- else
519
- puts "❌ Unknown db action: #{action}"
520
- puts "Available: create, migrate, seed, reset, setup, drop"
521
- exit 1
522
- end
523
- end
524
-
525
- # Testing commands
526
- def run_tests(target = nil, flags = {})
527
- each_target_service(target, flags) do |service|
528
- puts "🧪 Running tests for #{service}..."
529
- success = system_compose('exec', service, 'bash', '-lc', 'bundle exec rails test')
530
-
531
- unless success
532
- puts "❌ Tests failed for #{service} (exit code: #{$?.exitstatus})"
533
- exit 1 unless flags[:continue_on_failure]
534
- end
535
- end
536
-
537
- puts "✅ All tests passed!" if flags[:all]
538
- end
539
-
540
- def show_routes(service_name)
541
- unless service_name
542
- puts "❌ Error: Service name required"
543
- puts "Usage: regolith routes <service_name>"
544
- exit 1
545
- end
546
-
547
- ensure_service_exists!(service_name)
548
- puts "🛤 Routes for #{service_name}:"
549
- system_compose('exec', service_name, 'bash', '-lc', 'bundle exec rails routes')
550
- end
551
-
552
- # Health and monitoring
553
- def health_check
554
- puts "🔍 Health Check Results:"
555
- puts
556
-
557
- config = load_regolith_config
558
-
559
- config['services'].each do |name, service_config|
560
- port = service_config['port']
561
- status = check_service_health(port)
562
-
563
- status_icon = status[:healthy] ? '✅' : '❌'
564
- puts "#{status_icon} #{name} (port #{port}) - #{status[:message]}"
565
-
566
- # Show additional health data if available
567
- if status[:data] && status[:data]['version']
568
- puts " Version: #{status[:data]['version']}"
569
- end
570
- if status[:data] && status[:data]['time']
571
- puts " Last seen: #{Time.at(status[:data]['time']).strftime('%H:%M:%S')}"
572
- end
573
- end
574
- end
575
-
576
- def check_service_health(port)
577
- begin
578
- uri = URI("http://localhost:#{port}/health")
579
- response = Net::HTTP.get_response(uri)
580
-
581
- if response.code.to_i == 200
582
- # Try to parse structured health data
583
- health_data = JSON.parse(response.body) rescue {}
584
- {
585
- healthy: true,
586
- message: 'healthy',
587
- data: health_data
588
- }
589
- else
590
- { healthy: false, message: "HTTP #{response.code}" }
591
- end
592
- rescue
593
- { healthy: false, message: 'unreachable' }
594
- end
595
- end
596
-
597
- # Configuration
598
- def show_config(flags = {})
599
232
  config = load_regolith_config
600
-
601
- if flags[:json]
602
- puts JSON.pretty_generate(config)
603
- else
604
- puts "📋 Current Configuration:"
605
- puts
606
- puts YAML.dump(config)
607
- end
608
- end
609
-
610
- # Maintenance commands
611
- def prune_system
612
- puts "🧹 Pruning Docker system..."
613
- exec_compose('down', '-v')
614
- system('docker', 'system', 'prune', '-f')
615
- puts "✅ System pruned"
616
- end
617
-
618
- def rebuild_service(service_name = nil)
619
- if service_name
620
- ensure_service_exists!(service_name)
621
- puts "🔨 Rebuilding service '#{service_name}'..."
622
- exec_compose('build', '--no-cache', service_name)
623
- else
624
- puts "🔨 Rebuilding all services..."
625
- exec_compose('build', '--no-cache')
626
- end
627
- end
628
-
629
- # System diagnostics
630
- def run_doctor
631
- puts "🩺 Regolith System Doctor"
632
- puts "=" * 40
633
-
634
- checks = [
635
- { name: "Docker", check: -> { system('docker --version > /dev/null 2>&1') } },
636
- { name: "Docker Compose", check: -> { docker_compose_available? } },
637
- { name: "Ruby", check: -> { system('ruby --version > /dev/null 2>&1') } },
638
- { name: "Rails", check: -> { system('rails --version > /dev/null 2>&1') } },
639
- { name: "PostgreSQL Client", check: -> { system('psql --version > /dev/null 2>&1') } }
640
- ]
641
-
642
- checks.each do |check|
643
- status = check[:check].call ? "✅" : "❌"
644
- puts "#{status} #{check[:name]}"
645
- end
646
-
647
- puts
648
- check_regolith_config
649
- end
650
-
651
- def check_regolith_config
652
- puts "📋 Checking Regolith configuration..."
653
-
654
- if File.exist?('config/regolith.yml')
655
- config = load_regolith_config
656
-
657
- if config['services'].empty?
658
- puts "⚠️ No services configured"
659
- else
660
- puts "✅ Configuration valid (#{config['services'].size} services)"
661
- end
662
- else
663
- puts "❌ No regolith.yml found - not in a Regolith project?"
664
- end
665
- end
666
-
667
- def inspect_services(flags = {})
668
- puts "🔍 Regolith Services Inspection"
669
- puts "=" * 40
670
-
671
- config = load_regolith_config
672
-
673
- if config['services'].empty?
674
- puts "No services configured yet."
675
- return
676
- end
677
-
678
- if flags[:json]
679
- # JSON output for automation
680
- inspection_data = {
681
- services: config['services'].map do |name, service_config|
682
- {
683
- name: name,
684
- port: service_config['port'],
685
- endpoint: "http://localhost:#{service_config['port']}",
686
- root: service_config['root']
687
- }
688
- end,
689
- config: config
690
- }
691
- puts JSON.pretty_generate(inspection_data)
692
- else
693
- # Human-readable output
694
- puts "\n📊 Service Endpoints:"
695
- config['services'].each do |name, service_config|
696
- port = service_config['port']
697
- puts " #{name}: http://localhost:#{port}"
698
- end
699
-
700
- puts "\n📋 Full Configuration:"
701
- puts YAML.dump(config)
702
- end
703
- end
704
-
705
- # Helper methods
706
- def docker_compose_available?
707
- system('docker compose version > /dev/null 2>&1') ||
708
- system('docker-compose version > /dev/null 2>&1')
709
- end
710
-
711
- def docker_compose_command
712
- if system('docker compose version > /dev/null 2>&1')
713
- %w[docker compose]
714
- elsif system('docker-compose version > /dev/null 2>&1')
715
- %w[docker-compose]
716
- else
717
- puts "❌ Docker Compose not found"
233
+ unless config['services'][service_name]
234
+ puts "❌ Error: Service '#{service_name}' not found"
718
235
  exit 1
719
236
  end
720
- end
721
-
722
- def exec_compose(*args)
723
- cmd = docker_compose_command + args
724
- exec(*cmd)
725
- end
726
237
 
727
- def system_compose(*args)
728
- cmd = docker_compose_command + args
729
- system(*cmd)
730
- end
731
-
732
- def each_target_service(target, flags = {})
733
- services = if target == '--all' || target.nil? || flags[:all]
734
- load_regolith_config['services'].keys
735
- else
736
- [target]
737
- end
738
-
739
- services.each do |service|
740
- ensure_service_exists!(service)
741
- yield(service)
742
- end
743
- end
744
-
745
- def ensure_service_exists!(service_name)
746
- config = load_regolith_config
747
- unless config['services'].key?(service_name)
748
- puts "❌ Service '#{service_name}' not found"
749
- puts "Available services: #{config['services'].keys.join(', ')}"
750
- exit 1
751
- end
752
- end
753
-
754
- def show_service_info(config)
755
- config['services'].each do |name, service|
756
- puts "🚀 #{name}_service: http://localhost:#{service['port']}"
757
- end
758
-
759
- puts "🧭 Service registry: config/regolith.yml"
760
- puts
238
+ puts "🧪 Opening Rails console for #{service_name}_service..."
239
+ exec("docker-compose exec #{service_name} rails console")
761
240
  end
762
241
 
763
242
  def load_regolith_config
764
- config_path = Regolith.send(:find_regolith_config)
765
- return { 'services' => {} } unless config_path && File.exist?(config_path)
766
-
767
- # Use safe YAML loading
768
- config = Psych.safe_load(File.read(config_path), permitted_classes: [], aliases: false) || {}
243
+ return { 'services' => {} } unless File.exist?('config/regolith.yml')
244
+ config = YAML.load_file('config/regolith.yml') || {}
769
245
  config['services'] ||= {}
770
246
  config
771
247
  end
@@ -773,7 +249,6 @@ module Regolith
773
249
  def save_regolith_config(config)
774
250
  FileUtils.mkdir_p('config')
775
251
  File.write('config/regolith.yml', YAML.dump(config))
776
- Regolith.reload_service_registry!
777
252
  end
778
253
 
779
254
  def update_docker_compose(config)
@@ -781,91 +256,57 @@ module Regolith
781
256
  File.write('docker-compose.yml', docker_compose)
782
257
  end
783
258
 
784
- # File generators
785
259
  def generate_docker_compose(app_name, services = {})
786
- compose_services = {
787
- 'db' => {
788
- 'image' => 'postgres:14',
789
- 'environment' => {
790
- 'POSTGRES_DB' => "#{app_name}_development",
791
- 'POSTGRES_USER' => 'postgres',
792
- 'POSTGRES_PASSWORD' => 'password'
793
- },
794
- 'ports' => ['5432:5432'],
795
- 'volumes' => ['postgres_data:/var/lib/postgresql/data'],
796
- 'networks' => ['regolith'],
797
- 'healthcheck' => {
798
- 'test' => ['CMD-SHELL', 'pg_isready -U postgres'],
799
- 'interval' => '10s',
800
- 'timeout' => '5s',
801
- 'retries' => 5
802
- }
803
- }
804
- }
805
-
806
- services.each do |name, service|
807
- db_name = "#{app_name}_#{name}_development" # ← per-service DB
808
-
809
- compose_services[name] = {
810
- 'build' => {
811
- 'context' => service['root'],
812
- 'args' => { 'BUILD_ENV' => 'development' }
813
- },
814
- 'ports' => ["#{service['port']}:3000"],
815
- 'networks' => ['regolith'],
816
- 'depends_on' => { 'db' => { 'condition' => 'service_healthy' } },
817
- 'environment' => {
818
- 'DATABASE_URL' => "postgres://postgres:password@db:5432/#{db_name}",
819
- 'REGOLITH_SERVICE_NAME' => name,
820
- 'REGOLITH_SERVICE_PORT' => service['port']
821
- },
822
- 'volumes' => ["#{service['root']}:/app"],
823
- 'command' => 'bash -c "rm -f tmp/pids/server.pid && bundle install && rails db:prepare && rails server -b 0.0.0.0"',
824
- 'healthcheck' => {
825
- 'test' => ['CMD-SHELL', 'curl -f http://localhost:3000/health || exit 1'],
826
- 'interval' => '30s', 'timeout' => '10s', 'retries' => 3, 'start_period' => '40s'
827
- }
828
- }
829
- end
830
-
831
-
832
- {
833
- 'version' => '3.8',
834
- 'networks' => {
835
- 'regolith' => {}
836
- },
837
- 'services' => compose_services,
838
- 'volumes' => {
839
- 'postgres_data' => nil
840
- }
841
- }.to_yaml
260
+ template = <<~YAML
261
+ version: '3.8'
262
+
263
+ services:
264
+ db:
265
+ image: postgres:14
266
+ environment:
267
+ POSTGRES_DB: #{app_name}_development
268
+ POSTGRES_USER: postgres
269
+ POSTGRES_PASSWORD: password
270
+ ports:
271
+ - "5432:5432"
272
+ volumes:
273
+ - postgres_data:/var/lib/postgresql/data
274
+
275
+ <% services.each do |name, service| %>
276
+ <%= name %>:
277
+ build: <%= service['root'] %>
278
+ ports:
279
+ - "<%= service['port'] %>:3000"
280
+ depends_on:
281
+ - db
282
+ environment:
283
+ DATABASE_URL: postgres://postgres:password@db:5432/<%= app_name %>_development
284
+ REGOLITH_SERVICE_NAME: <%= name %>
285
+ REGOLITH_SERVICE_PORT: <%= service['port'] %>
286
+ volumes:
287
+ - <%= service['root'] %>:/app
288
+ command: bash -c "rm -f tmp/pids/server.pid && bundle install && rails server -b 0.0.0.0"
289
+ <% end %>
290
+
291
+ volumes:
292
+ postgres_data:
293
+ YAML
294
+
295
+ ERB.new(template).result(binding)
842
296
  end
843
297
 
844
298
  def generate_dockerfile
845
299
  <<~DOCKERFILE
846
- FROM ruby:3.1-slim
847
-
848
- # Install system dependencies
849
- RUN apt-get update -qq && \\
850
- apt-get install -y nodejs postgresql-client libyaml-dev build-essential pkg-config curl && \\
851
- apt-get clean && \\
852
- rm -rf /var/lib/apt/lists/*
300
+ FROM ruby:3.1
853
301
 
854
302
  WORKDIR /app
855
303
 
856
- # Copy Gemfile and install gems
857
- COPY Gemfile Gemfile.lock* ./
858
-
859
- # Conditional bundler config for dev vs prod
860
- ARG BUILD_ENV=development
861
- RUN if [ "$BUILD_ENV" = "production" ]; then \\
862
- bundle config set --local deployment 'true' && \\
863
- bundle config set --local without 'development test'; \\
864
- fi && bundle install
304
+ RUN apt-get update -qq && apt-get install -y nodejs postgresql-client libyaml-dev libsqlite3-dev build-essential pkg-config
865
305
 
866
- # Copy application code
867
306
  COPY . .
868
307
 
308
+ RUN bundle install
309
+
869
310
  EXPOSE 3000
870
311
 
871
312
  CMD ["rails", "server", "-b", "0.0.0.0"]
@@ -875,17 +316,15 @@ module Regolith
875
316
  def generate_regolith_initializer(service_name)
876
317
  <<~RUBY
877
318
  require 'ostruct'
878
-
319
+
879
320
  # Regolith service configuration
880
321
  Rails.application.configure do
881
322
  config.regolith = OpenStruct.new(
882
323
  service_name: '#{service_name}',
883
- service_registry: Rails.root.join('../../config/regolith.yml'),
884
- version: Regolith::VERSION
324
+ service_registry: Rails.root.join('../../config/regolith.yml')
885
325
  )
886
326
  end
887
327
 
888
- # Load service registry if available
889
328
  if File.exist?(Rails.application.config.regolith.service_registry)
890
329
  REGOLITH_SERVICES = YAML.load_file(Rails.application.config.regolith.service_registry)['services'] || {}
891
330
  else
@@ -894,184 +333,22 @@ module Regolith
894
333
  RUBY
895
334
  end
896
335
 
897
- def generate_cors_initializer
898
- <<~RUBY
899
- # CORS configuration for microservices
900
- Rails.application.config.middleware.insert_before 0, Rack::Cors do
901
- allow do
902
- origins '*' # Configure appropriately for production
903
- resource '*',
904
- headers: :any,
905
- methods: %i[get post put patch delete options head],
906
- expose: %w[Authorization Content-Type],
907
- max_age: 600
908
- end
909
- end
910
- RUBY
911
- end
912
-
913
- def generate_health_controller
914
- <<~RUBY
915
- module Regolith
916
- class HealthController < ActionController::API
917
- def show
918
- render json: {
919
- ok: true,
920
- service: Rails.application.config.regolith_service_name,
921
- time: Time.now.to_i,
922
- version: Rails.application.config.regolith.version
923
- }
924
- end
925
- end
926
- end
927
- RUBY
928
- end
929
-
930
- def generate_gitignore
931
- <<~GITIGNORE
932
- # Regolith
933
- /services/*/log/*
934
- /services/*/tmp/*
935
- /services/*/.env*
936
- .DS_Store
937
-
938
- # Docker
939
- docker-compose.override.yml
940
-
941
- # Logs
942
- *.log
943
-
944
- # Runtime data
945
- pids
946
- *.pid
947
- *.seed
948
-
949
- # Environment variables
950
- .env*
951
- !.env.example
952
- GITIGNORE
953
- end
954
-
955
- def generate_readme(app_name)
956
- <<~MARKDOWN
957
- # #{app_name.capitalize}
958
-
959
- A Regolith microservices application built with Rails and Docker.
960
-
961
- ## Getting Started
962
-
963
- ```bash
964
- # Start all services
965
- regolith server
966
-
967
- # Generate a new service
968
- regolith generate service users
969
-
970
- # Open service in browser
971
- regolith open users
972
-
973
- # View service logs
974
- regolith logs users -f
975
-
976
- # Run database migrations
977
- regolith db:migrate --all
978
-
979
- # Health check
980
- regolith health
981
- ```
982
-
983
- ## Services
984
-
985
- #{services_documentation}
986
-
987
- ## Development
988
-
989
- ```bash
990
- # Open Rails console for a service
991
- regolith console users
992
-
993
- # Run Rails commands
994
- regolith rails users db:migrate
995
- regolith rails users routes
996
-
997
- # Run tests
998
- regolith test --all
999
-
1000
- # Execute commands in service
1001
- regolith exec users bash
1002
- ```
1003
-
1004
- ## Architecture
1005
-
1006
- - **Rails 7** API-only applications
1007
- - **PostgreSQL** for persistence
1008
- - **Docker Compose** for orchestration
1009
- - **Service registry** for inter-service communication
1010
-
1011
- Built with [Regolith](https://regolith.bio) - Rails for distributed systems.
1012
- MARKDOWN
1013
- end
1014
-
1015
- def services_documentation
1016
- config = load_regolith_config
1017
- return "No services yet. Run `regolith generate service <name>` to create one." if config['services'].empty?
1018
-
1019
- config['services'].map do |name, service|
1020
- "- **#{name}** - http://localhost:#{service['port']}"
1021
- end.join("\n")
1022
- end
1023
-
1024
336
  def generate_makefile
1025
337
  <<~MAKEFILE
1026
- .PHONY: server up down restart logs console test health doctor
338
+ .PHONY: server console build clean
1027
339
 
1028
- # Start services
1029
- server up:
1030
- \tregolith server
340
+ server:
341
+ regolith server
1031
342
 
1032
- # Stop services
1033
- down:
1034
- \tregolith down
1035
-
1036
- # Restart services
1037
- restart:
1038
- \tregolith restart
1039
-
1040
- # View logs
1041
- logs:
1042
- \tregolith logs -f
1043
-
1044
- # Open console (usage: make console SERVICE=users)
1045
343
  console:
1046
- \t@if [ -z "$(SERVICE)" ]; then echo "Usage: make console SERVICE=service_name"; exit 1; fi
1047
- \tregolith console $(SERVICE)
1048
-
1049
- # Run tests
1050
- test:
1051
- \tregolith test --all
1052
-
1053
- # Health check
1054
- health:
1055
- \tregolith health
344
+ regolith console
1056
345
 
1057
- # System diagnostics
1058
- doctor:
1059
- \tregolith doctor
346
+ build:
347
+ docker-compose build
1060
348
 
1061
- # Database operations
1062
- db-migrate:
1063
- \tregolith db:migrate --all
1064
-
1065
- db-setup:
1066
- \tregolith db:setup --all
1067
-
1068
- # Cleanup
1069
349
  clean:
1070
- \tregolith prune
1071
-
1072
- # Shortcuts
1073
- dev: up
1074
- stop: down
350
+ docker-compose down -v
351
+ docker system prune -f
1075
352
  MAKEFILE
1076
353
  end
1077
354
 
@@ -1084,62 +361,24 @@ module Regolith
1084
361
 
1085
362
  def show_help
1086
363
  puts <<~HELP
1087
- Regolith #{Regolith::VERSION} - Rails for Distributed Systems
364
+ Regolith #{Regolith::VERSION} - Microservices framework
1088
365
 
1089
366
  USAGE:
1090
367
  regolith <command> [options]
1091
368
 
1092
- PROJECT COMMANDS:
369
+ COMMANDS:
1093
370
  new <app_name> Create a new Regolith application
1094
371
  generate service <name> Generate a new microservice
1095
-
1096
- SERVICE MANAGEMENT:
1097
- server, up Start all services with Docker Compose
1098
- down Stop and remove all services
1099
- restart [service] Restart one or all services
1100
- stop [service] Stop one or all services
1101
- ps, status Show running containers
1102
- logs [service] [-f] View service logs
1103
- exec <service> [cmd] Execute command in service container
1104
- shell <service> Open shell in service container
1105
- rebuild [service] Rebuild service images
1106
-
1107
- RAILS INTEGRATION:
1108
- console <service> Open Rails console for service
1109
- rails <service> <cmd> Run Rails command in service
1110
- routes <service> Show routes for service
1111
- open <service> Open service in browser
1112
-
1113
- DATABASE OPERATIONS:
1114
- db:migrate [service|--all] Run migrations
1115
- db:create [service|--all] Create databases
1116
- db:seed [service|--all] Seed databases
1117
- db:reset [service|--all] Reset databases
1118
- db:setup [service|--all] Setup databases
1119
- db:drop [service|--all] Drop databases
1120
-
1121
- TESTING & HEALTH:
1122
- test [service|--all] Run tests
1123
- health Health check all services
1124
-
1125
- UTILITIES:
1126
- config [--json] Show current configuration
1127
- inspect [--json] Show services and resolved endpoints
1128
- prune Clean up Docker system
1129
- doctor Run system diagnostics
1130
- version Show version
372
+ server Start all services with Docker Compose
373
+ console <service_name> Open Rails console for a service
374
+ version Show version information
1131
375
 
1132
376
  EXAMPLES:
1133
- regolith new marketplace
1134
- regolith generate service products
377
+ regolith new observatory
378
+ regolith generate service telescope
379
+ regolith generate service records
1135
380
  regolith server
1136
- regolith rails products db:migrate
1137
- regolith routes products
1138
- regolith open products
1139
- regolith shell products
1140
- regolith inspect --json
1141
- regolith config --json | jq '.services'
1142
- regolith test --all
381
+ regolith console telescope
1143
382
 
1144
383
  Get started:
1145
384
  regolith new myapp
@@ -1149,4 +388,4 @@ module Regolith
1149
388
  HELP
1150
389
  end
1151
390
  end
1152
- end
391
+ end
@@ -1,4 +1,4 @@
1
1
  # lib/regolith/version.rb
2
2
  module Regolith
3
- VERSION = "0.1.19"
3
+ VERSION = "0.1.20"
4
4
  end
data/regolith.gemspec CHANGED
@@ -5,18 +5,18 @@ Gem::Specification.new do |spec|
5
5
  spec.name = "regolith"
6
6
  spec.version = Regolith::VERSION
7
7
  spec.authors = ["Regolith Team"]
8
- spec.email = ["info@regolith.bio"]
8
+ spec.email = ["team@regolith.dev"]
9
9
 
10
- spec.summary = "Rails microservices. Zero setup. Docker + PostgreSQL"
11
- spec.description = "Generate and orchestrate Rails microservices with zero setup using Docker + PostgreSQL."
12
- spec.homepage = "https://regolith.bio"
10
+ spec.summary = "Rails for distributed systems"
11
+ spec.description = "Regolith provides seamless inter-service communication and orchestration for Ruby microservices"
12
+ spec.homepage = "https://github.com/regolith/regolith"
13
13
  spec.license = "MIT"
14
14
 
15
15
  spec.required_ruby_version = ">= 2.7.0"
16
16
 
17
- spec.metadata["homepage_uri"] = "https://regolith.bio"
18
- spec.metadata["source_code_uri"] = "https://github.com/ziolndr/regolith"
19
- spec.metadata["changelog_uri"] = "https://github.com/ziolndr/regolith/blob/main/CHANGELOG.md"
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/regolith/regolith"
19
+ spec.metadata["changelog_uri"] = "https://github.com/regolith/regolith/CHANGELOG.md"
20
20
 
21
21
  # Specify which files should be added to the gem when it is released.
22
22
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
@@ -34,4 +34,4 @@ Gem::Specification.new do |spec|
34
34
  # Development dependencies
35
35
  spec.add_development_dependency "rspec", "~> 3.0"
36
36
  spec.add_development_dependency "rake", "~> 13.0"
37
- end
37
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: regolith
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.19
4
+ version: 0.1.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Regolith Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-09 00:00:00.000000000 Z
11
+ date: 2025-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -66,10 +66,10 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '13.0'
69
- description: Generate and orchestrate Rails microservices with zero setup using Docker
70
- + PostgreSQL.
69
+ description: Regolith provides seamless inter-service communication and orchestration
70
+ for Ruby microservices
71
71
  email:
72
- - info@regolith.bio
72
+ - team@regolith.dev
73
73
  executables:
74
74
  - regolith
75
75
  extensions: []
@@ -86,13 +86,13 @@ files:
86
86
  - lib/regolith/service_client.rb
87
87
  - lib/regolith/version.rb
88
88
  - regolith.gemspec
89
- homepage: https://regolith.bio
89
+ homepage: https://github.com/regolith/regolith
90
90
  licenses:
91
91
  - MIT
92
92
  metadata:
93
- homepage_uri: https://regolith.bio
94
- source_code_uri: https://github.com/ziolndr/regolith
95
- changelog_uri: https://github.com/ziolndr/regolith/blob/main/CHANGELOG.md
93
+ homepage_uri: https://github.com/regolith/regolith
94
+ source_code_uri: https://github.com/regolith/regolith
95
+ changelog_uri: https://github.com/regolith/regolith/CHANGELOG.md
96
96
  post_install_message:
97
97
  rdoc_options: []
98
98
  require_paths:
@@ -111,5 +111,5 @@ requirements: []
111
111
  rubygems_version: 3.3.15
112
112
  signing_key:
113
113
  specification_version: 4
114
- summary: Rails microservices. Zero setup. Docker + PostgreSQL
114
+ summary: Rails for distributed systems
115
115
  test_files: []