Skip to content

Harden the Hazelnut image and streamline environment commands - #2

Open
balintbrews wants to merge 1 commit into
mainfrom
hazelnut-env-improvements
Open

Harden the Hazelnut image and streamline environment commands#2
balintbrews wants to merge 1 commit into
mainfrom
hazelnut-env-improvements

Conversation

@balintbrews

Copy link
Copy Markdown
Owner

Hardens the Hazelnut image based on end-to-end testing in containers, and streamlines the environment commands.

Bugs found by testing, and their fixes

Bug Fix
Canvas tooling (its Composer scripts, cypress.config.js, @drupal-canvas/test-utils, @drupal/playwright) locates Drupal by walking up parent directories, which cannot work when the checkout lives outside the Drupal tree; composer run phpstan, Cypress config load, and Playwright fixtures all failed canvas-env-init now moves the checkout physically into web/modules/contrib/canvas and leaves a symlink at the workspace path (bind-mounted checkouts fall back to the old linking with a warning)
PATH put vendor/bin first, so after composer install PHPUnit's own binary shadowed the phpunit wrapper (same for phpcs, phpstan); the wrappers silently never ran Append vendor/bin to PATH instead of prepending
PHP's built-in server kept its launch directory as the working directory, breaking docroot-relative includes (canvas_headless's jsonapi_resources impostor classes made the editor return a 500) canvas-env-start now serves from the docroot
php -S is single-threaded by default, serializing asset requests PHP_CLI_SERVER_WORKERS=8
npm --prefix through the workspace symlink breaks npm's workspace resolution: it pruned 2,145 packages and rewrote package-lock.json All scripts run npm from inside the target directory
Cypress e2e needs BASE_URL and a Drupal core path, Playwright fixtures need the Drupal root, and e2e site installs need a database URL; none were set Bake BASE_URL, DRUPAL_ROOT_CORE, DRUPAL_TEST_DRUPAL_ROOT, and DB_URL into the image, plus php8.3-sqlite3 for SQLite-based flows
site-install --ui followed by ui failed on a fresh checkout because npm dependencies were never installed in that flow ui installs dependencies when node_modules is absent

Improvements

  • Cypress binary and Playwright Chromium are baked into the image (/opt/cypress-cache, /opt/ms-playwright), pinned with build arguments that mirror what the Canvas repository resolves. The commands assume they are available; no downloads at runtime.
  • VNC bridge: canvas-env-start runs Xvfb, fluxbox, x11vnc, and noVNC (port 6080), mirroring the DDEV setup. cypress --open and playwright --headed sessions can be watched at http://localhost:6080/vnc.html.
  • Reconciled with composer.json: the image ships both pre-install-cmd hook scripts (check-repo.sh, plus a no-op check-repo-mercury.sh), so the image's composer.json stays byte-identical to the repository root copy and the build-time jq rewrite is gone.
  • bin/ cleanup: n removed; playwright is now a thin passthrough to playwright test; cypress gained --open for VNC sessions and dismisses the first-run welcome screen; phpcs/phpstan invoke the environment root's binaries directly with Canvas's configuration; site-install lost dead code (vendor/bin/dr).
  • npm and Turborepo quality of life: telemetry, fund, and update-notifier noise disabled.
  • AGENTS.md added to the build context, written for agents working inside the container.

Verified in containers

  • Image builds; MariaDB, the Xvfb/x11vnc/noVNC stack, and the web server start; the site is reachable, and the Canvas editor loads and works with built assets and via the Vite dev server (canvas_vite + ui), checked in a real browser.
  • composer install with both hook scripts; Drush 13.7 (status, uli, cr, php:eval).
  • site-install, site-install --stark, and site-install --ui.
  • PHPUnit unit and kernel tests, PHPStan, and PHPCBF via the wrappers.
  • Playwright canary spec passes in-container with the baked Chromium (test-site install, login, page creation, aria snapshot).
  • Cypress with the baked binary: config loads, Electron launches, the component-testing Vite server starts. The specs themselves pass natively (7/7 component tests; full runs in an emulated container are impractical, see notes).
  • Turborepo: all 9 packages build, lint (36 tasks) and package tests pass; container rebuilds hit the cache (FULL TURBO), and cache artifacts are portable between host and container when the VITE_* environment matches.
  • All monorepo workspaces require Node.js >=22.19.0 <23 || >=24.5.0; the image's Node 24 satisfies every workspace.

Notes

  • On Apple Silicon, Docker's Rosetta runs Node with the V8 JIT disabled (node --no-opt). The UI build that takes ~12 seconds natively takes ~45 minutes emulated, and JS-bundling-heavy steps (Cypress runs) are similarly affected. This is a local-testing caveat on Mac hosts, not an image issue; a native arm64 image variant would remove it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01B8Mgvp7U1cs88rTE5dvPEH

Tested end to end in containers: Drupal install, Drush, PHPUnit unit and
kernel tests, PHPStan, PHPCBF, Playwright, Cypress, the Canvas editor with
built assets and via the Vite dev server (canvas_vite), Turborepo builds
with cache reuse, and the VNC bridge.

- Move the Canvas checkout physically into web/modules/contrib/canvas and
  leave a symlink at the workspace path. Canvas tooling (its Composer
  scripts, cypress.config.js, @drupal-canvas/test-utils, and
  @drupal/playwright) locates Drupal by walking up parent directories,
  which cannot work from a checkout outside the Drupal tree.
- Append vendor/bin to PATH instead of prepending, so the phpunit, phpcs,
  and phpstan wrappers are not shadowed after composer install.
- Serve the site from the docroot: PHP's built-in server keeps its launch
  working directory, which broke docroot-relative includes such as
  canvas_headless's jsonapi_resources impostor classes.
- Run PHP_CLI_SERVER_WORKERS=8; the single-threaded default serialized
  asset requests.
- Run npm from inside the workspace root; npm --prefix through the
  workspace symlink breaks npm's workspace resolution and prunes packages.
- Bake the Cypress binary and Playwright Chromium into the image, pinned
  via build arguments.
- Add a VNC bridge (Xvfb, fluxbox, x11vnc, noVNC on port 6080) started by
  canvas-env-start, mirroring the DDEV setup.
- Rewrite the phpcs and phpstan wrappers to invoke the environment root's
  binaries directly with Canvas's configuration.
- Remove the n wrapper; use npm from the target directories directly.
- Ship both pre-install-cmd hook scripts so composer.json stays
  byte-identical to the repository root copy, replacing the jq rewrite.
- Set BASE_URL, DB_URL, DRUPAL_ROOT_CORE, and DRUPAL_TEST_DRUPAL_ROOT for
  the Cypress and Playwright configurations, and add PHP's SQLite driver.
- Make ui install npm dependencies when they are absent, so the
  site-install --ui flow works on a fresh checkout.
- Add an AGENTS.md for agents working inside the container.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B8Mgvp7U1cs88rTE5dvPEH
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant