From d64e5b6518016db0f88cc5fa81d29fe6c7894775 Mon Sep 17 00:00:00 2001 From: blomios Date: Tue, 6 Oct 2026 21:18:24 +0200 Subject: [PATCH] feat(deploy): publish Nodecast and Laya images together (#31) Update the Docker build/push helper to build and push both application and Laya images, and document the configurable image targets. Co-Authored-By: Claude Opus 4.8 --- README.md | 2 +- scripts/docker-build-push.sh | 7 +++- test/dockerBuildPushScript.test.js | 63 ++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 test/dockerBuildPushScript.test.js diff --git a/README.md b/README.md index 2ec04e2..817ee1e 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ LAYA_BASE_URL=http://localhost:8000 npm start `http://laya:8000` is a Compose-internal hostname and does not resolve from a host process. -Repository maintainers can still build and publish the nodecast-tv image with `./scripts/docker-build-push.sh`; this script is not needed by Compose users. +Repository maintainers can build and publish both the nodecast-tv and Laya images with `./scripts/docker-build-push.sh`; this script is not needed by Compose users. `REGISTRY`, `OWNER`, `IMAGE_NAME`, `LAYA_IMAGE_NAME`, and `TAG` can override the publication targets. Use `--no-push` to build both images locally without publishing them. ### Hardware Acceleration Setup diff --git a/scripts/docker-build-push.sh b/scripts/docker-build-push.sh index 1df4070..437a0a7 100755 --- a/scripts/docker-build-push.sh +++ b/scripts/docker-build-push.sh @@ -5,8 +5,10 @@ set -euo pipefail REGISTRY=${REGISTRY:-gitea.anthonybouteiller.ovh} OWNER=${OWNER:-blomios} IMAGE_NAME=${IMAGE_NAME:-nodecast-tv} +LAYA_IMAGE_NAME=${LAYA_IMAGE_NAME:-nodecast-tv-laya} TAG=${TAG:-latest} IMAGE="${REGISTRY}/${OWNER}/${IMAGE_NAME}:${TAG}" +LAYA_IMAGE="${REGISTRY}/${OWNER}/${LAYA_IMAGE_NAME}:${TAG}" push_image=true if [[ "${1:-}" == "--no-push" ]]; then @@ -23,8 +25,10 @@ fi repo_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) -echo "Target image: ${IMAGE}" +echo "Target Nodecast image: ${IMAGE}" +echo "Target Laya image: ${LAYA_IMAGE}" docker build --file "${repo_dir}/Dockerfile" --tag "${IMAGE}" "${repo_dir}" +docker build --file "${repo_dir}/Dockerfile.laya" --tag "${LAYA_IMAGE}" "${repo_dir}" if [[ "${DRY_RUN:-false}" == "true" || "${push_image}" == "false" ]]; then echo "Push skipped." @@ -32,3 +36,4 @@ if [[ "${DRY_RUN:-false}" == "true" || "${push_image}" == "false" ]]; then fi docker push "${IMAGE}" +docker push "${LAYA_IMAGE}" diff --git a/test/dockerBuildPushScript.test.js b/test/dockerBuildPushScript.test.js new file mode 100644 index 0000000..2d80c75 --- /dev/null +++ b/test/dockerBuildPushScript.test.js @@ -0,0 +1,63 @@ +const test = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const os = require('node:os'); +const path = require('node:path'); +const { spawnSync } = require('node:child_process'); + +const root = path.resolve(__dirname, '..'); +const script = path.join(root, 'scripts', 'docker-build-push.sh'); + +function runWithMockDocker(args = [], env = {}) { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'nodecast-docker-build-push-')); + const bin = path.join(dir, 'bin'); + fs.mkdirSync(bin); + const log = path.join(dir, 'docker.log'); + const docker = path.join(bin, 'docker'); + fs.writeFileSync(docker, `#!/usr/bin/env bash\nprintf '%s\\n' "$*" >> "${log}"\n`); + fs.chmodSync(docker, 0o755); + const result = spawnSync('bash', [script, ...args], { + cwd: root, + env: { + ...process.env, + PATH: `${bin}${path.delimiter}${process.env.PATH}`, + ...env + }, + encoding: 'utf8' + }); + const commands = fs.existsSync(log) ? fs.readFileSync(log, 'utf8').trim().split('\n').filter(Boolean) : []; + fs.rmSync(dir, { recursive: true, force: true }); + return { + result, + commands + }; +} + +test('docker build/push script builds and pushes Nodecast and Laya images by default', () => { + const { result, commands } = runWithMockDocker(); + assert.equal(result.status, 0, result.stderr || result.stdout); + assert.deepEqual(commands, [ + `build --file ${path.join(root, 'Dockerfile')} --tag gitea.anthonybouteiller.ovh/blomios/nodecast-tv:latest ${root}`, + `build --file ${path.join(root, 'Dockerfile.laya')} --tag gitea.anthonybouteiller.ovh/blomios/nodecast-tv-laya:latest ${root}`, + 'push gitea.anthonybouteiller.ovh/blomios/nodecast-tv:latest', + 'push gitea.anthonybouteiller.ovh/blomios/nodecast-tv-laya:latest' + ]); +}); + +test('--no-push builds both images and skips both pushes', () => { + const { result, commands } = runWithMockDocker(['--no-push']); + assert.equal(result.status, 0, result.stderr || result.stdout); + assert.deepEqual(commands, [ + `build --file ${path.join(root, 'Dockerfile')} --tag gitea.anthonybouteiller.ovh/blomios/nodecast-tv:latest ${root}`, + `build --file ${path.join(root, 'Dockerfile.laya')} --tag gitea.anthonybouteiller.ovh/blomios/nodecast-tv-laya:latest ${root}` + ]); +}); + +test('DRY_RUN=true builds both images and skips both pushes', () => { + const { result, commands } = runWithMockDocker([], { DRY_RUN: 'true' }); + assert.equal(result.status, 0, result.stderr || result.stdout); + assert.deepEqual(commands, [ + `build --file ${path.join(root, 'Dockerfile')} --tag gitea.anthonybouteiller.ovh/blomios/nodecast-tv:latest ${root}`, + `build --file ${path.join(root, 'Dockerfile.laya')} --tag gitea.anthonybouteiller.ovh/blomios/nodecast-tv-laya:latest ${root}` + ]); +});