imrishabh18/nema-23-stepper-controller
A 57 mm four-layer RP2040 NEMA23 stepper-controller PCB with USB‑C/USB‑PD power input, protected motor rail, DRV8452 dual-winding driver, bidirectional current sensing, temperature/enable interlock, optional magnetic encoder, RGB LED and buzzer status indicators, and motor/test connectors.
- Version
- 1.2.3
- License
- unset
- Stars
- 0
scripts/check-release.mjs
import {spawnSync} from 'node:child_process'
import {mkdirSync,writeFileSync,readFileSync,readdirSync} from 'node:fs'
import {createHash} from 'node:crypto'
// Deliberately stop on every failing stage. Never publish from this script.
const steps=[
['toolchain','bun',['run','verify:toolchain']],
['typecheck','bun',['run','typecheck']],
['schematic-source','bun',['scripts/check-schematic-source.mjs']],
['electrical-range','bun',['scripts/check-feature-source.mjs']],
['netlist','./node_modules/.bin/tsci',['check','netlist','index.circuit.tsx']],
['schematic','bun',['run','check:schematic']],
['placement','./node_modules/.bin/tsci',['check','placement','index.circuit.tsx']],
['drc','bun',['run','check:drc']],
['power-layers','bun',['scripts/check-power-layers.mjs']],
['shorts','bun',['run','check:shorts']],
['ground','uv',['run','--with','shapely==2.1.2','python','scripts/audit-ground-copper.py','dist/index/circuit.json','--output=checks/ground-copper-connectivity.json']],
['kelvin','uv',['run','--with','shapely==2.1.2','python','scripts/audit-kelvin-connections.py','dist/index/circuit.json']],
['previews','bun',['run','previews']],
]
mkdirSync('checks/release',{recursive:true})
const paths=['package.json','bun.lock','tsconfig.json','tscircuit.config.json','index.circuit.tsx','usb-pd-power.tsx','power-copper.tsx','passives.tsx','feature-parity.tsx','board-markings.tsx','symbol-text-compat.ts','schematic-section-notes.ts','usb-c-compat.ts','engineering/schematic-advisories.json','engineering/motor-profile.json','engineering/schematic-style.json']
const add=dir=>{for(const e of readdirSync(dir,{withFileTypes:true})){const p=`${dir}/${e.name}`;if(e.isDirectory())add(p);else paths.push(p)}}
for(const dir of ['vendor','imports','routing','scripts','assets','engineering/easyeda'])add(dir)
const hashes=()=>Object.fromEntries(paths.sort().map(p=>[p,createHash('sha256').update(readFileSync(p)).digest('hex')]))
const before=hashes()
writeFileSync('checks/release/status.json',JSON.stringify({status:'running',startedAt:new Date().toISOString()},null,2))
for(const [name,command,args] of steps){
console.log(`Checking ${name}...`)
const r=spawnSync(command,args,{encoding:'utf8',maxBuffer:32*1024*1024})
const output=(r.stdout??'')+(r.stderr??'')
writeFileSync(`checks/release/${name}.log`,output)
if(r.error||r.status!==0||(name==='netlist'&&!/Errors: 0\b/.test(output))||(name==='placement'&&/<PcbPlacementIssues>|Errors: [1-9]/.test(output))){
writeFileSync('checks/release/status.json',JSON.stringify({status:'failed',stage:name,finishedAt:new Date().toISOString()},null,2))
process.stderr.write(output)
throw r.error??new Error(`${name} failed (exit ${r.status}); publication blocked`)
}
console.log(`PASS: ${name}`)
}
if(JSON.stringify(before)!==JSON.stringify(hashes()))throw Error('Source changed during validation; rerun all release checks')
writeFileSync('checks/release/inputs.json',JSON.stringify(before,null,2))
writeFileSync('checks/release/status.json',JSON.stringify({status:'passed',finishedAt:new Date().toISOString(),checks:steps.map(s=>s[0])},null,2))
console.log('PASS: release checks including full-build DRC and all-layer Gerber shorts. Hardware validation remains required.')