Files
NovaSonic/scripts/build-push-images.mjs
marcandClaude Opus 5 043ec3a108 refactor(docker): docker-compose.yml ist der Pull-Weg, Bauen wandert nach .dev.yml
Namen getauscht: das Standard-Compose zieht jetzt die fertigen Registry-Images
(vorher docker-compose.prod.yml), die Build-Variante heisst docker-compose.dev.yml.
Weniger verwirrend, weil der Produktivfall ohne -f auskommt. Kopfkommentare,
README, CLAUDE.md, .env.example und build-push-images.mjs entsprechend angepasst.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 16:15:46 +02:00

57 lines
2.5 KiB
JavaScript

#!/usr/bin/env node
// Build the three NovaSonic images and push them to your registry, so the production host just PULLS
// (docker-compose.yml) instead of building (that's docker-compose.dev.yml). Run from your dev machine:
//
// npm run push-images # builds + pushes REGISTRY/*:TAG (and :latest)
//
// Config (env or a gitignored scripts/.env.release / repo .env):
// REGISTRY e.g. gitea.honeyy.duckdns.org/docker (Gitea uses a LOWERCASE owner)
// TAG image tag (default: latest)
// You must `docker login <registry-host>` once first. Plain-HTTP internal registries also need the
// daemon's insecure-registries list (see .env.example).
import { spawnSync } from 'node:child_process';
import { readFileSync, existsSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join, resolve } from 'node:path';
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
// Load REGISTRY/TAG from a local env file if present (repo .env, then scripts/.env.release).
for (const f of [join(root, '.env'), join(root, 'scripts', '.env.release')]) {
if (!existsSync(f)) continue;
for (const line of readFileSync(f, 'utf8').split('\n')) {
const m = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*)\s*$/i);
if (m && !(m[1] in process.env)) process.env[m[1]] = m[2].replace(/^["']|["']$/g, '');
}
}
const REGISTRY = (process.env.REGISTRY || '').replace(/\/$/, '');
const TAG = process.env.TAG || 'latest';
if (!REGISTRY) { console.error('\n✖ REGISTRY muss gesetzt sein (env oder .env). Siehe .env.example.'); process.exit(1); }
// name → build context (relative to repo root). Frontend uses the root Dockerfile.
const images = {
'novasonic-frontend': '.',
'novasonic-backend': 'backend',
'novasonic-scrobble': 'scrobble',
};
function run(cmd, args) {
console.log(`\n$ ${cmd} ${args.join(' ')}`);
const r = spawnSync(cmd, args, { cwd: root, stdio: 'inherit', shell: process.platform === 'win32' });
if (r.status !== 0) { console.error(`\n✖ Fehlgeschlagen: ${cmd} ${args.join(' ')}`); process.exit(1); }
}
for (const [name, ctx] of Object.entries(images)) {
const ref = `${REGISTRY}/${name}:${TAG}`;
const latest = `${REGISTRY}/${name}:latest`;
console.log(`\n=== ${name} → ${ref} ===`);
run('docker', ['build', '-t', ref, '-t', latest, ctx]);
run('docker', ['push', ref]);
if (latest !== ref) run('docker', ['push', latest]);
}
console.log(`\n✔ Alle Images gebaut + gepusht (${REGISTRY}/*:${TAG}). Auf dem Server:`);
console.log(' docker compose pull && docker compose up -d');