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