Class: InlineForms::SchemaApply

Inherits:
Object
  • Object
show all
Defined in:
lib/inline_forms/schema_apply.rb

Overview

Skeleton of the "apply" step of the staging pipeline: turn an approved SchemaIntent into the ordered shell commands a developer would run by hand (generate the migration + model edit, migrate, test, commit, restart). This is the rare, expensive, deliberate step — see the staging doc.

The engine does NOT execute these itself by default: which host runs them (a rake task on a single-server box, or a CI job after a PR on a clustered deploy) is an app decision. #commands returns the plan for inspection; #run! executes it via an injectable runner (defaults to Kernel#system) and stops at the first failure, so an app/rake task can opt in.

Constant Summary collapse

STEPS =
%i[generate migrate].freeze
DEFAULT_GENERATE_EXECUTOR =

In-process generate-only executor used by the schema GUI: runs the addto generator against the app's tree (edits the model, writes the migration file) but never migrates. Overridable so tests can record the args instead of mutating the working tree.

lambda do |args, destination_root|
  require "generators/inline_forms_addto_generator"
  InlineFormsAddtoGenerator.start(args, destination_root: destination_root)
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(intent, runner: nil) ⇒ SchemaApply

Returns a new instance of SchemaApply.



30
31
32
33
# File 'lib/inline_forms/schema_apply.rb', line 30

def initialize(intent, runner: nil)
  @intent = intent
  @runner = runner || ->(cmd) { system(*cmd) }
end

Instance Attribute Details

#intentObject (readonly)

Returns the value of attribute intent.



28
29
30
# File 'lib/inline_forms/schema_apply.rb', line 28

def intent
  @intent
end

Instance Method Details

#commandsObject

Ordered plan (each value is an argv array).



59
60
61
# File 'lib/inline_forms/schema_apply.rb', line 59

def commands
  { generate: generator_command, migrate: migrate_command }
end

#generate!(destination_root:, executor: DEFAULT_GENERATE_EXECUTOR) ⇒ Object

Run the addto generator in-process (model edit + migration file) WITHOUT running db:migrate. Returns the path of the migration it created (or nil when the executor did not create one, e.g. a recording test executor). The caller (GUI) then tells the user to run rails db:migrate + restart; the pending-migration gate covers the interim.



40
41
42
43
44
45
46
47
# File 'lib/inline_forms/schema_apply.rb', line 40

def generate!(destination_root:, executor: DEFAULT_GENERATE_EXECUTOR)
  before = addto_migrations(destination_root)
  executor.call(intent.generator_args, destination_root)
  # Only report a migration this run actually created. nil is correct and
  # expected for a :header (no column -> no migration) and must NOT fall
  # back to a pre-existing migration file.
  (addto_migrations(destination_root) - before).max
end

#generator_commandObject

rails g inline_forms_addto <Model> <attr:fe> [--after=..].



50
51
52
# File 'lib/inline_forms/schema_apply.rb', line 50

def generator_command
  %w[bundle exec rails g inline_forms_addto] + intent.generator_args
end

#migrate_commandObject



54
55
56
# File 'lib/inline_forms/schema_apply.rb', line 54

def migrate_command
  %w[bundle exec rails db:migrate]
end

#preview_planObject

Human-readable plan (what an app would show before the user confirms).



64
65
66
# File 'lib/inline_forms/schema_apply.rb', line 64

def preview_plan
  STEPS.map { |step| "#{step}: #{Shellwords.join(commands.fetch(step))}" }
end

#run!Object

Execute generate -> migrate, stopping at the first failure. Returns the step that failed, or nil on success. NOT run in tests (would shell out); an app/rake task calls this after approval + a git-clean check.



71
72
73
74
75
76
77
# File 'lib/inline_forms/schema_apply.rb', line 71

def run!
  STEPS.each do |step|
    ok = @runner.call(commands.fetch(step))
    return step unless ok
  end
  nil
end