Repository navigation
4.18.0
What's new since 4.17.0
Breaking changes
-
[#499] Fixed Drupal 10 static analysis rejecting PHPUnit attribute classes. @AlexSkrypnyk (#501)
Drupal 10 builds failedmake lintwith nine PHPStanattribute.notFounderrors, becausePHPUnit\Framework\Attributes\*first exists in PHPUnit 10 and Drupal 10 resolves PHPUnit 9.6 with no path to a newer one. The fix scopes a PHPStan ignore to those attribute classes and splits linting into a per-Drupal-major matrix, which renames the GitHub Actions check fromlinttolint-d10andlint-d11. Iflintis a required status check in branch protection, replace it with both new job names, or the rule will wait forever on a check that no longer runs. -
[#339] Unified 'chromedriver-*' and 'selenium-*' commands into 'browser-start' and 'browser-stop'. @AlexSkrypnyk (#462)
The four backend-specific commandschromedriver-start,chromedriver-stop,selenium-startandselenium-stopare gone from bothmakeandahoy, replaced bybrowser-startandbrowser-stop, which pick the backend fromWEBDRIVER_BACKENDand own the Selenium Docker handling that was previously inlined as shell in both runners. Replace any scripted call to the four old names withbrowser-start/browser-stop; the backend is now chosen by the environment variable rather than by the command you type. -
[#339] Made local Chrome via 'chromedriver' the default WebDriver backend for FunctionalJavascript tests. @AlexSkrypnyk (#460)
FunctionalJavascript tests previously required the Docker Selenium container every time; the default backend is now the locally installed Chrome, driven by a version-matchedchromedriver, so a local run needs no Docker and the endpoint port is auto-discovered from 4444 and persisted to.envso several projects can test at once. To keep the container, setWEBDRIVER_BACKEND=selenium- the shipped GitHub Actions and CircleCI configurations already pin it, so only local runs and consumer-authored pipelines change. -
[#395] Dropped PHP 8.2 support and raised the minimum to 8.3. @AlexSkrypnyk (#455)
Thecomposer.jsonfloor moves from>=8.2to>=8.3, with the PHPCStestVersion, the Rector PHP set, the CircleCI default image and the CI matrix all following, so the tested matrix is now PHP 8.3, 8.4 and 8.5. PHP 8.2 is security-support-only upstream and already sat below Drupal 11's own minimum, so move any 8.2 environment to 8.3 or newer before upgrading.
Highlights
-
[#509] Deployed the commit that CI tested instead of the default branch. @AlexSkrypnyk (#512)
The deploy workflow triggers onworkflow_runand checked out without pinning a ref, so it force-pushed the tip of the default branch to a destination branch named after the triggering run - the name and the content described different commits. The checkout is now pinned to the triggering run's head SHA, so a release tag deploys the tagged commit CI actually tested, and the job is gated on same-repository push events so no tree this repository did not produce can reach the deployment key. -
[#506] Stripped the scaffold example extension on update and stopped discarding project lifecycle scripts. @AlexSkrypnyk (#507)
The update procedure wiped the project root and restored onlysrc/,tests/andconfig/, so a project's ownassemble-*.sh/provision-*.sh/start-*.sh/stop-*.shhooks were destroyed on every scaffold update -scripts/is now restored with the rest. A new step also deletes the bundled example extension thatinit.phphad merely renamed, guarded so a file goes only when it is both untracked and on the enumerated example list, leaving anything git already tracks untouched. -
[#432] Added an opt-in login-link QR code and a Cloudflare init opt-out. @AlexSkrypnyk (#459)
make loginandahoy logincan render the one-time login link as a terminal QR code, so it can be scanned straight from a phone instead of retyped; nothing is drawn unless you opt in andqrencodeis installed.init.phpalso gains a Cloudflare tunnel opt-out prompt, so declining strips thescripts/*-cloudflared.shhooks while the tunnel-agnosticTUNNEL_URLhandling stays for ngrok, Tailscale or anything similar. -
[#456] Suppressed verbose '.devtools' command output unless DEBUG is set. @AlexSkrypnyk (#458)
A normalahoy buildprinted around 540 lines, almost all of it Composer, npm and Drush noise. Tool output is now captured and echoed only when the command fails, dropping a build to roughly 60 clean[TASK]/[ OK ]lines, while your own front-end build andscripts/*lifecycle hooks stay visible because they are meaningful rather than noise. SetDEBUG=1to stream everything live again. -
[#384] Made PHPStan config compatible with Drupal.org CI. @AlexSkrypnyk (#453)
Drupal.org's GitLab CI analyses from insideweb/modules/custom/<module>/, a working directory where the scaffold's path-scopedignoreErrorsentry never matched, so every legitimate suppression was skipped and surfaced as a failure. Dropping that path scope lets generated extensions pass PHPStan on Drupal.org CI, and the README documents the one override a consumer needs when wiring up their own.gitlab-ci.yml:_PHPUNIT_EXTRA: '--no-coverage'. -
[#431] Added start/stop lifecycle hooks and Cloudflare tunnel support. @AlexSkrypnyk (#454)
Lifecycle hooks now cover all four phases:scripts/start-*.shruns after the server starts andscripts/stop-*.shbefore it stops, joining the existing assemble and provision hooks. A newresolve_site_url()helper prefers aTUNNEL_URLread from.envand falls back tohttp://host:port, so the local site can be exposed publicly through a tunnel - opt-in Cloudflare quick-tunnel hooks ship as a working reference, and the core stays generic enough for ngrok or Tailscale.
Other changes
-
[#511] Stopped 'login' re-inlining the 'drush' invocation in both wrappers. @AlexSkrypnyk (#515)
Thelogincommand re-inlined the Drush binary path and the site-URL resolution that thedrushcommand sitting directly above it already encapsulated, so the same invocation was written four times across the two wrappers - including a rawbuild/vendor/bin/drushcall in the very files that teach consumers to use the wrappers instead. Each wrapper now spells it once, andahoy drushforwards its arguments as"$@"rather than unquoted$*, so an argument containing spaces survives as one argument. -
[#510] Made the 'qrcode' command render on invocation and report a missing 'qrencode'. @AlexSkrypnyk (#513)
.devtools/qrcodewas documented on the command surface but printed nothing on a normal machine, because the opt-in gate lived inside the rendering helper and so silenced the deliberate caller along with the automatic one. Invoking the command now always renders, theloginwrappers keep their own gate under the renamedLOGIN_QRCODEvariable, and a missingqrencodebinary now fails with an install hint instead of returning silently. -
[#508] Fixed Selenium pinning port 4444 and 'MINK_DRIVER_ARGS_WEBDRIVER' overriding the environment. @AlexSkrypnyk (#514)
The Selenium backend pinned port 4444 and named its container the fixed stringselenium, so a second project'sdocker rm -fdestroyed the first project's still-running container. It now claims a free port from 4444 and names the containerselenium-<port>, matching what the chromedriver backend already did. Droppingforce="true"onMINK_DRIVER_ARGS_WEBDRIVERalso means a test that does not extend the shipped base class can export its own driver args. -
[#504] Migrated the deprecated 'version-resolver.default' field to a resolver category. @AlexSkrypnyk (#505)
Release Drafter v7 folded version resolution intocategoriesand warns on every run that the top-levelversion-resolverblock is deprecated. The configuration now declares an unconditionalversion-resolvercategory carrying theminorincrement, which contributes to the resolved version without rendering a heading, so the published notes stay byte-identical. Without it, the next draft would silently fall back to the built-inpatchdefault once the field is removed upstream - easy to miss, since drafts are created without human involvement. -
[#500] Fixed the deploy workflow clearing a valid branch name when a tag shares that name. @AlexSkrypnyk (#502)
The guard that blanks the head branch on a tag push tested whether a tag of that name existed anywhere in the repository, so pushing to a branch that happened to collide with an existing tag name deployed to the default branch instead of the intended one. It now matches by commit identity withgit tag --points-at, so the branch is cleared only when a tag of that name sits on the triggering commit; annotated tags are peeled, so both tag kinds are covered. -
[#492] Unified the spelling of 'JavaScript' across commands, tests and fixtures. @AlexSkrypnyk (#498)
Jsmeant two different things depending on context - Jest intest-js, and an abbreviation ofFunctionalJavascriptin class names such asYourExtensionSmokeJsTest. The language is now spelled out in full in every identifier, withtest-javascriptcanonical andtest-jskept as a working alias in both wrappers. Pinning Ahoy to 2.5.0 in CI along the way revived all nine declared aliases, which the previous 2.1.1 pin silently discarded because it predates alias support. -
[#493, #494] Documented missing '.devtools' entries and corrected PHPUnit README paths. @AlexSkrypnyk (#497)
.devtools/README.mddocumented only 6 of its 9 entries, omittingbrowser,infoandqrcode- all three reachable from the public command surface - andphpunit.xml/phpunit.d10.xmlpointed atcore/tests/README.md, a path that resolves only from the docroot and not frombuild/, where those configs actually run. Both are corrected, and a newDocumentationTestpins each invariant so neither can silently drift back. -
[#488] Resolved 'DEPLOY_BRANCH' from a repository variable and the default branch in the deploy workflow. @AlexSkrypnyk (#495)
DEPLOY_BRANCHwas computed from a self-reference to an env variable the workflow never defined, so it always resolved to an empty string and a configured deploy branch could never take effect on GitHub Actions, even though CircleCI already resolved it correctly. It now reads the optionalvars.DEPLOY_BRANCHrepository variable, with the head branch and the repository default branch as fallbacks, and a new test asserts every${{ env.X }}reference in the workflows resolves to a definition in the same file - a defect class neither yamllint, actionlint nor Zizmor catches. -
Converged naming, structure, API shape and comments across the scaffold. @AlexSkrypnyk (#474)
A convergence pass unifying naming, structure, API shape and source comments onto the forms the codebase already dominated, one class per commit. The substantive find:browser,infoandqrcodewere absent from every lint and analysis config while each of their peers was listed, and bringing them under PHPStan surfaced a real defect where the purity assumption onwebdriver_ready()made both readiness poll loops read as always false - now annotated@phpstan-impure. -
Update toshimaru/auto-author-assign action to v3.1.0 @renovate[bot] (#472)
-
Replaced versioned Drupal Rector sets with a composer-based provider and pinned rector/rector below 2.6.2 on Drupal 10 builds. @AlexSkrypnyk (#473)
rector/rector2.6.2 dropped the versionedPHPUnitSetList::PHPUNIT_*andTwigSetList::TWIG_*constants thatpalantirnet/drupal-rectorstill references, and since this template commits no lock file, CI resolved the new release on every run and Rector aborted before it analysed anything.rector.phpnow binds its sets to the installeddrupal/coreversion throughDrupalSetProvider, and Drupal 10 builds pinrector/rectorto^2 <2.6.2, where the old constants are still reachable. -
Update selenium/standalone-chromium:latest Docker digest to 1d3d834 @renovate[bot] (#471)
-
Update zizmorcore/zizmor-action action to v0.6.2 @renovate[bot] (#470)
-
Update release-drafter/release-drafter digest to 34d8067 @renovate[bot] (#468)
-
Update zizmorcore/zizmor-action action to v0.6.1 @renovate[bot] (#467)
-
Resolved the deferred consistency judgment calls from the previous convergence pass. @AlexSkrypnyk (#466)
Resolves the 15 judgment calls the previous pass deferred, across the example module's dependency injection,init.php's confirmation flags, the.devtoolsengine's shared helpers, and the Makefile's alignment with the ahoy runner. The behaviour-visible piece:passthru_or_fail()andpassthru_verbose_or_fail()masked a failing command's real exit code as1whenever a failure message was supplied, so a failing custom hook now propagates its true exit code. -
Converged the scaffold codebase onto its dominant naming, API, and structure conventions. @AlexSkrypnyk (#465)
The first convergence pass, taking the committed code as the source of truth rather than an external style guide: unified helper parameter names,assertSameat type-stable sites, data-provider rows keyed by parameter name,\Drupal::service()and\Drupal::configFactory()in the module hooks, and help text aligned between the two runners. Every change is behaviour-preserving, with the behaviour-changing and public-symbol calls itemised for a separate decision rather than folded in. -
Polished scaffold documentation and added a security policy. @AlexSkrypnyk (#464)
Reconciles README andCONTRIBUTING.dist.mddrift with the code - the Drupal version matrix, the PHPUnit bootstrap path, a stale Renovate example - and documents theDEBUG=1output toggle. Adds aSECURITY.mdpolicy covering supported versions and how to report a vulnerability, whichinit.phpremoves during init so generated projects define their own rather than inheriting the scaffold's. -
[#461] Added CONTRIBUTING.md and moved local development docs into it. @AlexSkrypnyk (#463)
The local-development, building, provisioning, XDebug, coding-standards and testing sections move verbatim out ofREADME.dist.mdinto a newCONTRIBUTING.dist.md, whichinit.phprenames toCONTRIBUTING.mdalongside the README, leaving a generated project's README as badges, features and a pointer. The scaffold also gains its own maintainer-facingCONTRIBUTING.mdcovering the.scaffold/layout, the p0-p5 self-tests and the snapshot regeneration procedure. -
[#229] Collected browser test output under the '.logs' directory. @AlexSkrypnyk (#457)
Drupal core hardcodes browser debug output toweb/sites/simpletest/browser_outputregardless of configuration, so per-request HTML dumps and JS screenshots landed outside the.logs/directory where JUnit results and coverage already collect. Provision now symlinks that hardcoded path into.logs/browser_output, so CI archives every test artifact from one bundle instead of two disconnected locations. -
Update actions/setup-node action to v7 @renovate[bot] (#448)
-
Update dependency prettier to ^3.9.6 @renovate[bot] (#452)
-
Update actions/checkout digest to 3d3c42e @renovate[bot] (#451)
-
Update all dependencies @renovate[bot] (#450)
-
Update zizmorcore/zizmor-action action to v0.6.0 @renovate[bot] (#449)
-
Update all dependencies @renovate[bot] (#447)
-
Update dependency prettier to ^3.9.4 @renovate[bot] (#446)
-
Update dependency prettier to ^3.9.3 @renovate[bot] (#445)
-
Update dependency prettier to ^3.9.1 @renovate[bot] (#444)
-
Update dependency prettier to ^3.9.0 @renovate[bot] (#443)
-
Update actions/cache digest to 55cc834 @renovate[bot] (#442)
-
Update dependency prettier to ^3.8.5 @renovate[bot] (#441)
-
Update release-drafter/release-drafter digest to 4d75298 @renovate[bot] (#440)
-
Update release-drafter/release-drafter digest to 73b95fa @renovate[bot] (#439)
-
Update all dependencies (major) @renovate[bot] (#438)
-
Update all dependencies @renovate[bot] (#437)
-
Update all dependencies to v0.5.7 @renovate[bot] (#436)
-
Update all dependencies to v7 @renovate[bot] (#435)
-
Update all dependencies to ed4bc48 @renovate[bot] (#434)
-
Update all dependencies to v3.0.3 @renovate[bot] (#433)
Full Changelog: 4.17.0...4.18.0