Files
SGF/scripts/payable-history-sgf-run.mjs
2026-11-02 20:29:34 +02:00

35 lines
3.7 KiB
JavaScript

import fs from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
import {spawnSync} from 'node:child_process';
const read=p=>JSON.parse(fs.readFileSync(p,'utf8').replace(/^\uFEFF/,''));
const state=read('C:/laragon/data/sgf-tempo/run/modular-regression-current.json');
if(state.port!==55439||!/^[a-f0-9]{12}$/.test(state.id))throw Error('Wrong isolated host');
const resume=process.argv[2];if(resume&&!/^[a-f0-9]{12}$/.test(resume))throw Error('Invalid QA resume tag');
const tag=resume??crypto.randomBytes(6).toString('hex'),root=path.join(state.root,'private/payable-history-'+tag);
fs.mkdirSync(root,{recursive:true});
const admin=fs.readFileSync(path.join(state.root,'private/admin-password.txt'),'utf8').trim();
const pg=input=>{const r=spawnSync('C:/Program Files/PostgreSQL/17/bin/psql.exe',['-h','127.0.0.1','-p','55439','-U','sgf_regression_owner','-d','postgres','-Atq','-v','ON_ERROR_STOP=1'],{input,encoding:'utf8',windowsHide:true,env:{...process.env,PGPASSWORD:admin}});if(r.status!==0)throw Error('Isolated database provisioning refused');return r.stdout.trim();};
if(pg("SELECT current_setting('cluster_name')")!=='sgf_modular_regression_'+state.id)throw Error('Wrong cluster');
let config={tag,root,cluster:'sgf_modular_regression_'+state.id,source_instance:'qa-history-'+tag};
for(const mode of resume?[]:['native','sgf']){
const role='payable_history_'+mode+'_'+tag,database=(mode==='native'?'compras_receipts_test_':'payable_sgf_')+tag,password=crypto.randomBytes(32).toString('hex');
pg(`CREATE ROLE ${role} LOGIN PASSWORD '${password}' NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS; CREATE DATABASE ${database} OWNER ${role}; REVOKE ALL ON DATABASE ${database} FROM PUBLIC;`);
const storage=path.join(root,mode);for(const d of ['framework/cache/data','framework/views','framework/sessions','logs','cache'])fs.mkdirSync(path.join(storage,d),{recursive:true});
config[mode]={root:path.resolve(mode==='native'?'../compras':'.'),database,role,password,storage};
}
const settings=path.join(root,'settings.json');if(resume){config=read(settings);if(config.root!==root||config.tag!==tag||config.cluster!=='sgf_modular_regression_'+state.id)throw Error('Resume context refused');}else fs.writeFileSync(settings,JSON.stringify(config,null,2));
const php='C:/laragon/tools/sgf-tempo/php-8.4.27/php.exe';
const phases=process.argv[3]?process.argv[3].split(','):['native','sgf','regression','native-post'];
for(const phase of phases){
const expected={native:'source.json',sgf:'fixture.json',regression:'regression.json','native-post':'native-post.json',post:'sgf-post.json'}[phase];if(!expected)throw Error('Unknown phase');const started=Date.now();
if(fs.existsSync(path.join(root,expected))){const prior=fs.readFileSync(path.join(root,expected)),archive=path.join(root,expected+'.'+crypto.createHash('sha256').update(prior).digest('hex')+'.archive');if(!fs.existsSync(archive))fs.writeFileSync(archive,prior,{flag:'wx'});}
const r=spawnSync(php,['scripts/payable-history-sgf-proof.php',settings,phase],{cwd:process.cwd(),encoding:'utf8',windowsHide:true,maxBuffer:8*1024*1024});
fs.writeFileSync(path.join(root,phase+'-'+started+'-stdout.txt'),r.stdout||'');fs.writeFileSync(path.join(root,phase+'-'+started+'-stderr.txt'),r.stderr||'');
if(r.status!==0||!fs.existsSync(path.join(root,expected))||fs.statSync(path.join(root,expected)).mtimeMs<started-2000)throw Error('QA phase '+phase+' failed; diagnostics retained privately at '+root);
process.stdout.write(r.stdout);
}
fs.writeFileSync(path.join(state.root,'payable-history-latest.json'),JSON.stringify({tag,root},null,2));
console.log(JSON.stringify({tag,root,synthetic_only:true,databases_retained:true,installed_or_demo_databases_touched:false}));