Run the gate, the editor suite and the three games on the Gitea runner
game-maker / suite (push) Successful in 7m31s
game-maker / suite (push) Successful in 7m31s
The job image (tools/ci/Dockerfile, label game-maker-ci) carries chromium with the Vulkan drivers, php-cli and the host's fonts; the render device itself comes from the runner's container.options, so a job container gets the Intel GPU instead of llvmpipe. tools/ci/serve.sh puts the checkout behind /game-maker/ with php -S and writes the project shells the seeders need; every tool now takes its server from GAME_MAKER_BASE_URL rather than from a project id repeated in shell scripts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c47fd5e4dc
commit
4f0908df77
8 files changed
+181
-4
No files matched your search
@@ -0,0 +1,21 @@
|
||||
# The image behind the Gitea Actions label `game-maker-ci`. It is built on the host and kept
|
||||
# local (the runner has `force_pull: false`), so a change here needs a rebuild:
|
||||
#
|
||||
# DOCKER_BUILDKIT=0 docker build --network git_default -t game-maker-ci:latest tools/ci
|
||||
#
|
||||
# Both flags are needed on stein2: DNS is dead in Docker's default bridge network, and Buildkit
|
||||
# cannot join a named network.
|
||||
FROM node:22-bookworm
|
||||
|
||||
# chromium + the Vulkan drivers: the e2e harness starts chromium with --use-angle=vulkan and has
|
||||
# no software fallback. The render device itself comes from the runner's container.options;
|
||||
# without it chromium falls back to llvmpipe and gets WebGL 1.0 only.
|
||||
# php-cli serves api/index.php, which every tool loads and saves its project through.
|
||||
# The fonts are the host's set on purpose: the checks measure text widths to find click points,
|
||||
# so a different set moves them.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
chromium mesa-vulkan-drivers libvulkan1 \
|
||||
php-cli php-mbstring \
|
||||
fonts-dejavu-core fonts-droid-fallback fonts-noto-color-emoji fonts-noto-mono \
|
||||
fonts-texgyre fonts-urw-base35 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Creates the empty project files the seeders write into. `PUT ?r=projects/{id}` does not create
|
||||
* a project and `POST` hands out a random id, so a fresh CI checkout has to put the shells with
|
||||
* the known ids in place itself. The playground is left out – no tool may touch it.
|
||||
*
|
||||
* Usage: node tools/ci/project-shells.mjs [dataDir]
|
||||
*/
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { PROJECTS } from '../lib/projects.mjs';
|
||||
|
||||
const root = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
|
||||
const dir = process.argv[2] ?? resolve(root, 'data/projects');
|
||||
|
||||
await mkdir(dir, { recursive: true });
|
||||
for (const [name, id] of Object.entries(PROJECTS)) {
|
||||
if (name === 'playground') continue;
|
||||
const doc = {
|
||||
id,
|
||||
name,
|
||||
revision: 0,
|
||||
updatedAt: '1970-01-01T00:00:00Z',
|
||||
project: {},
|
||||
};
|
||||
await writeFile(resolve(dir, `${id}.json`), `${JSON.stringify(doc)}\n`);
|
||||
console.log(`shell ${name} ${id}`);
|
||||
}
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
# The editor suite in CI: serve the checkout, seed the fixture, run every step.
|
||||
# Ends in a line that survives a pipe, like check.sh does.
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$(readlink -f "$0")")/../.."
|
||||
source tools/ci/serve.sh
|
||||
game_maker_serve
|
||||
|
||||
set +e
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs
|
||||
code=$?
|
||||
echo "=== E2E EXIT $code ==="
|
||||
exit $code
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# The three example games in CI: seed each one, then play it in a headless browser.
|
||||
# Ends in a line that survives a pipe, like check.sh does.
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$(readlink -f "$0")")/../.."
|
||||
source tools/ci/serve.sh
|
||||
game_maker_serve
|
||||
|
||||
set +e
|
||||
code=0
|
||||
for game in jumprun tetris actor; do
|
||||
echo "--- $game"
|
||||
node "tools/seed-$game.mjs" && node "tools/smoke-$game.mjs" || code=1
|
||||
done
|
||||
echo "=== SMOKES EXIT $code ==="
|
||||
exit $code
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
# Sourced, not run: it leaves the PHP server in the caller's background and exports
|
||||
# GAME_MAKER_BASE_URL, which every tool reads.
|
||||
#
|
||||
# The build wires its assets absolutely under /game-maker/dist/, so the checkout has to be
|
||||
# served under that path segment – hence the symlink into /srv rather than `-t .`.
|
||||
|
||||
export GAME_MAKER_BASE_URL=http://127.0.0.1:8080/game-maker/
|
||||
|
||||
game_maker_serve() {
|
||||
local root
|
||||
root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
|
||||
|
||||
mkdir -p "$root/data/projects" "$root/data/textures"
|
||||
node "$root/tools/ci/project-shells.mjs"
|
||||
|
||||
# A server from an earlier step of the same job is fine to keep.
|
||||
if curl -sf "${GAME_MAKER_BASE_URL}api/index.php?r=projects" >/dev/null 2>&1; then
|
||||
echo "server already up at $GAME_MAKER_BASE_URL"
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p /srv && ln -sfn "$root" /srv/game-maker
|
||||
# Without workers the single-threaded dev server stalls: the editor fetches project and
|
||||
# textures in parallel.
|
||||
PHP_CLI_SERVER_WORKERS=8 php -S 0.0.0.0:8080 -t /srv >/tmp/php-server.log 2>&1 &
|
||||
|
||||
for _ in $(seq 60); do
|
||||
curl -sf "${GAME_MAKER_BASE_URL}api/index.php?r=projects" >/dev/null 2>&1 && break
|
||||
sleep 0.5
|
||||
done
|
||||
if ! curl -sf "${GAME_MAKER_BASE_URL}api/index.php?r=projects" >/dev/null 2>&1; then
|
||||
echo "the server never came up" >&2
|
||||
tail -20 /tmp/php-server.log >&2
|
||||
return 1
|
||||
fi
|
||||
echo "serving $root at $GAME_MAKER_BASE_URL"
|
||||
}
|
||||
@@ -24,12 +24,14 @@ export const PROJECTS = {
|
||||
export const DEFAULT_BASE_URL = 'https://nockal.com/game-maker/';
|
||||
|
||||
/**
|
||||
* Reads `[projectId] [baseUrl]` from argv, falling back to `defaultId`. Targeting the playground
|
||||
* aborts: no tool may overwrite or mutate it.
|
||||
* Reads `[projectId] [baseUrl]` from argv, falling back to `defaultId` and to
|
||||
* `GAME_MAKER_BASE_URL` – which is how CI points every tool at its own server without
|
||||
* repeating the project ids in shell scripts. Targeting the playground aborts: no tool may
|
||||
* overwrite or mutate it.
|
||||
*/
|
||||
export function cliArgs(script, defaultId) {
|
||||
const projectId = process.argv[2] ?? defaultId;
|
||||
const baseUrl = process.argv[3] ?? DEFAULT_BASE_URL;
|
||||
const baseUrl = process.argv[3] ?? process.env.GAME_MAKER_BASE_URL ?? DEFAULT_BASE_URL;
|
||||
if (projectId === PROJECTS.playground) {
|
||||
console.error(`refusing to run ${script} against the playground project (${PROJECTS.playground}).`);
|
||||
process.exit(2);
|
||||
|
||||
Reference in new issue
Block a user