Class: InlineForms::SchemaBatch

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/inline_forms/schema_batch.rb

Overview

A batch of proposed schema changes (SchemaIntentRecord rows), the unit the automated pipeline processes. Lifecycle:

draft      — admin is still adding/removing intents (the "cart")
submitted  — frozen; waiting for CI to pick it up
processing — CI is generating code / running the test gate
ready      — code committed (git_sha set); waiting for the deploy window
applied    — migrated + restarted
failed     — any step failed; error holds the diagnostics

IMMUTABILITY: the moment a batch leaves draft, its intents are frozen (enforced in SchemaIntentRecord) and the batch itself only accepts status-flow updates (status, git_sha, error, applied_at). content_digest seals the intent list at submit time; export re-emits it and the import side re-verifies it, so a batch provably cannot change between "admin pressed submit" and "CI replayed it".

Constant Summary collapse

STATUSES =
%w[draft submitted processing ready applied failed].freeze
TRANSITIONS =
{
  "draft"      => %w[submitted],
  "submitted"  => %w[processing failed],
  "processing" => %w[ready failed],
  "ready"      => %w[applied failed],
  "failed"     => %w[submitted],   # resubmit after a fix
  "applied"    => []
}.freeze
STATUS_FLOW_COLUMNS =

Columns the pipeline may still write after the batch left draft.

%w[status git_sha error applied_at updated_at].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.current_draftObject



50
51
52
# File 'app/models/inline_forms/schema_batch.rb', line 50

def self.current_draft
  with_status(:draft).order(:id).first_or_create!
end

Instance Method Details

#applied?Boolean

Returns:

  • (Boolean)


58
# File 'app/models/inline_forms/schema_batch.rb', line 58

def applied? = status == "applied"

#draft?Boolean

Returns:

  • (Boolean)


54
# File 'app/models/inline_forms/schema_batch.rb', line 54

def draft? = status == "draft"

#due_for_apply?Boolean

ready + the requested window (if any) has arrived.

Returns:

  • (Boolean)


62
63
64
# File 'app/models/inline_forms/schema_batch.rb', line 62

def due_for_apply?
  ready? && (window_at.nil? || window_at <= Time.current)
end

#failed?Boolean

Returns:

  • (Boolean)


59
# File 'app/models/inline_forms/schema_batch.rb', line 59

def failed? = status == "failed"

#processing?Boolean

Returns:

  • (Boolean)


56
# File 'app/models/inline_forms/schema_batch.rb', line 56

def processing? = status == "processing"

#ready?Boolean

Returns:

  • (Boolean)


57
# File 'app/models/inline_forms/schema_batch.rb', line 57

def ready? = status == "ready"

#submit!(requested_by: nil, window_at: nil) ⇒ Object

Freeze the batch: seal the digest, record who/when, optionally a window.

Raises:

  • (ArgumentError)


67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'app/models/inline_forms/schema_batch.rb', line 67

def submit!(requested_by: nil, window_at: nil)
  raise ArgumentError, "only a draft batch can be submitted" unless draft?
  raise ArgumentError, "cannot submit an empty batch" if intents.reload.empty?

  with_lock do
    self.status         = "submitted"
    self.   = Time.current
    self.window_at      = window_at
    self.requested_by   = requested_by if requested_by
    self.content_digest = InlineFormsSchemaEdit::BatchExport.digest_for(self)
    save!
  end
  self
end

#submitted?Boolean

Returns:

  • (Boolean)


55
# File 'app/models/inline_forms/schema_batch.rb', line 55

def  = status == "submitted"

#transition!(to, git_sha: nil, error: nil) ⇒ Object

Status-flow update used by the pipeline (CI callback / apply task).



83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'app/models/inline_forms/schema_batch.rb', line 83

def transition!(to, git_sha: nil, error: nil)
  to = to.to_s
  unless TRANSITIONS.fetch(status, []).include?(to)
    raise ArgumentError, "illegal transition #{status} -> #{to}"
  end

  self.status  = to
  self.git_sha = git_sha if git_sha
  self.error   = error if error
  self.applied_at = Time.current if to == "applied"
  save!
  self
end