f46b2316f2c619e048e759f38c274afb50bb22b8
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
42647d309b |
Run the gate on stein2 and the suite on the WSL runner (#283)
The gate needs no GPU, so it goes back to the runner on stein2 (`game-maker-ci`, same image). The suite stays on `game-maker-wsl` on melektaus-atx. The two jobs no longer share the four cores of one runner while they overlap. - The change of `runs-on` for the gate is the user's own edit. - The header comment now says which job runs where. GM_TEST_WORKERS stays at two, for the day both jobs share one runner again. Tests: - Both runners were online in Gitea before the push (`stein2-docker`, `melektaus-atx-wsl`). - Prettier passes on the file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
857e23c69b |
Run CI on a WSL2 runner with the RTX 4070 (#283)
stein2 should stop carrying the full e2e run. The new runner lives in the WSL2 distro game-maker-ci on melektaus-atx and uses the same image and fonts. Its GPU sits behind /dev/dxg and Mesa's d3d12 driver, which headless chromium cannot reach, so the harness gets a second way to start the browser. - GAME_MAKER_BROWSER=wsl starts an invisible Xvfb and an X11 chromium on ANGLE/GL. Without the variable, stein2 keeps the headless Vulkan launch exactly as before. - The harness logs the renderer and stops on software rendering. Under WSL a missing d3d12 driver falls back to llvmpipe, which still offers WebGL 2 and would pass unnoticed. - The CI image gains xvfb. The font set is unchanged: fc-list gives the same 149 fonts with the same hash. - ci.yml runs both jobs on the new label game-maker-wsl. The stein2 runner keeps game-maker-ci, so moving back is one line per job. Findings: - Wayland on weston reached the GPU too, but drew at about 40 fps and let the editor clock stall in long runs (GM_STEPS=1-17: 2 failed). - Vulkan through a self-built dzn caps ANGLE at ES 2.0 because VK_EXT_provoking_vertex is missing, so chromium drops the GPU. - The flaky check in e2e 41 (#282) fails more often under WSL: two of three solo runs were red. Tests: - ./check.sh: 195 files, 2823 tests passed - WSL container, GM_STEPS=1-17: ALL PASSED, 553 checks - WSL container, full run: 1589 of 1590, the one FAIL is #282 - WSL container, smokes: 24 / 19 / 21 checks - stein2 headless, e2e 39+40: ALL PASSED, 100 checks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4194f3e150 |
Share a link that plays the game without the editor (#266)
A project could only be played inside the editor, behind the login.
To show a game to someone else there was no way short of an account.
A release freezes the saved project under a random token and serves
it on a page that holds nothing but the game view.
- Menu -> Release... opens a dialog with the state of the release,
the link with Copy link and Open, Publish or Update release, and
Take down behind a confirmation.
- Publish saves first and refuses while anything is unsaved, like
snapshots. Updating keeps the link. Take down kills it, and a new
Publish hands out a new token.
- The link is play.html?game=<32 hex>. The page needs no session,
paints Theme.colors.background, zooms with Auto and waits for
"Click to play" so that sound and keyboard focus are allowed.
- The game always starts in the start scene. Persistent variables
are stored per link in the browser. Plugins are not loaded, and the
dialog warns about them and about a project without a scene.
- GET ?r=releases/{token} is the only route besides auth/* that works
without a login. The public answer carries the token as project.id,
so the project id stays hidden. Release files are written with 0640
and nginx does not serve them directly (measured 403).
- Starting, the frame and Load scene moved into runtime/GameRun.ts.
Play in the editor and the play page run through the same code.
- WorldViewport moved to src/viewport/ and no longer needs the
EditorState. Pointer forwarding (gamePointer.ts) and setting up
textures, fonts and sounds (projectFiles.ts) exist only once.
- Vite builds two pages. The play page loads 4 kB of its own code
plus the shared chunk (Pixi, runtime, drawing, 653 kB) and Rapier,
without the editor.
Found on the way, not fixed here: data/projects/<id>.json answers 200
without a login because the files are 0644.
Tests:
- ./check.sh: 194 files, 2808 tests, exit 0.
- tests/php/releases.test.php: 20 checks, also added to CI.
- New e2e module 60 with 10 checks, played in a browser without a
session. Module 46 counts the menu entries and was updated.
- Full e2e run: 1572 checks passed.
- Counter-checks: 3 unit, 2 PHP and 3 browser mutations all fail.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
94749b4f3e |
Let a project keep named snapshots and restore them (#231)
Autosave only keeps the latest revision. Before a risky change there
was no way to put a known good state aside and go back to it later.
The main menu now has "Snapshots..." to create, restore and delete
named copies of the open project.
- Server: SnapshotStore.php keeps each snapshot as a copy of the
project JSON under data/snapshots/<project>/ (git-ignored). Four
routes under projects/{id}/snapshots use the same owner check as the
project, so an admin also sees foreign snapshots.
- Create writes the autosave first. With unsaved edits (play with open
edits, failed save, conflict) no snapshot is made and a message says
why. The rule is the pure function in src/editor/snapshots.ts.
- An empty name falls back to the local date and time.
- Restore asks first, then keeps the current state as "Before
restoring <name>". It writes the snapshot back as a new revision and
reloads the project, so the undo list is empty. A restore can itself
be undone by restoring that snapshot.
- Deleting a project deletes its snapshots too. Images, sounds, fonts
and pixel art are content-addressed and never deleted, so a snapshot
can always reach them.
- Client: SnapshotStore and HttpSnapshotStore in src/core/store, the
SnapshotsDialog, and the flows in ProjectSession. A stale revision
(409) becomes StaleRevisionError.
- CI runs the new PHP test in the gate job next to accounts.
Not covered by e2e: the lock during play and the conflict case. Both
are unit tests only.
Tests:
- check.sh: 164 files, 2401 tests, CHECK EXIT 0.
- tests/php/snapshots.test.php: 14 checks, all passed.
- tests/editor/snapshots.test.ts: 5 tests for the time format, the
blocker rule, the routes and 409.
- New e2e module 50 on a throwaway project: create, rename, restore,
undo the restore, delete, then delete the project and get 404 on
its snapshots. 46b expects the new menu entry. e2e 46,50: 20 checks
passed. The check sum goes from 1385 to 1393 (computed).
- Counter-checks, originals restored and compared with cmp: blocker
always allowed fails 1 unit test. No sorting fails 2 PHP checks.
Restore without keeping the old state fails 50c and aborts 50d.
- The first sort test with 2 snapshots passed by chance half the time
because of random ids. It now uses 8.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
ceaa44e5b8 |
Add roles and a user management tab for admins (#180, #179)
Until now every account could do the same, and managing accounts meant running make-user.php on the server. Accounts now carry a role, and admins get a tab in the editor to create, rename, re-role, reset and delete accounts. Both issues share the same server files, so they land in one commit. #180 Roles: - Every account is admin or user. A missing or unknown role counts as user, on the server and in the client. - auth/session and auth/login return {user, role}. - Auth::requireAdmin() answers everyone else with 403. - make-user.php takes the role as a third argument. Without it an existing account keeps its role, so a password reset from the CLI never demotes an admin. - Admins see and save other users' projects like their own. Saving keeps the original owner. #179 User management: - The account menu gets "User management" (admins only) and "Plugins" (everyone). Both open the same closable tab, accounts on top and plugins below. The fixed Plugins tab is gone. - Per account: Rename, Role, Password (no old password needed) and Delete with a confirmation. "New user..." creates one. - Each account lists its projects with an Open button. - Delete is refused while the account still owns projects. - Renaming moves the projects along and ends every session of the account. transfer takes the same lock as save. - On their own row an admin can only set the password. The last admin cannot be demoted or deleted. The server enforces both. - The account rules live in AccountRules.php and accountRules.ts as pure functions, so they are testable without a server. Findings: - At 1280 px the Delete button reached past the column edge and was not clickable. The name column is flexible now, and module 49 checks the layout. - The server lets an admin delete other users' projects, but the editor has no button for it yet. Left open in the issue. Tests: - ./check.sh: 148 files, 2214 tests, exit 0 (was 147 / 2204). - New tests/php/accounts.test.php, 51 checks, plain PHP. CI runs it as its own step in the gate job, the host has no PHP. - New e2e module 49 with 18 checks. CI creates the e2e-admin account in serve.sh. Modules 14, 38, 46 and the scaffold follow the new tab. - e2e 1-16,37,38,45,46,49: all passed, 581 checks. - Counter-checks: owner on save, admin view, default role and self delete in PHP fail 7, 5, 5 and 1 checks. Unchecked requireAdmin, a wider column and the caller as owner each fail exactly their e2e check. - Check sum 1314 -> 1333 (+1 in 38, +18 in 49), computed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
15bdfdf07a |
A gate that stands in front of the suite delays the news it carries, so it runs beside it (#94)
The workflow ran everything in one job: check.sh, then build, then the e2e suite and the smokes. The runner has two job slots and four cores, so the second slot lay idle for the whole run, and a lint error was reported only after the full suite had passed in front of it - six minutes instead of one. Now `gate` and `suite` are two jobs without `needs:`. They start together, both have to pass. The price is contention: while the gate runs, vitest and chromium share four cores, and the suite measures text widths and frame counts, which a loaded machine reports differently. The gate therefore caps vitest at two workers via GM_TEST_WORKERS, so two cores stay free for the browser over the whole overlap. Locally the variable is unset and nothing changes. Measured before the push: the cap costs vitest 4.4s (16.6s -> 21.0s), check.sh exits 0 with it, build ok. Whether the split is worth it is a question for the runner - the expected net gain is about 50s, and the acceptance is a measurement over at least two runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
4f0908df77 |
Run the gate, the editor suite and the three games on the Gitea runner
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> |