regolith 0.1.18 → 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: 8494378218297f554df53058b3c1704b0bfef62faf6c6c65c783897b73a20964
4
- data.tar.gz: c2b92cf6baa28dac0f57eedd8f9c810685289365cce2860ed9feacb31d7e0c42
3
+ metadata.gz: bc4410cdbfbd1a5f314f784309bc88d2b0d6b9e3bbcda0bd6a3d49e74893ba95
4
+ data.tar.gz: 7b4b961f4c89d92943070dd8f30ee4067bf6a61d5a3e3d73f1ab18ee3face259
5
5
  SHA512:
6
- metadata.gz: 0111fcbebc4f066bca55fd305001eb8ad58c568ec8cc0bda45b2f56ec19d3f9c537b822f83973d7d2c8b15cb408fc331e93cbe7f0da18af5208113b615f5e038
7
- data.tar.gz: 2c5e1bf7c54fa24ae1ab7aa57f60e59fea2c36c47d384484f57f5e428d565dc902b80bbd8e737a6f6bf64c9f58b963b24b4cb8a4be16578eaafe0f6761f8a692
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
232
  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"
233
+ unless config['services'][service_name]
234
+ puts "❌ Error: Service '#{service_name}' not found"
521
235
  exit 1
522
236
  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
237
 
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
- 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"
718
- exit 1
719
- end
720
- end
721
-
722
- def exec_compose(*args)
723
- cmd = docker_compose_command + args
724
- exec(*cmd)
725
- end
726
-
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,97 +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
- compose_services[name] = {
808
- 'build' => {
809
- 'context' => service['root'],
810
- 'args' => {
811
- 'BUILD_ENV' => 'development'
812
- }
813
- },
814
- 'ports' => ["#{service['port']}:3000"],
815
- 'networks' => ['regolith'],
816
- 'depends_on' => {
817
- 'db' => {
818
- 'condition' => 'service_healthy'
819
- }
820
- },
821
- 'environment' => {
822
- 'DATABASE_URL' => "postgres://postgres:password@db:5432/#{app_name}_development",
823
- 'REGOLITH_SERVICE_NAME' => name,
824
- 'REGOLITH_SERVICE_PORT' => service['port']
825
- },
826
- 'volumes' => ["#{service['root']}:/app"],
827
- 'command' => 'bash -c "rm -f tmp/pids/server.pid && bundle install && rails db:prepare && rails server -b 0.0.0.0"',
828
- 'healthcheck' => {
829
- 'test' => ['CMD-SHELL', 'curl -f http://localhost:3000/health || exit 1'],
830
- 'interval' => '30s',
831
- 'timeout' => '10s',
832
- 'retries' => 3,
833
- 'start_period' => '40s'
834
- }
835
- }
836
- end
837
-
838
- {
839
- 'version' => '3.8',
840
- 'networks' => {
841
- 'regolith' => {}
842
- },
843
- 'services' => compose_services,
844
- 'volumes' => {
845
- 'postgres_data' => nil
846
- }
847
- }.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)
848
296
  end
849
297
 
850
298
  def generate_dockerfile
851
299
  <<~DOCKERFILE
