Class: Maquina::Generators::SolidErrorsGenerator

Inherits:
Rails::Generators::Base
  • Object
show all
Defined in:
lib/generators/maquina/solid_errors/solid_errors_generator.rb

Instance Method Summary collapse

Instance Method Details

#add_gemObject

  1. Add gem to Gemfile



77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 77

def add_gem
  gemfile_path = File.join(destination_root, "Gemfile")
  return unless File.exist?(gemfile_path)

  content = File.read(gemfile_path)
  unless content.include?('gem "solid_errors"')
    append_to_file "Gemfile", "\ngem \"solid_errors\"\n"
  end

  if agent? && !content.include?('gem "mcp"')
    append_to_file "Gemfile", "\ngem \"mcp\"\n"
  end
end

#add_routeObject

  1. Routes



92
93
94
95
96
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 92

def add_route
  mount_path = "#{options[:prefix]}/solid_errors"

  route "mount SolidErrors::Engine, at: \"#{mount_path}\""
end

#configure_application_jobObject

  1. Enrich job failures with job context (always — benefits the dashboard too, not just the agent). On Solid Queue >= 1.0.2 a failed job’s exception already flows to the Rails error reporter that Solid Errors subscribes to; this only attaches the job class/arguments/id to that report so a job failure is distinguishable and replayable.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 48

def configure_application_job
  job_path = "app/jobs/application_job.rb"
  full_path = File.join(destination_root, job_path)
  return unless File.exist?(full_path)
  return if File.read(full_path).include?("Rails.error.set_context")

  inject_into_class job_path, "ApplicationJob", <<~RUBY
    # Attach job context to errors reported to Rails.error so background-job
    # failures are distinguishable from request failures in Solid Errors,
    # and carry replayable arguments. Sets context only and lets Solid
    # Queue's built-in reporting forward the exception (reported once).
    #
    # If your Solid Queue version does not propagate this context to its
    # report, fall back to rescuing in the block, reporting explicitly with
    # `Rails.error.report(e, handled: false)`, and RE-RAISING (re-raising is
    # required: it preserves the failed_execution record and retries).
    around_perform do |job, block|
      Rails.error.set_context(
        active_job: job.class.name,
        arguments: job.arguments,
        job_id: job.job_id,
        queue_name: job.queue_name
      )
      block.call
    end
  RUBY
end

#copy_layoutObject

  1. Layout



107
108
109
110
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 107

def copy_layout
  copy_file "app/views/layouts/solid_errors/application.html.erb",
    "app/views/layouts/solid_errors/application.html.erb"
end

#copy_stimulus_controllersObject

  1. Stimulus controllers



113
114
115
116
117
118
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 113

def copy_stimulus_controllers
  copy_file "app/javascript/controllers/clipboard_controller.js",
    "app/javascript/controllers/clipboard_controller.js"
  copy_file "app/javascript/controllers/backtrace_filter_controller.js",
    "app/javascript/controllers/backtrace_filter_controller.js"
end

#copy_viewsObject

  1. Custom views



121
122
123
124
125
126
127
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 121

def copy_views
  return unless options[:copy_views]

  view_files.each do |view|
    copy_file view, view
  end
end

#create_admin_navigationObject

  1. Admin navigation



99
100
101
102
103
104
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 99

def create_admin_navigation
  nav_path = "app/views/layouts/_admin_navigation.html.erb"
  return if File.exist?(File.join(destination_root, nav_path))

  template "app/views/layouts/_admin_navigation.html.erb.tt", nav_path
end

#create_agent_filesObject

  1. AI-agent triage tooling (opt-in). Read-only query/triage layer over the errors store, a bin/ runner, and a stdio MCP server. Resolution stays a human action in the Backstage dashboards.



132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 132

def create_agent_files
  return unless agent?

  agent_files.each do |file|
    copy_file file, file
  end

  copy_file "bin/failures", "bin/failures"
  copy_file "bin/failures-mcp", "bin/failures-mcp"
  chmod "bin/failures", 0o755
  chmod "bin/failures-mcp", 0o755
end

#create_backstage_controllerObject

  1. BackstageController



24
25
26
27
28
29
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 24

def create_backstage_controller
  backstage_path = "app/controllers/backstage_controller.rb"
  return if File.exist?(File.join(destination_root, backstage_path))

  template "app/controllers/backstage_controller.rb.tt", backstage_path
end

#create_helperObject

  1. Helper



32
33
34
35
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 32

def create_helper
  copy_file "app/helpers/solid_errors_helper.rb",
    "app/helpers/solid_errors_helper.rb"
end

#create_initializerObject

  1. Initializer



38
39
40
41
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 38

def create_initializer
  template "config/initializers/solid_errors.rb.tt",
    "config/initializers/solid_errors.rb"
end

#create_mcp_http_controllerObject

  1. MCP-over-HTTP endpoint (opt-in, internet-exposed). Mounts the same read-only tool surface behind the existing backstage Basic Auth so a developer can query a deployed app’s failures from their machine.



148
149
150
151
152
153
154
155
156
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 148

def create_mcp_http_controller
  return unless options[:mcp_http]

  template "app/controllers/failures_mcp_controller.rb.tt",
    "app/controllers/failures_mcp_controller.rb"

  route %(match "#{options[:prefix]}/failures/mcp", ) +
    %(to: "failures_mcp#handle", via: %i[get post delete])
end

#run_bundle_installObject

  1. Bundle install



159
160
161
162
163
164
165
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 159

def run_bundle_install
  return unless rails_app?

  Bundler.with_unbundled_env do
    system("bundle install", chdir: destination_root)
  end
end

#show_post_installObject

  1. Post-install message



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/generators/maquina/solid_errors/solid_errors_generator.rb', line 168

def show_post_install
  return if options[:quiet]

  say ""
  say "Solid Errors has been installed!", :green
  say ""
  say "Next steps:", :yellow
  say "  1. bin/rails generate solid_errors:install"
  say "     (when prompted to overwrite the initializer, choose 'n' to keep your config)"
  say "  2. bin/rails db:migrate"
  say ""
  say "Configuration:", :yellow
  say "  - Set credentials: bin/rails credentials:edit"
  say "    backstage:"
  say "      username: your_user"
  say "      password: your_password"
  say "  - Or set ENV vars: #{options[:user_env_var]}, #{options[:password_env_var]}"
  say ""
  say "Job failures: app/jobs/application_job.rb now tags reported errors with", :yellow
  say "  job class, arguments, and id so background-job failures show up in the"
  say "  Solid Errors dashboard with replayable context (Solid Queue >= 1.0.2)."
  say ""

  show_agent_post_install if agent?
  show_mcp_http_post_install if options[:mcp_http]
end