Files
codegraph/scripts/validation/release-installers.cjs
T

50 lines
5.0 KiB
JavaScript

// Disposable archive tests. All downloads are inert local fixtures. No user PATH changes.
const fs=require('node:fs'), path=require('node:path'), os=require('node:os'), cp=require('node:child_process'), crypto=require('node:crypto'), assert=require('node:assert/strict');
const repo=path.resolve(__dirname,'../..');
const up=require(path.join(repo,'dist/upgrade/index.js'));
const temp=fs.mkdtempSync(path.join(os.tmpdir(),'cg-installer-proof-'));
const rows=[];
function run(cmd,args,env={}) { const r=cp.spawnSync(cmd,args,{encoding:'utf8',timeout:20000,env:{...process.env,...env}}); if(r.error)throw r.error;return r; }
function check(name,f){try{f();rows.push({name,pass:true});}catch(e){rows.push({name,pass:false,error:String(e)});}console.log(JSON.stringify(rows.at(-1)));}
const hash=f=>crypto.createHash('sha256').update(fs.readFileSync(f)).digest('hex');
try {
for(const version of ['v1.6.1','1.6.1-rc.1+build.2']) check('legitimate-version-'+version,()=>assert(up.parseSemver(version)));
for(const version of ['1.6.1 invalid','1.6.1&INERT','1.6.1/../inert','01.6.1']) check('invalid-version-'+version,()=>assert.equal(up.parseSemver(version),null));
const windows=process.platform==='win32';
const target=windows?'win32-x64':'linux-x64';
const asset=`codegraph-${target}.${windows?'zip':'tar.gz'}`;
const tree=path.join(temp,`codegraph-${target}`);fs.mkdirSync(path.join(tree,'bin'),{recursive:true});fs.writeFileSync(path.join(tree,'bin','codegraph'),'replacement');fs.writeFileSync(path.join(tree,'node.exe'),'inert');
const archive=path.join(temp,asset);
if(windows){const r=run('powershell.exe',['-NoProfile','-Command',`Compress-Archive -LiteralPath '${tree.replace(/'/g,"''")}' -DestinationPath '${archive.replace(/'/g,"''")}'`]);assert.equal(r.status,0,r.stderr);}
else {const r=run('tar',['-czf',archive,'-C',temp,`codegraph-${target}`]);assert.equal(r.status,0,r.stderr);}
const sum=`${hash(archive)} ${asset}\n`;
const stub=path.join(temp,'stubs');fs.mkdirSync(stub);
if(!windows){
fs.writeFileSync(path.join(stub,'uname'),'#!/bin/sh\ncase "$1" in -s) echo Linux;; -m) echo x86_64;; esac\n',{mode:0o755});
fs.writeFileSync(path.join(stub,'curl'),'#!/bin/sh\nwhile [ "$#" -gt 0 ]; do case "$1" in -o) shift; out="$1";; https:*) url="$1";; esac; shift; done\ncase "$url" in */SHA256SUMS) [ "$FIXTURE_MODE" != missing ] || exit 22; cp "$FIXTURE_SUMS" "$out";; *) cp "$FIXTURE_ARCHIVE" "$out";; esac\n',{mode:0o755});
}
const modes=['valid','mismatch','missing','duplicate','unlisted'];
for(const kind of windows?['powershell-install','powershell-upgrade']:['shell-install']) for(const mode of modes) check(`${kind}-${mode}`,()=>{
const caseDir=path.join(temp,kind,mode);fs.mkdirSync(caseDir,{recursive:true});
const install=path.join(caseDir,"O'Brien-install");
const dest=path.join(install,windows?'current':'versions/v1.6.1');fs.mkdirSync(path.join(dest,'bin'),{recursive:true});fs.writeFileSync(path.join(dest,'bin','codegraph'),'original');
const sums=path.join(caseDir,'sums');fs.writeFileSync(sums,mode==='mismatch'?'0'.repeat(64)+` ${asset}\n`:mode==='duplicate'?sum+sum:mode==='unlisted'?sum.replace(asset,'unrelated.tar.gz'):sum);
const env={CODEGRAPH_VERSION:'v1.6.1',CODEGRAPH_INSTALL_DIR:install,CODEGRAPH_BIN_DIR:path.join(caseDir,'out'),FIXTURE_MODE:mode,FIXTURE_ARCHIVE:archive,FIXTURE_SUMS:sums,PATH:stub+path.delimiter+process.env.PATH};
let result;
if(windows){
// Install prefix includes real validation/download/extraction. Stop before user PATH mutation.
const body=kind==='powershell-install'?fs.readFileSync(path.join(repo,'install.ps1'),'utf8').split('# 4. Put the launcher')[0]:up.buildWindowsUpgradeScript(dest,'v1.6.1','x64');
const script=path.join(caseDir,'test.ps1');
fs.writeFileSync(script,`$ErrorActionPreference='Stop'\nfunction Invoke-WebRequest { param($Uri,$OutFile) if($Uri.EndsWith('/SHA256SUMS')){if($env:FIXTURE_MODE -eq 'missing'){throw 'fixture 404'};Copy-Item -LiteralPath $env:FIXTURE_SUMS -Destination $OutFile}else{Copy-Item -LiteralPath $env:FIXTURE_ARCHIVE -Destination $OutFile} }\n`+body);
result=run('powershell.exe',['-NoProfile','-ExecutionPolicy','Bypass','-File',script],env);
}else result=run('sh',[path.join(repo,'install.sh')],env);
assert.equal(result.status===0,mode==='valid',result.stdout+'\n'+result.stderr);
if(mode==='mismatch') assert.match(result.stdout+'\n'+result.stderr,/checksum mismatch/i);
if(mode==='duplicate'||mode==='unlisted') assert.match(result.stdout+'\n'+result.stderr,/missing or ambiguous|checksum.*(missing|duplicate)|expected.*checksum/i);
if(mode==='missing'&&windows) assert.match(result.stdout+'\n'+result.stderr,/fixture 404/);
assert.equal(fs.readFileSync(path.join(dest,'bin','codegraph'),'utf8'),mode==='valid'?'replacement':'original');
});
console.log(JSON.stringify({platform:process.platform,node:process.version,scope:windows?'native PowerShell install-prefix and full generated upgrade':'actual shell installer with inert download stubs',rows}));
process.exitCode=rows.every(r=>r.pass)?0:1;
}finally{fs.rmSync(temp,{recursive:true,force:true});}