Class: Carson::Ledger
- Inherits:
-
Object
- Object
- Carson::Ledger
- Defined in:
- lib/carson/ledger.rb
Constant Summary collapse
- UNSET =
Object.new
- ACTIVE_DELIVERY_STATES =
Delivery::ACTIVE_STATES
Instance Attribute Summary collapse
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Instance Method Summary collapse
-
#active_deliveries(repo_path:) ⇒ Object
Lists active deliveries for a repository in creation order.
-
#active_delivery(repo_path:, branch_name:) ⇒ Object
Looks up the active delivery for a branch, if one exists.
-
#initialize(path:) ⇒ Ledger
constructor
A new instance of Ledger.
-
#prepare! ⇒ Object
Ensures the SQLite schema exists before Carson uses the ledger.
-
#queued_deliveries(repo_path:) ⇒ Object
Lists queued deliveries ready for integration.
-
#record_revision(delivery:, cause:, provider:, status:, summary:) ⇒ Object
Records one revision cycle against a delivery and bumps the delivery counter.
-
#revisions_for_delivery(delivery_id:) ⇒ Object
Lists revisions for a delivery in ascending order.
-
#update_delivery(delivery:, status: UNSET, pr_number: UNSET, pr_url: UNSET, cause: UNSET, summary: UNSET, worktree_path: UNSET, revision_count: UNSET, integrated_at: UNSET, superseded_at: UNSET) ⇒ Object
Updates a delivery record in place.
-
#upsert_delivery(repository:, branch_name:, head:, worktree_path:, authority:, pr_number:, pr_url:, status:, summary:, cause:) ⇒ Object
Creates or refreshes a delivery for the same branch head.
Constructor Details
#initialize(path:) ⇒ Ledger
Returns a new instance of Ledger.
11 12 13 14 |
# File 'lib/carson/ledger.rb', line 11 def initialize( path: ) @path = File.( path ) prepare! end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
16 17 18 |
# File 'lib/carson/ledger.rb', line 16 def path @path end |
Instance Method Details
#active_deliveries(repo_path:) ⇒ Object
Lists active deliveries for a repository in creation order.
125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/carson/ledger.rb', line 125 def active_deliveries( repo_path: ) with_database do |database| rows = database.execute( <<~SQL, SELECT * FROM deliveries WHERE repo_path = ? AND status IN ( #{active_state_placeholders} ) ORDER BY created_at ASC, id ASC SQL [ repo_path, *ACTIVE_DELIVERY_STATES ] ) rows.map { |row| build_delivery( row: row ) } end end |
#active_delivery(repo_path:, branch_name:) ⇒ Object
Looks up the active delivery for a branch, if one exists.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/carson/ledger.rb', line 109 def active_delivery( repo_path:, branch_name: ) with_database do |database| row = database.get_first_row( <<~SQL, SELECT * FROM deliveries WHERE repo_path = ? AND branch_name = ? AND status IN ( #{active_state_placeholders} ) ORDER BY updated_at DESC LIMIT 1 SQL [ repo_path, branch_name, *ACTIVE_DELIVERY_STATES ] ) build_delivery( row: row ) if row end end |
#prepare! ⇒ Object
Ensures the SQLite schema exists before Carson uses the ledger.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/carson/ledger.rb', line 19 def prepare! FileUtils.mkdir_p( File.dirname( path ) ) with_database do |database| database.execute_batch( <<~SQL ) CREATE TABLE IF NOT EXISTS deliveries ( id INTEGER PRIMARY KEY AUTOINCREMENT, repo_path TEXT NOT NULL, branch_name TEXT NOT NULL, head TEXT NOT NULL, worktree_path TEXT, authority TEXT NOT NULL, status TEXT NOT NULL, pr_number INTEGER, pr_url TEXT, revision_count INTEGER NOT NULL DEFAULT 0, cause TEXT, summary TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, integrated_at TEXT, superseded_at TEXT ); CREATE UNIQUE INDEX IF NOT EXISTS index_deliveries_on_identity ON deliveries ( repo_path, branch_name, head ); CREATE INDEX IF NOT EXISTS index_deliveries_on_state ON deliveries ( repo_path, status, created_at ); CREATE TABLE IF NOT EXISTS revisions ( id INTEGER PRIMARY KEY AUTOINCREMENT, delivery_id INTEGER NOT NULL, number INTEGER NOT NULL, cause TEXT NOT NULL, provider TEXT NOT NULL, status TEXT NOT NULL, started_at TEXT NOT NULL, finished_at TEXT, summary TEXT, FOREIGN KEY ( delivery_id ) REFERENCES deliveries ( id ) ); CREATE UNIQUE INDEX IF NOT EXISTS index_revisions_on_delivery_number ON revisions ( delivery_id, number ); SQL end end |
#queued_deliveries(repo_path:) ⇒ Object
Lists queued deliveries ready for integration.
140 141 142 143 144 145 146 147 |
# File 'lib/carson/ledger.rb', line 140 def queued_deliveries( repo_path: ) with_database do |database| database.execute( "SELECT * FROM deliveries WHERE repo_path = ? AND status = ? ORDER BY created_at ASC, id ASC", [ repo_path, "queued" ] ).map { |row| build_delivery( row: row ) } end end |
#record_revision(delivery:, cause:, provider:, status:, summary:) ⇒ Object
Records one revision cycle against a delivery and bumps the delivery counter.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/carson/ledger.rb', line 185 def record_revision( delivery:, cause:, provider:, status:, summary: ) = now_utc with_database do |database| next_number = database.get_first_value( "SELECT COALESCE( MAX(number), 0 ) + 1 FROM revisions WHERE delivery_id = ?", [ delivery.id ] ).to_i database.execute( <<~SQL, INSERT INTO revisions ( delivery_id, number, cause, provider, status, started_at, finished_at, summary ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? ) SQL [ delivery.id, next_number, cause, provider, status, , ( status == "completed" || status == "failed" || status == "stalled" ) ? : nil, summary ] ) database.execute( "UPDATE deliveries SET revision_count = ?, updated_at = ? WHERE id = ?", [ next_number, , delivery.id ] ) build_revision( row: database.get_first_row( "SELECT * FROM revisions WHERE id = ?", [ database.last_insert_row_id ] ) ) end end |
#revisions_for_delivery(delivery_id:) ⇒ Object
Lists revisions for a delivery in ascending order.
215 216 217 218 219 220 221 222 |
# File 'lib/carson/ledger.rb', line 215 def revisions_for_delivery( delivery_id: ) with_database do |database| database.execute( "SELECT * FROM revisions WHERE delivery_id = ? ORDER BY number ASC, id ASC", [ delivery_id ] ).map { |row| build_revision( row: row ) } end end |
#update_delivery(delivery:, status: UNSET, pr_number: UNSET, pr_url: UNSET, cause: UNSET, summary: UNSET, worktree_path: UNSET, revision_count: UNSET, integrated_at: UNSET, superseded_at: UNSET) ⇒ Object
Updates a delivery record in place.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/carson/ledger.rb', line 150 def update_delivery( delivery:, status: UNSET, pr_number: UNSET, pr_url: UNSET, cause: UNSET, summary: UNSET, worktree_path: UNSET, revision_count: UNSET, integrated_at: UNSET, superseded_at: UNSET ) updates = {} updates[ "status" ] = status unless status.equal?( UNSET ) updates[ "pr_number" ] = pr_number unless pr_number.equal?( UNSET ) updates[ "pr_url" ] = pr_url unless pr_url.equal?( UNSET ) updates[ "cause" ] = cause unless cause.equal?( UNSET ) updates[ "summary" ] = summary unless summary.equal?( UNSET ) updates[ "worktree_path" ] = worktree_path unless worktree_path.equal?( UNSET ) updates[ "revision_count" ] = revision_count unless revision_count.equal?( UNSET ) updates[ "integrated_at" ] = integrated_at unless integrated_at.equal?( UNSET ) updates[ "superseded_at" ] = superseded_at unless superseded_at.equal?( UNSET ) updates[ "updated_at" ] = now_utc with_database do |database| assignments = updates.keys.map { |key| "#{key} = ?" }.join( ", " ) database.execute( "UPDATE deliveries SET #{assignments} WHERE id = ?", updates.values + [ delivery.id ] ) fetch_delivery( database: database, id: delivery.id, repository: delivery.repository ) end end |
#upsert_delivery(repository:, branch_name:, head:, worktree_path:, authority:, pr_number:, pr_url:, status:, summary:, cause:) ⇒ Object
Creates or refreshes a delivery for the same branch head.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/carson/ledger.rb', line 69 def upsert_delivery( repository:, branch_name:, head:, worktree_path:, authority:, pr_number:, pr_url:, status:, summary:, cause: ) = now_utc with_database do |database| row = database.get_first_row( "SELECT * FROM deliveries WHERE repo_path = ? AND branch_name = ? AND head = ? LIMIT 1", [ repository.path, branch_name, head ] ) if row database.execute( <<~SQL, UPDATE deliveries SET worktree_path = ?, authority = ?, status = ?, pr_number = ?, pr_url = ?, cause = ?, summary = ?, updated_at = ? WHERE id = ? SQL [ worktree_path, , status, pr_number, pr_url, cause, summary, , row.fetch( "id" ) ] ) return fetch_delivery( database: database, id: row.fetch( "id" ), repository: repository ) end supersede_branch!( database: database, repository: repository, branch_name: branch_name, timestamp: ) database.execute( <<~SQL, INSERT INTO deliveries ( repo_path, branch_name, head, worktree_path, authority, status, pr_number, pr_url, revision_count, cause, summary, created_at, updated_at ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ? ) SQL [ repository.path, branch_name, head, worktree_path, , status, pr_number, pr_url, cause, summary, , ] ) fetch_delivery( database: database, id: database.last_insert_row_id, repository: repository ) end end |