import os, pathlib, shutil, subprocess, json root = pathlib.Path(__file__).resolve().parent source = pathlib.Path(os.environ.get('NETLIFY_VERIFY_REPO_ROOT', '/tmp/netliloop-work/build')).resolve() sandbox = root/'mutations' sandbox.mkdir(exist_ok=True) (sandbox/'package.json').write_text('{"type":"module"}') if (sandbox/'node_modules').is_symlink(): (sandbox/'node_modules').unlink() (sandbox/'node_modules').symlink_to(source/'node_modules', target_is_directory=True) for package, test in [('run-utils','options.test.ts'),('git-utils','filenames.test.ts')]: dest = sandbox/'packages'/package dest.mkdir(parents=True,exist_ok=True) shutil.copytree(source/'packages'/package/'src', dest/'src', dirs_exist_ok=True) (dest/'tests').mkdir(exist_ok=True) shutil.copy(source/'packages'/package/'tests'/test, dest/'tests'/test) shutil.copy(source/'packages'/package/'package.json', dest/'package.json') shutil.copy(source/'packages'/package/'vitest.config.ts', dest/'vitest.config.ts') env = {'PATH':os.environ['PATH'], 'HOME':str(sandbox), 'TMPDIR':'/tmp', 'NETLIFY_INTERNAL_GIT':'1', 'CI':'1', 'NO_COLOR':'1'} vitest = str(source/'node_modules/vitest/vitest.mjs') receipts = [] def execute(label, package, tests, should_fail): command = ['node',vitest,'run','--config',f'packages/{package}/vitest.config.ts',*tests] result = subprocess.run(command,cwd=sandbox,env=env,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True) (root/(label+'.log')).write_text(result.stdout) lines = [line.strip() for line in result.stdout.splitlines() if 'Test Files' in line or 'Tests ' in line] print(label, 'exit='+str(result.returncode), '; '.join(lines), flush=True) assert bool(result.returncode) == should_fail, (label,result.stdout) receipts.append({'label':label, 'command':command, 'exit':result.returncode, 'summary':lines}) run_test=['packages/run-utils/tests/options.test.ts'] git_test=['packages/git-utils/tests/filenames.test.ts'] execute('isolated-baseline', 'run-utils', run_test+git_test, False) run_path=sandbox/'packages/run-utils/src/main.ts' git_path=sandbox/'packages/git-utils/src/diff.ts' run_original=run_path.read_text() git_original=git_path.read_text() mutations=[ ('mutant-command-defaults','run-utils',run_test,run_path,run_original.replace('execaCommand(command, optionsA)','execaCommand(command, options)')), ('mutant-omitted-argv','run-utils',run_test,run_path,run_original.replace('return [[], options]','return []')), ('mutant-explicit-prefer-local-false','run-utils',run_test,run_path,run_original.replace('execaCommand(command, optionsA)','execaCommand(command, { ...optionsA, preferLocal: true })')), ('mutant-original-line-parser','git-utils',git_test,git_path,"""import { git } from './exec.js' export const getDiffFiles = function (base, head, cwd) { const stdout = git(['diff', '--name-status', '--no-renames', `${base}...${head}`], cwd) const files = stdout.split('\\n').map((line) => { const result = /([ADM])\\s+(.*)/.exec(line) if (result === null) return const [, type, filepath] = result return { type, filepath } }).filter(Boolean) const byType = (type) => files.filter((file) => file.type === type).map(file => file.filepath) return { modifiedFiles: byType('M'), createdFiles: byType('A'), deletedFiles: byType('D') } } """), ('mutant-space-filename','git-utils',git_test,git_path,git_original.replace('filepath: fields[index + 1]', "filepath: fields[index + 1].replaceAll(' ', '_')")), ] try: for label,package,tests,path,mutant in mutations: assert mutant != path.read_text() path.write_text(mutant) execute(label,package,tests,True) path.write_text(run_original if path == run_path else git_original) finally: run_path.write_text(run_original) git_path.write_text(git_original) execute('isolated-restored-green','run-utils',run_test+git_test,False) (root/'mutation-receipts.json').write_text(json.dumps(receipts,indent=2))