852
- FROM ruby:3.1-slim
853
-
854
- # Install system dependencies
855
- RUN apt-get update -qq && \\
856
- apt-get install -y nodejs postgresql-client libyaml-dev build-essential pkg-config curl && \\
857
- apt-get clean && \\
858
- rm -rf /var/lib/apt/lists/*
300
+ FROM ruby:3.1
859
301
 
860
302
  WORKDIR /app
861
303
 
862
- # Copy Gemfile and install gems
863
- COPY Gemfile Gemfile.lock* ./
864
-
865
- # Conditional bundler config for dev vs prod
866
- ARG BUILD_ENV=development
867
- RUN if [ "$BUILD_ENV" = "production" ]; then \\
868
- bundle config set --local deployment 'true' && \\
869
- bundle config set --local without 'development test'; \\
870
- fi && bundle install
304
+ RUN apt-get update -qq && apt-get install -y nodejs postgresql-client libyaml-dev libsqlite3-dev build-essential pkg-config
871
305
 
872
- # Copy application code
873
306
  COPY . .
874
307
 
308
+ RUN bundle install
309
+
875
310
  EXPOSE 3000
876
311
 
877
312
  CMD ["rails", "server", "-b", "0.0.0.0"]
@@ -881,17 +316,15 @@ module Regolith
881
316
  def generate_regolith_initializer(service_name)
882
317
  <<~RUBY
883
318
  require 'ostruct'
884
-
319
+
885
320
  # Regolith service configuration
886
321
  Rails.application.configure do
887
322
  config.regolith = OpenStruct.new(
888
323
  service_name: '#{service_name}',
889
- service_registry: Rails.root.join('../../config/regolith.yml'),
890
- version: Regolith::VERSION
324
+ service_registry: Rails.root.join('../../config/regolith.yml')
891
325
  )
892
326
  end
893
327
 
894
- # Load service registry if available
895
328
  if File.exist?(Rails.application.config.regolith.service_registry)
896
329
  REGOLITH_SERVICES = YAML.load_file(Rails.application.config.regolith.service_registry)['services'] || {}
897
330
  else
@@ -900,184 +333,22 @@ module Regolith
900
333
  RUBY
901
334
  end
902
335
 
903
- def generate_cors_initializer
904
- <<~RUBY
905
- # CORS configuration for microservices
906
- Rails.application.config.middleware.insert_before 0, Rack::Cors do
907
- allow do
908
- origins '*' # Configure appropriately for production
909
- resource '*',
910
- headers: :any,
911
- methods: %i[get post put patch delete options head],
912
- expose: %w[Authorization Content-Type],
913
- max_age: 600
914
- end
915
- end
916
- RUBY
917
- end
918
-
919
- def generate_health_controller
920
- <<~RUBY
921
- module Regolith
922
- class HealthController < ActionController::API
923
- def show
924
- render json: {
925
- ok: true,
926
- service: Rails.application.config.regolith_service_name,
927
- time: Time.now.to_i,
928
- version: Rails.application.config.regolith.version
929
- }
930
- end
931
- end
932
- end
933
- RUBY
934
- end
935
-
936
- def generate_gitignore
937
- <<~GITIGNORE
938
- # Regolith
939
- /services/*/log/*
940
- /services/*/tmp/*
941
- /services/*/.env*
942
- .DS_Store
943
-
944
- # Docker
945
- docker-compose.override.yml
946
-
947
- # Logs
948
- *.log
949
-
950
- # Runtime data
951
- pids
952
- *.pid
953
- *.seed
954
-
955
- # Environment variables
956
- .env*
957
- !.env.example
958
- GITIGNORE
959
- end
960
-
961
- def generate_readme(app_name)
962
- <<~MARKDOWN
963
- # #{app_name.capitalize}
964
-
965
- A Regolith microservices application built with Rails and Docker.
966
-
967
- ## Getting Started
968
-
969
- ```bash
970
- # Start all services
971
- regolith server
972
-
973
- # Generate a new service
974
- regolith generate service users
975
-
976
- # Open service in browser
977
- regolith open users
978
-
979
- # View service logs
980
- regolith logs users -f
981
-
982
- # Run database migrations
983
- regolith db:migrate --all
984
-
985
- # Health check
986
- regolith health
987
- ```
988
-
989
- ## Services
990
-
991
- #{services_documentation}
992
-
993
- ## Development
994
-
995
- ```bash
996
- # Open Rails console for a service
997
- regolith console users
998
-
999
- # Run Rails commands
1000
- regolith rails users db:migrate
1001
- regolith rails users routes
1002
-
1003
- # Run tests
1004
- regolith test --all
1005
-
1006
- # Execute commands in service
1007
- regolith exec users bash
1008
- ```
1009
-
1010
- ## Architecture
1011
-
1012
- - **Rails 7** API-only applications
1013
- - **PostgreSQL** for persistence
1014
- - **Docker Compose** for orchestration
1015
- - **Service registry** for inter-service communication
1016
-
1017
- Built with [Regolith](https://regolith.bio) - Rails for distributed systems.
1018
- MARKDOWN
1019
- end
1020
-
1021
- def services_documentation
1022
- config = load_regolith_config
1023
- return "No services yet. Run `regolith generate service <name>` to create one." if config['services'].empty?
1024
-
1025
- config['services'].map do |name, service|
1026
- "- **#{name}** - http://localhost:#{service['port']}"
1027
- end.join("\n")
1028
- end
1029
-
1030
336
  def generate_makefile
1031
337
  <<~MAKEFILE
1032
- .PHONY: server up down restart logs console test health doctor
338
+ .PHONY: server console build clean
1033
339
 
1034
- # Start services
1035
- server up:
1036
- \tregolith server
340
+ server:
341
+ regolith server
1037
342
 
1038
- # Stop services
1039
- down:
1040
- \tregolith down
1041
-
1042
- # Restart services
1043
- restart:
1044
- \tregolith restart
1045
-
1046
- # View logs
1047
- logs:
1048
- \tregolith logs -f
1049
-
1050
- # Open console (usage: make console SERVICE=users)
1051
343
  console:
1052
- \t@if [ -z "$(SERVICE)" ]; then echo "Usage: make console SERVICE=service_name"; exit 1; fi
1053
- \tregolith console $(SERVICE)
1054
-
1055
- # Run tests
1056
- test:
1057
- \tregolith test --all
1058
-
1059
- # Health check
1060
- health:
1061
- \tregolith health
344
+ regolith console
1062
345
 
1063
- # System diagnostics
1064
- doctor:
1065
- \tregolith doctor
346
+ build:
347
+ docker-compose build
1066
348
 
1067
- # Database operations
1068
- db-migrate:
1069
- \tregolith db:migrate --all
1070
-
1071
- db-setup:
1072
- \tregolith db:setup --all
1073
-
1074
- # Cleanup
1075
349
  clean:
1076
- \tregolith prune
1077
-
1078
- # Shortcuts
1079
- dev: up
1080
- stop: down
350
+ docker-compose down -v
351
+ docker system prune -f
1081
352
  MAKEFILE
1082
353
  end
1083
354
 
@@ -1090,62 +361,24 @@ module Regolith
1090
361
 
1091
362
  def show_help
1092
363
  puts <<~HELP
1093
- Regolith #{Regolith::VERSION} - Rails for Distributed Systems
364
+ Regolith #{Regolith::VERSION} - Microservices framework
1094
365
 
1095
366
  USAGE:
1096
367
  regolith <command> [options]
1097
368
 
1098
- PROJECT COMMANDS:
369
+ COMMANDS:
1099
370
  new <app_name> Create a new Regolith application
1100
371
  generate service <name> Generate a new microservice
1101
-
1102
- SERVICE MANAGEMENT:
1103
- server, up Start all services with Docker Compose
1104
- down Stop and remove all services
1105
- restart [service] Restart one or all services
1106
- stop [service] Stop one or all services
1107
- ps, status Show running containers
1108
- logs [service] [-f] View service logs
1109
- exec <service> [cmd] Execute command in service container
1110
- shell <service> Open shell in service container
1111
- rebuild [service] Rebuild service images
1112
-
1113
- RAILS INTEGRATION:
1114
- console <service> Open Rails console for service
1115
- rails <service> <cmd> Run Rails command in service
1116
- routes <service> Show routes for service
1117
- open <service> Open service in browser
1118
-
1119
- DATABASE OPERATIONS:
1120
- db:migrate [service|--all] Run migrations
1121
- db:create [service|--all] Create databases
1122
- db:seed [service|--all] Seed databases
1123
- db:reset [service|--all] Reset databases
1124
- db:setup [service|--all] Setup databases
1125
- db:drop [service|--all] Drop databases
1126
-
1127
- TESTING & HEALTH:
1128
- test [service|--all] Run tests
1129
- health Health check all services
1130
-
1131
- UTILITIES:
1132
- config [--json] Show current configuration
1133
- inspect [--json] Show services and resolved endpoints
1134
- prune Clean up Docker system
1135
- doctor Run system diagnostics
1136
- 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
1137
375
 
1138
376
  EXAMPLES:
1139
- regolith new marketplace
1140
- regolith generate service products
377
+ regolith new observatory
378
+ regolith generate service telescope
379
+ regolith generate service records
1141
380
  regolith server
1142
- regolith rails products db:migrate
1143
- regolith routes products
1144
- regolith open products
1145
- regolith shell products
1146
- regolith inspect --json
1147
- regolith config --json | jq '.services'
1148
- regolith test --all
381
+ regolith console telescope
1149
382
 
1150
383
  Get started:
1151
384
  regolith new myapp
@@ -1155,4 +388,4 @@ module Regolith
1155
388
  HELP
1156
389
  end
1157
390
  end
1158
- end
391
+ end
@@ -1,4 +1,4 @@
1
1
  # lib/regolith/version.rb
2
2
  module Regolith
3
- VERSION = "0.1.18"
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.18
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: []