Drupal https://brookemahoney.com/ en Testing with DDev, Gitlab, and serving Drupal from a subfolder instead of a subdomain https://brookemahoney.com/blog/testing-ddev-gitlab-and-serving-drupal-subfolder-instead-subdomain <span class="field field--name-title field--type-string field--label-hidden">Testing with DDev, Gitlab, and serving Drupal from a subfolder instead of a subdomain</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>While working on the Easy Breadcrumb module for Drupal, I came across a situation where a test was failling on Gitlab but was passing with DDev: <a href="https://www.drupal.org/project/easy_breadcrumb/issues/3615550">https://www.drupal.org/project/easy_breadcrumb/issues/3615550</a></p><p>The difference that mattered was that Gitlab serves the site from <em>http://localhost/web</em> for testing and locally it gets served from a fully qualified domain name, ie. <em>http://ddev.site.example.com</em>.</p><h2>Getting the test to fail locally</h2><h3>Using firecow/gitlab-ci-local</h3><p>To get the test to fail locally, I used the suggestions at <a href="https://project.pages.drupalcode.org/gitlab_templates/info/test-locally/">https://project.pages.drupalcode.org/gitlab_templates/info/test-locally/</a> , which suggested <a href="https://github.com/firecow/gitlab-ci-local">firecow/gitlab-ci-local</a> . I did get that working but I ran into a hitch. My work computer is a Mac with an ARM64 chip and gitlab-ci-local tries to install <em>selenium/standalone-chrome:127.0</em>, which doesn't support ARM64. I dug around and figured out that I could use <em>selenium/standalone-chromium:latest</em> instead by adding a few lines in <em>.gitlab-ci.yml:</em></p><pre><code class="language-plaintext">phpunit: services: - !reference [.with-database] - name: selenium/standalone-chromium:latest alias: selenium # The lines below are to filter which tests run. In this case, only tests in the # "redirect" group. variables: _PHPUNIT_TESTGROUPS: "redirect"</code></pre><p>Then, on the command line, to just run PHPUnit and not most of the other steps, I used the --stage flag to just run jobs in the test stage, which by default is just PHPUnit:</p><pre><code class="language-bash">$ drupal-ci-local --stage=test</code></pre><p>That worked and I was able to reproduce locally. But, it took about a minute to run the test instead of 2 or 3 seconds with DDev.</p><h3>Using DDEV to serve a Drupal site from a subdirectory instead of a subdomain</h3><p>This way is not perfect, but it worked well enough for me to use Xdebug when running tests and when browing the site in a browser.</p><p>The code below results in the site being served from a subdirectory named <em>easy</em>, ie. <em>http://example.com/easy</em>.</p><p>First, cd to root of project, then:</p><pre><code class="language-bash">mkdir router ls -s ./web ./router/easy</code></pre><p>Then, in .<em>ddev/config.yaml</em></p><pre><code class="language-plaintext">docroot: router</code></pre><p>Next, in <em>settings.php</em></p><pre><code class="language-php">if (isset($GLOBALS['request'])) { $request = $GLOBALS['request']; $script_name = $request-&gt;server-&gt;get('SCRIPT_NAME'); if ($script_name === '/easy/index.php' || $script_name === '/index.php') { $request-&gt;server-&gt;set('SCRIPT_NAME', '/easy/index.php'); } }</code></pre><p>Then, in .<em>ddev/nginx_full/nginx-site.conf</em>, replace the section that starts with 'location /' to be like this instead:</p><pre><code class="language-plaintext"> # 1. CSS/JS caches location ~* ^/easy/sites/.*/files/(css|js)/ { try_files $uri @rewrite; expires max; log_not_found off; } # 2. Image styles location ~* ^/easy/sites/.*/files/styles/ { try_files $uri @rewrite; } # 3. Clean URLs location /easy { try_files $uri $uri/ /easy/index.php?$query_string; } # 4. Fallback location @rewrite { rewrite ^/easy/(.*)$ /easy/index.php?$query_string; }</code></pre><p>To run phpunit tests, pass in SIMPLETEST_BASE_URL.<br>Example which just runs ones test:</p><pre><code class="language-plaintext">ddev exec SIMPLETEST_BASE_URL=http://localhost/easy vendor/bin/phpunit --bootstrap web/core/tests/bootstrap.php --filter testEasyBreadcrumbFollowRedirects web/modules/custom/easy_breadcrumb </code></pre><p>&nbsp;</p></div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>brooke</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2026-08-10T11:42:10-07:00" title="Monday, 10 August 2026 - 11:42" class="datetime">Mon, 10 Aug 2026 - 11:42</time> </span> Mon, 10 Aug 2026 18:42:10 +0000 brooke 148 at https://brookemahoney.com Bash scripts for Drupal, DDEV, and Tome https://brookemahoney.com/blog/bash-scripts-drupal-ddev-and-tome <span class="field field--name-title field--type-string field--label-hidden">Bash scripts for Drupal, DDEV, and Tome</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>This website is made with <a href="https://drupal.org">Drupal</a>. Local development is done with <a href="https://ddev.com/">DDEV</a> configured to use Orbstack for container management. The <a href="https://tome.fyi/">Tome</a> Drupal module exports the dynamic site to a static site. Python is used to preview the site locally. Public hosting is provided free by Github.</p><p>Here are some custom bash aliases and functions I use to make common local tasks easy. <a href="https://www.npmjs.com/package/concurrently">Concurrently</a> is used to run two processes in one terminal session.</p><pre><code class="language-bash language-plaintext">alias brookemahoneycomCd='cd ~/Sites/brookemahoneycom' brookemahoneycomLaunch () { # Starts Orbstack if it isn't running. orb brookemahoneycomCd cd drupal ddev launch } brookemahoneycomPreview () { brookemahoneycomCd cd docs concurrently 'python -m http.server' 'open "http://localhost:8000"' } brookemahoneycomBuild() { # Starts Orbstack if it isn't running. orb # Changes to the drupal directory. cd ~/Sites/brookemahoneycom/drupal # Clears caches. ddev drush cr # Exports the site with Tome. ddev drush tome:static --uri=https://brookemahoney.com # Removes old docs directory. rm -rf ~/Sites/brookemahoneycom/docs # Copies the Tome build directory to docs for Github hosting. cp -R ~/Sites/brookemahoneycom/drupal/html ~/Sites/brookemahoneycom/docs # Copies over static files, such as CNAME for Github hosting. cp -R ~/projects/brookemahoneycom/sync/ ~/Sites/brookemahoneycom/docs } </code></pre><p>All the code for the Drupal install is in <a href="https://github.com/brookemahoney/brookmahoneycom">this site's Github repo</a>.</p></div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span>brooke</span></span> <span class="field field--name-created field--type-created field--label-hidden"><time datetime="2025-09-17T13:46:57-07:00" title="Wednesday, 17 September 2025 - 13:46" class="datetime">Wed, 17 Sep 2025 - 13:46</time> </span> Wed, 17 Sep 2025 20:46:57 +0000 brooke 11 at https://brookemahoney.com