Class: Reeve::Generators::UpgradeGenerator

Inherits:
Rails::Generators::Base
  • Object
show all
Includes:
ActiveRecord::Generators::Migration
Defined in:
lib/generators/reeve/upgrade/upgrade_generator.rb

Overview

bin/rails generate reeve:upgrade — brings an existing ledger up to the audit-entry contract this version of the gem writes.

Why this exists as a second generator rather than as a re-run of reeve:install: Rails resolves a migration by name, so install on a host that already has create_reeve_audit_entries reports identical and emits nothing, or — once the template has changed, which is exactly the upgrade case — offers to overwrite a migration that has already run. Overwriting an applied migration does not touch the database and destroys the record of what was applied, so the one thing a host must never be told to do about an out-of-date ledger is run the install generator again.

What it emits is decided by the table, not by a version number the host might have recorded wrongly or not at all: each step declares the columns it adds, and a step whose columns are all present has already been applied. That makes running this on a current ledger a no-op it can report rather than a duplicate migration.

Constant Summary collapse

TABLE =
"reeve_audit_entries"
STEPS =

The ladder, oldest first. One entry per contract bump that touches the table.

adds is what makes a step detectable, so it must name every column the step creates. A step that changes a column without adding one cannot be detected this way and needs its own predicate — see the additive-only rule in contracts/audit-entry.md, which exists so that stays hypothetical: an append-only ledger cannot be backfilled, so a column that is not additive has no honest value to give the rows already written.

[
  {
    contract: 2,
    adds: %w[contract_version],
    template: "add_contract_version_to_reeve_audit_entries.rb.tt",
    destination: "add_contract_version_to_reeve_audit_entries.rb"
  }
].freeze

Instance Method Summary collapse

Instance Method Details

#create_upgrade_migrationsObject



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/generators/reeve/upgrade/upgrade_generator.rb', line 67

def create_upgrade_migrations
  return if @halted

  pending = STEPS.reject { |step| applied?(step) }
  return @nothing_to_do = true if pending.empty?

  pending.each do |step|
    migration_template(step[:template], "db/migrate/#{step[:destination]}")
  end

  @emitted = pending
end

#report_next_stepObject



80
81
82
83
84
# File 'lib/generators/reeve/upgrade/upgrade_generator.rb', line 80

def report_next_step
  return if @halted

  say(@nothing_to_do ? up_to_date_message : pending_message)
end

#verify_ledger_existsObject



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/generators/reeve/upgrade/upgrade_generator.rb', line 49

def verify_ledger_exists
  return if table_exists?

  say <<~MISSING

    There is no #{TABLE} table to upgrade.

    This generator is for a ledger that already exists. For a new one:

      bin/rails generate reeve:install
      bin/rails db:migrate
  MISSING

  # Not an exception: "you wanted the other generator" is a normal thing to get
  # wrong, and a backtrace would suggest reeve broke.
  @halted = true
end