Promote as a real deployment; version state and scope dropdowns
Turns promotion into a first-class deployment (action='promote') so it lands in the deployments UI with before/after content, per-server restart tracking, and one-click rollback. Non-beta matching-scope servers get restart_state= pending so the existing sweep drains and restarts them the same way drift does. Also adds a per-version state (untested/tested/test-failed) so the upload flow can visibly signal that a beta must land before promotion, and swaps the scope-value text box for game/map dropdowns populated from the fleet. Beta rollback at ready-promote is now labelled Reject and marks the version test-failed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,35 @@ function migrateServers(handle: Database.Database): void {
|
||||
}
|
||||
}
|
||||
|
||||
// Additive columns on tables the script model owns. Same pattern as
|
||||
// migrateServers — CREATE TABLE IF NOT EXISTS won't backfill columns onto
|
||||
// pre-existing tables, so we introspect and ALTER as needed.
|
||||
const SCRIPT_VERSIONS_COLUMNS: Array<{ name: string; ddl: string }> = [
|
||||
// state was added post-launch to make untested/tested/test-failed visible
|
||||
// in the UI. Existing rows default to 'untested' — this is safe because
|
||||
// any real promoted version's script has current_version_id set (which is
|
||||
// the authoritative "promoted" signal), and any version already gated
|
||||
// through a ready-promote beta will be re-marked next time that state
|
||||
// machine fires.
|
||||
{ name: 'state', ddl: "ALTER TABLE script_versions ADD COLUMN state TEXT NOT NULL DEFAULT 'untested'" }
|
||||
];
|
||||
|
||||
const DEPLOYMENTS_COLUMNS: Array<{ name: string; ddl: string }> = [
|
||||
{ name: 'script_id', ddl: 'ALTER TABLE deployments ADD COLUMN script_id INTEGER REFERENCES scripts(id)' },
|
||||
{ name: 'script_version_id', ddl: 'ALTER TABLE deployments ADD COLUMN script_version_id INTEGER REFERENCES script_versions(id)' },
|
||||
{ name: 'prior_version_id', ddl: 'ALTER TABLE deployments ADD COLUMN prior_version_id INTEGER REFERENCES script_versions(id)' },
|
||||
{ name: 'beta_id', ddl: 'ALTER TABLE deployments ADD COLUMN beta_id INTEGER REFERENCES betas(id)' },
|
||||
{ name: 'rolled_back_by', ddl: 'ALTER TABLE deployments ADD COLUMN rolled_back_by TEXT REFERENCES deployments(id)' }
|
||||
];
|
||||
|
||||
function migrateTable(handle: Database.Database, table: string, cols: Array<{ name: string; ddl: string }>): void {
|
||||
const rows = handle.prepare(`PRAGMA table_info(${table})`).all() as Array<{ name: string }>;
|
||||
const existing = new Set(rows.map((r) => r.name));
|
||||
for (const col of cols) {
|
||||
if (!existing.has(col.name)) handle.exec(col.ddl);
|
||||
}
|
||||
}
|
||||
|
||||
// The pre-script-model beta tables had entirely different shapes (slug PK,
|
||||
// beta_scripts, beta_deploys). schema.sql defines the new shape; CREATE TABLE
|
||||
// IF NOT EXISTS is a no-op if the old tables already exist, so we have to
|
||||
@@ -84,6 +113,8 @@ export function db(): Database.Database {
|
||||
dropLegacyBetaTables(_db);
|
||||
_db.exec(schemaSql);
|
||||
migrateServers(_db);
|
||||
migrateTable(_db, 'script_versions', SCRIPT_VERSIONS_COLUMNS);
|
||||
migrateTable(_db, 'deployments', DEPLOYMENTS_COLUMNS);
|
||||
|
||||
return _db;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user