Files
vendoo/tools/verify-release-1.27.0.mjs
Masterluke77andGitHub 6f48827f4d Vendoo 1.41.2 – Git Ignore Boundary & Module Tracking Hotfix (#18)
* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix

* fix: track native source modules with root-anchored runtime ignores
2026-07-09 17:09:00 +02:00

89 lines
6.2 KiB
JavaScript

import { readFileSync, readdirSync, existsSync } from 'fs';
import { resolve, extname, relative } from 'path';
import { spawnSync } from 'child_process';
const root = resolve(new URL('..', import.meta.url).pathname);
const failures = [];
const summary = { js_files: 0, json_files: 0, html_ids: 0, css_blocks: 0, nav_targets: 0 };
function walk(dir) {
return readdirSync(dir, { withFileTypes: true }).flatMap(entry => {
const full = resolve(dir, entry.name);
if (entry.isDirectory()) return ['node_modules', '.git', 'uploads'].includes(entry.name) ? [] : walk(full);
return [full];
});
}
for (const file of walk(root)) {
const ext = extname(file).toLowerCase();
if (['.js', '.mjs'].includes(ext)) {
summary.js_files += 1;
const result = spawnSync(process.execPath, ['--check', file], { encoding: 'utf8' });
if (result.status !== 0) failures.push(`${relative(root, file)}: ${result.stderr.trim()}`);
}
if (ext === '.json') {
summary.json_files += 1;
try { JSON.parse(readFileSync(file, 'utf8').replace(/^\uFEFF/, '')); }
catch (error) { failures.push(`${relative(root, file)}: ungültiges JSON (${error.message})`); }
}
}
const pkg = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'));
const html = readFileSync(resolve(root, 'public/index.html'), 'utf8');
const app = readFileSync(resolve(root, 'public/app.js'), 'utf8');
const css = readFileSync(resolve(root, 'public/style.css'), 'utf8');
const server = readFileSync(resolve(root, 'server.mjs'), 'utf8');
const db = readFileSync(resolve(root, 'lib/db.mjs'), 'utf8');
const worker = readFileSync(resolve(root, 'lib/image-batch-jobs.mjs'), 'utf8');
const editor = readFileSync(resolve(root, 'lib/image-editor.mjs'), 'utf8');
if (pkg.version !== '1.27.0') failures.push(`package.json-Version ist ${pkg.version}`);
for (const marker of ['content="1.27.0"', 'style.css?v=1.27.0', 'app.js?v=1.27.0']) if (!html.includes(marker)) failures.push(`Build-Marker fehlt: ${marker}`);
if (!app.startsWith("const VENDOO_UI_BUILD = '1.27.0';")) failures.push('UI-Build ist nicht 1.27.0');
const ids = [...html.matchAll(/\bid="([^"]+)"/g)].map(match => match[1]);
summary.html_ids = ids.length;
const duplicateIds = [...new Set(ids.filter((id, index) => ids.indexOf(id) !== index))];
if (duplicateIds.length) failures.push(`Doppelte HTML-IDs: ${duplicateIds.join(', ')}`);
const sections = new Set([...html.matchAll(/<section\s+id="([^"]+)"/g)].map(match => match[1]));
const navTargets = [...html.matchAll(/class="[^"]*nav-item[^"]*"[^>]*data-tab="([^"]+)"/g)].map(match => match[1]);
summary.nav_targets = navTargets.length;
for (const target of navTargets) if (!sections.has(target)) failures.push(`Navigation ohne Zielsektion: ${target}`);
if (!sections.has('image-factory')) failures.push('Bildproduktion-Seite fehlt');
if (!html.includes('data-tab="image-factory"')) failures.push('Bildproduktion-Navigation fehlt');
summary.css_blocks = (css.match(/{/g) || []).length;
if (summary.css_blocks !== (css.match(/}/g) || []).length) failures.push('CSS-Klammern unausgeglichen');
for (const marker of ['.image-factory-layout', '.image-factory-source-grid', '.image-factory-profile-grid', '.image-factory-job-list', '@container (max-width: 680px)']) if (!css.includes(marker)) failures.push(`Bildproduktions-CSS fehlt: ${marker}`);
for (const marker of [
"app.get('/api/image-batch/profiles'", "app.post('/api/image-batch/jobs'", "app.post('/api/image-batch/jobs/:id/pause'",
"app.post('/api/image-batch/jobs/:id/resume'", "app.post('/api/image-batch/jobs/:id/cancel'", "app.post('/api/image-batch/jobs/:id/retry'",
"app.get('/api/image-batch/jobs/:id/archive'", 'startImageBatchJobLoop()',
]) if (!server.includes(marker)) failures.push(`Batch-API fehlt: ${marker}`);
for (const table of ['image_batch_profiles', 'image_batch_jobs', 'image_batch_job_items']) if (!db.includes(`CREATE TABLE IF NOT EXISTS ${table}`)) failures.push(`Datenbanktabelle fehlt: ${table}`);
for (const profile of ['ebay-main','vinted-portrait','kleinanzeigen','etsy','instagram-square','instagram-portrait','webshop','original-optimized']) if (!db.includes(`'${profile}'`)) failures.push(`Standardprofil fehlt: ${profile}`);
for (const marker of ['createImageBatchJob', 'pauseImageBatchJob', 'resumeImageBatchJob', 'cancelImageBatchJob', 'retryImageBatchJob', 'retryImageBatchItem', 'getImageBatchOutputPaths']) if (!worker.includes(`function ${marker}`) && !worker.includes(`function ${marker}(`) && !worker.includes(`export function ${marker}`)) failures.push(`Worker-Funktion fehlt: ${marker}`);
for (const marker of ['outputDirectory = null', "RESIZE_FITS = new Set(['inside', 'contain', 'cover'])", "context: 'batch'"]) if (!(editor + worker).includes(marker)) failures.push(`Render-Erweiterung fehlt: ${marker}`);
for (const marker of ['setupImageFactory()', "if (tabId === 'image-factory') loadImageFactory()", 'submitImageFactoryJob', 'media-send-to-factory']) if (!app.includes(marker) && !html.includes(marker)) failures.push(`UI-Anbindung fehlt: ${marker}`);
const uiResult = spawnSync(process.execPath, [resolve(root, 'tools/verify-ui-contracts-1.26.1.mjs')], { encoding: 'utf8' });
if (uiResult.status !== 0) failures.push(`UI-Verträge: ${uiResult.stderr || uiResult.stdout}`);
const dbResult = spawnSync('python', [resolve(root, 'tools/verify-db-migrations.py')], { encoding: 'utf8' });
if (dbResult.status !== 0) failures.push(`DB-Migration: ${dbResult.stderr || dbResult.stdout}`);
for (const path of ['lib/image-batch-jobs.mjs', 'tools/verify-slice32-image-render.mjs', 'local-ai/workflows/vendoo_flux_schnell_api.json']) if (!existsSync(resolve(root, path))) failures.push(`Pflichtdatei fehlt: ${path}`);
const workflow = readFileSync(resolve(root, 'local-ai/workflows/vendoo_flux_schnell_api.json'), 'utf8');
if (workflow.includes('LoadImage')) failures.push('Freier FLUX-Workflow enthält LoadImage');
if (/FASHN|virtual_tryon/i.test(server + app)) failures.push('Entfernte VTO/FASHN-Logik wieder aktiv');
if (failures.length) {
console.error(JSON.stringify({ ok: false, failures, summary }, null, 2));
process.exit(1);
}
console.log(JSON.stringify({
ok: true, version: pkg.version, ...summary,
built_in_profiles: 8, persistent_batch_jobs: true, pause_resume_cancel_retry: true,
restart_recovery: true, gallery_integration: true, zip_export: true,
}, null, 2));