From a99ebe043164f622c5b69dab627f7dc0290d7713 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Thu, 7 May 2026 13:35:05 +1000 Subject: [PATCH 01/12] move to ddev - init --- .ddev/config.yaml | 312 ++++++++++++++++++++++++++++++++++++++++++++++ .editorconfig | 17 ++- .gitattributes | 77 ++++++++++-- 3 files changed, 392 insertions(+), 14 deletions(-) create mode 100644 .ddev/config.yaml diff --git a/.ddev/config.yaml b/.ddev/config.yaml new file mode 100644 index 000000000..eb025a134 --- /dev/null +++ b/.ddev/config.yaml @@ -0,0 +1,312 @@ +name: tide-core +type: drupal10 +docroot: docroot +php_version: "8.3" +webserver_type: nginx-fpm +xdebug_enabled: false +additional_hostnames: [] +additional_fqdns: [] +database: + type: mariadb + version: "10.6" +use_dns_when_possible: true +composer_version: "2" +router_http_port: "8080" +router_https_port: "8443" +web_environment: + - DRUPAL_MODULE_PREFIX= +corepack_enable: false + +hooks: + post-import-db: + - exec: drush cache:rebuild + - exec: drush updatedb -y + - exec: drush cache:rebuild + +# Key features of DDEV's config.yaml: + +# name: # Name of the project, automatically provides +# http://projectname.ddev.site and https://projectname.ddev.site +# If the name is omitted, the project will take the name of the enclosing directory, +# which is useful if you want to have a copy of the project side by side with this one. + +# type: # backdrop, cakephp, craftcms, drupal, drupal6, drupal7, drupal8, drupal9, drupal10, drupal11, generic, laravel, magento, magento2, php, shopware6, silverstripe, symfony, typo3, wordpress +# See https://ddev.readthedocs.io/en/stable/users/quickstart/ for more +# information on the different project types + +# docroot: # Relative path to the directory containing index.php. + +# php_version: "8.3" # PHP version to use, "5.6" through "8.4" + +# You can explicitly specify the webimage but this +# is not recommended, as the images are often closely tied to DDEV's' behavior, +# so this can break upgrades. + +# webimage: # nginx/php docker image. + +# database: +# type: # mysql, mariadb, postgres +# version: # database version, like "10.11" or "8.0" +# MariaDB versions can be 5.5-10.8, 10.11, and 11.4. +# MySQL versions can be 5.5-8.0. +# PostgreSQL versions can be 9-17. + +# router_http_port: # Port to be used for http (defaults to global configuration, usually 80) +# router_https_port: # Port for https (defaults to global configuration, usually 443) + +# xdebug_enabled: false # Set to true to enable Xdebug and "ddev start" or "ddev restart" +# Note that for most people the commands +# "ddev xdebug" to enable Xdebug and "ddev xdebug off" to disable it work better, +# as leaving Xdebug enabled all the time is a big performance hit. + +# xhgui_https_port: 8142 +# Can be used to change the router https port for xhgui application +# Very rarely used + +# xhgui_http_port: 8143 +# Can be used to change the router http port for xhgui application +# Very rarely used + +# host_xhgui_port: 8142 +# Can be used to change the host binding port of the xhgui +# application. Rarely used; only when port conflict and +# bind_all_ports is used (normally with router disabled) + +# xhprof_enabled: false # Set to true to enable Xhprof and "ddev start" or "ddev restart" +# Note that for most people the commands +# "ddev xhprof" to enable Xhprof and "ddev xhprof off" to disable it work better, +# as leaving Xhprof enabled all the time is a big performance hit. + +# xhprof_mode: [prepend|xhgui|global] +# Set to "xhgui" to enable XHGui features +# "xhgui" will become default in a future major release + +# webserver_type: nginx-fpm, apache-fpm, generic + +# timezone: Europe/Berlin +# If timezone is unset, DDEV will attempt to derive it from the host system timezone +# using the $TZ environment variable or the /etc/localtime symlink. +# This is the timezone used in the containers and by PHP; +# it can be set to any valid timezone, +# see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +# For example Europe/Dublin or MST7MDT + +# composer_root: +# Relative path to the Composer root directory from the project root. This is +# the directory which contains the composer.json and where all Composer related +# commands are executed. + +# composer_version: "2" +# You can set it to "" or "2" (default) for Composer v2 or "1" for Composer v1 +# to use the latest major version available at the time your container is built. +# It is also possible to use each other Composer version channel. This includes: +# - 2.2 (latest Composer LTS version) +# - stable +# - preview +# - snapshot +# Alternatively, an explicit Composer version may be specified, for example "2.2.18". +# To reinstall Composer after the image was built, run "ddev debug rebuild". + +# nodejs_version: "22" +# change from the default system Node.js version to any other version. +# See https://ddev.readthedocs.io/en/stable/users/configuration/config/#nodejs_version for more information +# and https://www.npmjs.com/package/n#specifying-nodejs-versions for the full documentation, +# Note that using of 'ddev nvm' is discouraged because "nodejs_version" is much easier to use, +# can specify any version, and is more robust than using 'nvm'. + +# corepack_enable: false +# Change to 'true' to 'corepack enable' and gain access to latest versions of yarn/pnpm + +# additional_hostnames: +# - somename +# - someothername +# would provide http and https URLs for "somename.ddev.site" +# and "someothername.ddev.site". + +# additional_fqdns: +# - example.com +# - sub1.example.com +# would provide http and https URLs for "example.com" and "sub1.example.com" +# Please take care with this because it can cause great confusion. + +# upload_dirs: "custom/upload/dir" +# +# upload_dirs: +# - custom/upload/dir +# - ../private +# +# would set the destination paths for ddev import-files to /custom/upload/dir +# When Mutagen is enabled this path is bind-mounted so that all the files +# in the upload_dirs don't have to be synced into Mutagen. + +# disable_upload_dirs_warning: false +# If true, turns off the normal warning that says +# "You have Mutagen enabled and your 'php' project type doesn't have upload_dirs set" + +# ddev_version_constraint: "" +# Example: +# ddev_version_constraint: ">= 1.22.4" +# This will enforce that the running ddev version is within this constraint. +# See https://github.com/Masterminds/semver#checking-version-constraints for +# supported constraint formats + +# working_dir: +# web: /var/www/html +# db: /home +# would set the default working directory for the web and db services. +# These values specify the destination directory for ddev ssh and the +# directory in which commands passed into ddev exec are run. + +# omit_containers: [db, ddev-ssh-agent] +# Currently only these containers are supported. Some containers can also be +# omitted globally in the ~/.ddev/global_config.yaml. Note that if you omit +# the "db" container, several standard features of DDEV that access the +# database container will be unusable. In the global configuration it is also +# possible to omit ddev-router, but not here. + +# performance_mode: "global" +# DDEV offers performance optimization strategies to improve the filesystem +# performance depending on your host system. Should be configured globally. +# +# If set, will override the global config. Possible values are: +# - "global": uses the value from the global config. +# - "none": disables performance optimization for this project. +# - "mutagen": enables Mutagen for this project. +# - "nfs": enables NFS for this project. +# +# See https://ddev.readthedocs.io/en/stable/users/install/performance/#nfs +# See https://ddev.readthedocs.io/en/stable/users/install/performance/#mutagen + +# fail_on_hook_fail: False +# Decide whether 'ddev start' should be interrupted by a failing hook + +# host_https_port: "59002" +# The host port binding for https can be explicitly specified. It is +# dynamic unless otherwise specified. +# This is not used by most people, most people use the *router* instead +# of the localhost port. + +# host_webserver_port: "59001" +# The host port binding for the ddev-webserver can be explicitly specified. It is +# dynamic unless otherwise specified. +# This is not used by most people, most people use the *router* instead +# of the localhost port. + +# host_db_port: "59002" +# The host port binding for the ddev-dbserver can be explicitly specified. It is dynamic +# unless explicitly specified. + +# mailpit_http_port: "8025" +# mailpit_https_port: "8026" +# The Mailpit ports can be changed from the default 8025 and 8026 + +# host_mailpit_port: "8025" +# The mailpit port is not normally bound on the host at all, instead being routed +# through ddev-router, but it can be bound directly to localhost if specified here. + +# webimage_extra_packages: [php7.4-tidy, php-bcmath] +# Extra Debian packages that are needed in the webimage can be added here + +# dbimage_extra_packages: [telnet,netcat] +# Extra Debian packages that are needed in the dbimage can be added here + +# use_dns_when_possible: true +# If the host has internet access and the domain configured can +# successfully be looked up, DNS will be used for hostname resolution +# instead of editing /etc/hosts +# Defaults to true + +# project_tld: ddev.site +# The top-level domain used for project URLs +# The default "ddev.site" allows DNS lookup via a wildcard +# If you prefer you can change this to "ddev.local" to preserve +# pre-v1.9 behavior. + +# ngrok_args: --basic-auth username:pass1234 +# Provide extra flags to the "ngrok http" command, see +# https://ngrok.com/docs/ngrok-agent/config or run "ngrok http -h" + +# disable_settings_management: false +# If true, DDEV will not create CMS-specific settings files like +# Drupal's settings.php/settings.ddev.php or TYPO3's additional.php +# In this case the user must provide all such settings. + +# You can inject environment variables into the web container with: +# web_environment: +# - SOMEENV=somevalue +# - SOMEOTHERENV=someothervalue + +# no_project_mount: false +# (Experimental) If true, DDEV will not mount the project into the web container; +# the user is responsible for mounting it manually or via a script. +# This is to enable experimentation with alternate file mounting strategies. +# For advanced users only! + +# bind_all_interfaces: false +# If true, host ports will be bound on all network interfaces, +# not the localhost interface only. This means that ports +# will be available on the local network if the host firewall +# allows it. + +# default_container_timeout: 120 +# The default time that DDEV waits for all containers to become ready can be increased from +# the default 120. This helps in importing huge databases, for example. + +#web_extra_exposed_ports: +#- name: nodejs +# container_port: 3000 +# http_port: 2999 +# https_port: 3000 +#- name: something +# container_port: 4000 +# https_port: 4000 +# http_port: 3999 +# Allows a set of extra ports to be exposed via ddev-router +# Fill in all three fields even if you don’t intend to use the https_port! +# If you don’t add https_port, then it defaults to 0 and ddev-router will fail to start. +# +# The port behavior on the ddev-webserver must be arranged separately, for example +# using web_extra_daemons. +# For example, with a web app on port 3000 inside the container, this config would +# expose that web app on https://.ddev.site:9999 and http://.ddev.site:9998 +# web_extra_exposed_ports: +# - name: myapp +# container_port: 3000 +# http_port: 9998 +# https_port: 9999 + +#web_extra_daemons: +#- name: "http-1" +# command: "/var/www/html/node_modules/.bin/http-server -p 3000" +# directory: /var/www/html +#- name: "http-2" +# command: "/var/www/html/node_modules/.bin/http-server /var/www/html/sub -p 3000" +# directory: /var/www/html + +# override_config: false +# By default, config.*.yaml files are *merged* into the configuration +# But this means that some things can't be overridden +# For example, if you have 'use_dns_when_possible: true'' you can't override it with a merge +# and you can't erase existing hooks or all environment variables. +# However, with "override_config: true" in a particular config.*.yaml file, +# 'use_dns_when_possible: false' can override the existing values, and +# hooks: +# post-start: [] +# or +# web_environment: [] +# or +# additional_hostnames: [] +# can have their intended affect. 'override_config' affects only behavior of the +# config.*.yaml file it exists in. + +# Many DDEV commands can be extended to run tasks before or after the +# DDEV command is executed, for example "post-start", "post-import-db", +# "pre-composer", "post-composer" +# See https://ddev.readthedocs.io/en/stable/users/extend/custom-commands/ for more +# information on the commands that can be extended and the tasks you can define +# for them. Example: +#hooks: +# post-import-db: +# - exec: drush sql:sanitize +# - exec: drush updatedb +# - exec: drush cache:rebuild diff --git a/.editorconfig b/.editorconfig index d97fcd755..686c443ce 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,2 +1,17 @@ -[composer.{json,lock,dev.json}] +# Drupal editor configuration normalization +# @see http://editorconfig.org/ + +# This is the top-most .editorconfig file; do not search in parent directories. +root = true + +# All files. +[*] +end_of_line = LF +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[composer.{json,lock}] indent_size = 4 diff --git a/.gitattributes b/.gitattributes index fb375e1bd..e7b792f84 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,13 +1,64 @@ -# Ignore files for distribution archives. -.gitattributes export-ignore -.gitignore export-ignore -.github export-ignore -.circleci export-ignore -.circleci/config.yml export-ignore -.env export-ignore -dev-init.sh export-ignore - -# linguist configuration for syntax highlighting in github UI. -*.module linguist-language=PHP -*.install linguist-language=PHP -*.inc linguist-language=PHP +# Drupal git normalization +# @see https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html +# @see https://www.drupal.org/node/1542048 + +# Normally these settings would be done with macro attributes for improved +# readability and easier maintenance. However macros can only be defined at the +# repository root directory. Drupal avoids making any assumptions about where it +# is installed. + +# Define text file attributes. +# - Treat them as text. +# - Ensure no CRLF line-endings, neither on checkout nor on checkin. +# - Detect whitespace errors. +# - Exposed by default in `git diff --color` on the CLI. +# - Validate with `git diff --check`. +# - Deny applying with `git apply --whitespace=error-all`. +# - Fix automatically with `git apply --whitespace=fix`. + +*.config text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.css text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.dist text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.engine text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php +*.html text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=html +*.inc text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php +*.install text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php +*.js text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.json text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.lock text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.map text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.md text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.module text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php +*.php text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php +*.po text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.profile text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php +*.script text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.sh text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php +*.sql text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.svg text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.theme text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 diff=php linguist-language=php +*.twig text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.txt text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.xml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 +*.yml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 + +# PHPStan's baseline uses tabs instead of spaces. +core/.phpstan-baseline.php text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tabwidth=2 diff=php linguist-language=php + +# Define binary file attributes. +# - Do not treat them as text. +# - Include binary diff in patches instead of "binary files differ." +*.eot -text diff +*.exe -text diff +*.gif -text diff +*.gz -text diff +*.ico -text diff +*.jpeg -text diff +*.jpg -text diff +*.otf -text diff +*.phar -text diff +*.png -text diff +*.svgz -text diff +*.ttf -text diff +*.woff -text diff +*.woff2 -text diff From 01dc1a7a5a13dfc762afb9ad008b19adfba9b7fd Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Sat, 4 Jul 2026 18:12:43 +1000 Subject: [PATCH 02/12] Migrated local development from Ahoy/Lagoon to DDEV with ddev-drupal-contrib. - Adopt ddev/ddev-drupal-contrib: module repo is the composer root, `ddev poser` builds a disposable Drupal site into web/, `ddev symlink-project` symlinks the module into web/modules/custom/tide_core (live code edits, no sync step). - Fold composer.dev.json into composer.json (require-dev, autoload-dev, allow-plugins, full installer-paths targeting web/); tide_test now comes from the monorepo, not a separate VCS repo. - Pin dev-site core via DRUPAL_CORE=10.6.x in .ddev/config.yaml. - Add services: Elasticsearch 7.17 add-on, Selenium Chrome add-on, custom ClamAV compose file (tide_core hard-depends on clamav module). - Add `ddev install-site` command (testing profile + tide_core/tide_test, points clamav at the local ddev service). - Point behat.yml/phpunit.xml.dist at web/ docroot and ddev service hostnames; phpunit unit suite now also covers modules/*/tests/src/Unit. --- .../ddev-drupal-contrib/manifest.yaml | 19 ++++++ .../manifest.yaml | 19 ++++++ .../elasticsearch/manifest.yaml | 9 +++ .ddev/commands/host/core-version | 22 +++++++ .ddev/commands/web/eslint | 22 +++++++ .ddev/commands/web/expand-composer-json | 28 +++++++++ .ddev/commands/web/install-site | 35 +++++++++++ .ddev/commands/web/nightwatch | 12 ++++ .ddev/commands/web/phpcbf | 17 ++++++ .ddev/commands/web/phpcs | 17 ++++++ .ddev/commands/web/phpstan | 28 +++++++++ .ddev/commands/web/phpunit | 33 +++++++++++ .ddev/commands/web/poser | 18 ++++++ .ddev/commands/web/stylelint | 21 +++++++ .ddev/commands/web/symlink-project | 27 +++++++++ .ddev/config.contrib.yaml | 24 ++++++++ .ddev/config.selenium-standalone-chrome.yaml | 31 ++++++++++ .ddev/config.yaml | 8 ++- .ddev/docker-compose.clamav.yaml | 21 +++++++ .ddev/docker-compose.elasticsearch.yaml | 28 +++++++++ .ddev/docker-compose.selenium-chrome.yaml | 37 ++++++++++++ ...docker-compose.selenium-chrome_extras.yaml | 5 ++ .ddev/elasticsearch/config/elasticsearch8.yml | 15 +++++ .../docker-compose.elasticsearch8.yaml | 6 ++ .gitignore | 3 + README.md | 24 ++++++-- behat.yml | 10 ++-- composer.json | 58 ++++++++++++++++++- phpcs.xml | 2 +- phpunit.xml.dist | 18 +++--- 30 files changed, 591 insertions(+), 26 deletions(-) create mode 100644 .ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml create mode 100644 .ddev/addon-metadata/ddev-selenium-standalone-chrome/manifest.yaml create mode 100644 .ddev/addon-metadata/elasticsearch/manifest.yaml create mode 100755 .ddev/commands/host/core-version create mode 100755 .ddev/commands/web/eslint create mode 100755 .ddev/commands/web/expand-composer-json create mode 100755 .ddev/commands/web/install-site create mode 100755 .ddev/commands/web/nightwatch create mode 100755 .ddev/commands/web/phpcbf create mode 100755 .ddev/commands/web/phpcs create mode 100755 .ddev/commands/web/phpstan create mode 100755 .ddev/commands/web/phpunit create mode 100755 .ddev/commands/web/poser create mode 100755 .ddev/commands/web/stylelint create mode 100755 .ddev/commands/web/symlink-project create mode 100644 .ddev/config.contrib.yaml create mode 100644 .ddev/config.selenium-standalone-chrome.yaml create mode 100644 .ddev/docker-compose.clamav.yaml create mode 100644 .ddev/docker-compose.elasticsearch.yaml create mode 100644 .ddev/docker-compose.selenium-chrome.yaml create mode 100644 .ddev/docker-compose.selenium-chrome_extras.yaml create mode 100644 .ddev/elasticsearch/config/elasticsearch8.yml create mode 100644 .ddev/elasticsearch/docker-compose.elasticsearch8.yaml diff --git a/.ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml b/.ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml new file mode 100644 index 000000000..864be2588 --- /dev/null +++ b/.ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml @@ -0,0 +1,19 @@ +name: ddev-drupal-contrib +repository: ddev/ddev-drupal-contrib +version: 1.1.5 +install_date: "2026-07-04T17:00:13+10:00" +project_files: + - commands/host/core-version + - commands/web/eslint + - commands/web/expand-composer-json + - commands/web/nightwatch + - commands/web/phpcbf + - commands/web/phpcs + - commands/web/phpstan + - commands/web/phpunit + - commands/web/poser + - commands/web/stylelint + - commands/web/symlink-project + - config.contrib.yaml +global_files: [] +removal_actions: [] diff --git a/.ddev/addon-metadata/ddev-selenium-standalone-chrome/manifest.yaml b/.ddev/addon-metadata/ddev-selenium-standalone-chrome/manifest.yaml new file mode 100644 index 000000000..668ca93e3 --- /dev/null +++ b/.ddev/addon-metadata/ddev-selenium-standalone-chrome/manifest.yaml @@ -0,0 +1,19 @@ +name: ddev-selenium-standalone-chrome +repository: ddev/ddev-selenium-standalone-chrome +version: 2.1.0 +install_date: "2026-07-04T17:51:19+10:00" +project_files: + - docker-compose.selenium-chrome.yaml + - config.selenium-standalone-chrome.yaml +global_files: [] +removal_actions: + - | + #ddev-nodisplay + #ddev-description:Remove docker-compose.selenium-chrome_extras.yaml file + if [ -f docker-compose.selenium-chrome_extras.yaml ]; then + if grep -q '#ddev-generated' docker-compose.selenium-chrome_extras.yaml; then + rm -f docker-compose.selenium-chrome_extras.yaml + else + echo "Unwilling to remove '$DDEV_APPROOT/.ddev/docker-compose.selenium-chrome_extras.yaml' because it does not have #ddev-generated in it; you can manually delete it if it is safe to delete." + fi + fi diff --git a/.ddev/addon-metadata/elasticsearch/manifest.yaml b/.ddev/addon-metadata/elasticsearch/manifest.yaml new file mode 100644 index 000000000..878c50958 --- /dev/null +++ b/.ddev/addon-metadata/elasticsearch/manifest.yaml @@ -0,0 +1,9 @@ +name: elasticsearch +repository: ddev/ddev-elasticsearch +version: v0.3.3 +install_date: "2026-07-04T17:40:21+10:00" +project_files: + - elasticsearch/ + - docker-compose.elasticsearch.yaml +global_files: [] +removal_actions: [] diff --git a/.ddev/commands/host/core-version b/.ddev/commands/host/core-version new file mode 100755 index 000000000..e3e012246 --- /dev/null +++ b/.ddev/commands/host/core-version @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Switch the core version and rebuild. +## Usage: core-version [version] +## Example: "ddev core-version ^11" or "ddev core-version ~11.1.0" + +set -eu -o pipefail + +# Handle default values. +DRUPAL_CORE=${1:-default} +if [ "$DRUPAL_CORE" == "default" ]; then + DRUPAL_CORE="" +fi + +# Set/clear the env. +ddev dotenv set .ddev/.env.web --drupal-core "${DRUPAL_CORE}" + +# Restart and rebuild. +ddev restart +ddev poser diff --git a/.ddev/commands/web/eslint b/.ddev/commands/web/eslint new file mode 100755 index 000000000..6be295c6a --- /dev/null +++ b/.ddev/commands/web/eslint @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run eslint inside the web container +## Usage: eslint [flags] [args] +## Example: "ddev eslint" +## ExecRaw: true + +set -eu -o pipefail + +if "$DDEV_DOCROOT/core/node_modules/.bin/eslint" --version >/dev/null ; then + # Configure prettier + test -e .prettierrc.json || ln -s $DDEV_DOCROOT/core/.prettierrc.json . + test -e .prettierignore || echo '*.yml' > .prettierignore + # Change directory to the project root folder + cd "$DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH/${DDEV_SITENAME//-/_}" || exit + "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/node_modules/.bin/eslint" --config="../../../core/.eslintrc.passing.json" --no-error-on-unmatched-pattern --ignore-pattern="*.es6.js" --resolve-plugins-relative-to=$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core --ext=.js,.yml . "$@" +else + echo "eslint is not available. You may need to 'ddev exec \"cd $DDEV_DOCROOT/core && yarn install\"'" + exit 1 +fi diff --git a/.ddev/commands/web/expand-composer-json b/.ddev/commands/web/expand-composer-json new file mode 100755 index 000000000..509e414a9 --- /dev/null +++ b/.ddev/commands/web/expand-composer-json @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Add Drupal core and other needed dependencies. +## Usage: expand-composer-json [flags] [PROJECT_NAME] +## Example: "ddev expand-composer-json ctools" +## ExecRaw: true +## MutagenSync: true + +set -eu -o pipefail + +# Set the default core version. +export DRUPAL_CORE=${DRUPAL_CORE:-^11} + +export _WEB_ROOT=$DDEV_DOCROOT +cd "$DDEV_COMPOSER_ROOT" || exit +curl -OL https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/scripts/expand_composer_json.php +_ddev_drupal_contrib_empty_composer=false +if [[ ! -f composer.json ]]; then + echo "{}" > composer.json + _ddev_drupal_contrib_empty_composer=true +fi +php expand_composer_json.php "$DDEV_SITENAME" +rm -f expand_composer_json.php +if [ "$_ddev_drupal_contrib_empty_composer" = true ]; then + rm -f composer.json +fi diff --git a/.ddev/commands/web/install-site b/.ddev/commands/web/install-site new file mode 100755 index 000000000..365659383 --- /dev/null +++ b/.ddev/commands/web/install-site @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +## Description: Install a fresh Drupal site (testing profile) and enable tide_core + tide_test. +## Usage: install-site +## Example: "ddev install-site" +## ExecRaw: true + +set -eu -o pipefail + +DRUPAL_PROFILE=${DRUPAL_PROFILE:-testing} +DRUPAL_ADMIN_NAME=${DRUPAL_ADMIN_NAME:-admin} +DRUPAL_ADMIN_PASSWORD=${DRUPAL_ADMIN_PASSWORD:-admin} + +drush site:install "${DRUPAL_PROFILE}" -y \ + --account-name="${DRUPAL_ADMIN_NAME}" \ + --account-pass="${DRUPAL_ADMIN_PASSWORD}" \ + --site-name="Single Digital Presence Content Management System" \ + install_configure_form.enable_update_status_module=NULL \ + install_configure_form.enable_update_status_emails=NULL + +drush user:unblock "${DRUPAL_ADMIN_NAME}" +drush cache:rebuild + +echo "==> Enabling tide_core" +drush pm:enable -y tide_core + +echo "==> Pointing ClamAV at the local ddev service" +drush -y config:set clamav.settings mode_daemon_tcpip.hostname clamav +drush -y config:set clamav.settings mode_daemon_tcpip.port 3310 + +echo "==> Enabling tide_test" +drush pm:enable -y tide_test + +drush cache:rebuild +drush user:login --no-browser diff --git a/.ddev/commands/web/nightwatch b/.ddev/commands/web/nightwatch new file mode 100755 index 000000000..06b2ea261 --- /dev/null +++ b/.ddev/commands/web/nightwatch @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run nightwatch inside the web container +## Usage: nightwatch [flags] [args] +## Example: "ddev nightwatch" +## ExecRaw: true + +set -eu -o pipefail + +yarn --cwd "$DDEV_DOCROOT/core" test:nightwatch "$DDEV_APPROOT/$DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH/" "$@" diff --git a/.ddev/commands/web/phpcbf b/.ddev/commands/web/phpcbf new file mode 100755 index 000000000..25393e07b --- /dev/null +++ b/.ddev/commands/web/phpcbf @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run phpcbf inside the web container +## Usage: phpcbf [flags] [args] +## Example: "ddev phpcbf" or "ddev phpcbf -n" +## ExecRaw: true + +set -eu -o pipefail + +if ! command -v phpcbf >/dev/null; then + echo "phpcbf is not available. You may need to 'ddev composer install'" + exit 1 +fi +test -e phpcs.xml.dist || curl -OL https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/assets/phpcs.xml.dist +phpcbf -s --report-full --report-summary --report-source $DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH "$@" diff --git a/.ddev/commands/web/phpcs b/.ddev/commands/web/phpcs new file mode 100755 index 000000000..efcf54af3 --- /dev/null +++ b/.ddev/commands/web/phpcs @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run phpcs inside the web container +## Usage: phpcs [flags] [args] +## Example: "ddev phpcs" or "ddev phpcs -n" +## ExecRaw: true + +set -eu -o pipefail + +if ! command -v phpcs >/dev/null; then + echo "phpcs is not available. You may need to 'ddev composer install'" + exit 1 +fi +test -e phpcs.xml.dist || curl -OL https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/assets/phpcs.xml.dist +phpcs -s --report-full --report-summary --report-source $DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH --ignore=*/.ddev/* "$@" diff --git a/.ddev/commands/web/phpstan b/.ddev/commands/web/phpstan new file mode 100755 index 000000000..253ff6d4a --- /dev/null +++ b/.ddev/commands/web/phpstan @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run phpstan inside the web container +## Usage: phpstan [flags] [args] +## Example: "ddev phpstan" or "ddev phpstan -n" +## ExecRaw: true +## MutagenSync: true + +set -eu -o pipefail + +if ! command -v phpstan >/dev/null; then + echo "phpstan is not available. You may need to 'ddev poser'" + exit 1 +fi +test -e phpstan.neon || curl -OL https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/assets/phpstan.neon +# See https://git.drupalcode.org/project/gitlab_templates/-/commit/a107b7f1f79af12e0b09f70be47b68e3f69b4504 +sed -i 's/BASELINE_PLACEHOLDER/phpstan-baseline.neon/g' phpstan.neon +# Add an empty baseline file to ensure it exists. +test -e phpstan-baseline.neon || touch phpstan-baseline.neon + +EXTENSION_DIRECTORY=$DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH/${DDEV_SITENAME//-/_} +cd "$EXTENSION_DIRECTORY" || exit 1 +# Ensure PHPStan configuration is symlinked from project root. +ln -s $DDEV_DOCROOT/phpstan.neon 2>/dev/null || true +ln -s $DDEV_DOCROOT/phpstan-baseline.neon 2>/dev/null || true +phpstan analyze . "$@" diff --git a/.ddev/commands/web/phpunit b/.ddev/commands/web/phpunit new file mode 100755 index 000000000..b96730419 --- /dev/null +++ b/.ddev/commands/web/phpunit @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run phpunit inside the web container +## Usage: phpunit [flags] [args] +## Example: "ddev phpunit" or "ddev phpunit --stop-on-failure" +## Example: "ddev phpunit web/modules/custom/mymodule/tests/src/Unit/MyTest.php" +## Example: "ddev phpunit --filter testMyFunction" +## ExecRaw: true + +set -eu -o pipefail + +if ! command -v phpunit >/dev/null; then + echo "phpunit is not available. You may need to 'ddev composer install'" + exit 1 +fi + +# CHECK for local config. +if [ -f "phpunit.xml" ]; then + # Defer to local config + phpunit "$@" +else + # Check if we are running a specific test or test folder. + if [ $# -gt 0 ] && [ -e "$1" ]; then + TEST_PATH="$1" + shift + phpunit --bootstrap $PWD/$DDEV_DOCROOT/core/tests/bootstrap.php "$TEST_PATH" "$@" + else + # Run all custom module tests. + phpunit --bootstrap $PWD/$DDEV_DOCROOT/core/tests/bootstrap.php $DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH "$@" + fi +fi diff --git a/.ddev/commands/web/poser b/.ddev/commands/web/poser new file mode 100755 index 000000000..e6d6617f8 --- /dev/null +++ b/.ddev/commands/web/poser @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Expand composer.json and run composer install. +## Usage: poser [flags] [args] +## Example: "ddev poser" or "ddev poser --prefer-source" +## ExecRaw: true +## MutagenSync: true + +set -eu -o pipefail + +export COMPOSER=composer.contrib.json +.ddev/commands/web/expand-composer-json +composer install "$@" +# The -f flag suppresses errors if lock file does not exist. +rm -f composer.contrib.json composer.contrib.lock +touch $DDEV_DOCROOT/core/.env diff --git a/.ddev/commands/web/stylelint b/.ddev/commands/web/stylelint new file mode 100755 index 000000000..521d3bc75 --- /dev/null +++ b/.ddev/commands/web/stylelint @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Run stylelint inside the web container +## Usage: stylelint [flags] [args] +## Example: "ddev stylelint" +## ExecRaw: true + +set -eu -o pipefail + +if "$DDEV_DOCROOT/core/node_modules/.bin/stylelint" --version >/dev/null ; then + # Configure prettier + test -e .prettierrc.json || ln -s $DDEV_DOCROOT/core/.prettierrc.json . + # Change directory to the project root folder + cd "$DDEV_DOCROOT/$DRUPAL_PROJECTS_PATH/${DDEV_SITENAME//-/_}" || exit + "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/node_modules/.bin/stylelint" --color --config "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/.stylelintrc.json" "./**/*.css" "$@" +else + echo "stylelint is not available. You may need to 'ddev exec \"cd $DDEV_DOCROOT/core && yarn install\"'" + exit 1 +fi diff --git a/.ddev/commands/web/symlink-project b/.ddev/commands/web/symlink-project new file mode 100755 index 000000000..7db02d30c --- /dev/null +++ b/.ddev/commands/web/symlink-project @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## Description: Symlink project files into the configured location (defaults to `web/modules/custom/[PROJECT_NAME]`) +## Usage: symlink-project [flags] [args] +## Example: "ddev symlink-project" +## ExecRaw: true + +set -eu -o pipefail + +export _WEB_ROOT=$DDEV_DOCROOT +cd "$DDEV_COMPOSER_ROOT" || exit +curl -OL https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/scripts/symlink_project.php + +if [ -n "${PROJECT_FILES-}" ]; then + # Suppress a warning. + PROJECT_FILES=$(ls -A --ignore="web" --ignore="vendor" --ignore="symlink_project.php" --ignore=".ddev" --ignore=".idea") + export PROJECT_FILES +fi + +# Symlink name using underscores. +# @see https://www.drupal.org/docs/develop/creating-modules/naming-and-placing-your-drupal-module +# DRUPAL_PROJECT_FOLDER is used by the symlink-project script in gitlab_templates +export DRUPAL_PROJECT_FOLDER=${DDEV_DOCROOT}/${DRUPAL_PROJECTS_PATH}/${DDEV_SITENAME//-/_} +php symlink_project.php +rm -f symlink_project.php diff --git a/.ddev/config.contrib.yaml b/.ddev/config.contrib.yaml new file mode 100644 index 000000000..344b786ae --- /dev/null +++ b/.ddev/config.contrib.yaml @@ -0,0 +1,24 @@ +#ddev-generated +## Command provided by https://github.com/ddev/ddev-drupal-contrib +## To customize this configuration, see: +## https://ddev.readthedocs.io/en/stable/users/extend/customization-extendibility/ +web_environment: + # To change the Drupal core version, see the README: + # https://github.com/ddev/ddev-drupal-contrib/blob/main/README.md#changing-the-drupal-core-version + # https://git.drupalcode.org/project/gitlab_templates/-/blob/1.9.6/scripts/expand_composer_json.php?ref_type=tags#L15 + - IGNORE_PROJECT_DRUPAL_CORE_VERSION=1 + # To change the location of your project code, see the README: + # https://github.com/ddev/ddev-drupal-contrib/blob/main/README.md#changing-the-symlink-location + - DRUPAL_PROJECTS_PATH=modules/custom + - SIMPLETEST_DB=mysql://db:db@db/db + - SIMPLETEST_BASE_URL=http://web + - BROWSERTEST_OUTPUT_DIRECTORY=/tmp + - BROWSERTEST_OUTPUT_BASE_URL=${DDEV_PRIMARY_URL} +hooks: + post-start: + - exec-host: | + if [[ -f vendor/autoload.php ]]; then + ddev symlink-project + else + exit 0 + fi diff --git a/.ddev/config.selenium-standalone-chrome.yaml b/.ddev/config.selenium-standalone-chrome.yaml new file mode 100644 index 000000000..842c650b8 --- /dev/null +++ b/.ddev/config.selenium-standalone-chrome.yaml @@ -0,0 +1,31 @@ +#ddev-generated +# Remove the line above if you don't want this file to be overwritten when you run +# ddev get ddev/ddev-selenium-standalone-chrome +# +# This file comes from https://github.com/ddev/ddev-selenium-standalone-chrome +# +web_environment: + - BROWSERTEST_OUTPUT_DIRECTORY=/tmp + - BROWSERTEST_OUTPUT_BASE_URL=${DDEV_PRIMARY_URL} + - SIMPLETEST_BASE_URL=http://web + - SIMPLETEST_DB=mysql://db:db@db/db + # Use disable-dev-shm-usage instead of setting shm_usage + # https://developers.google.com/web/tools/puppeteer/troubleshooting#tips + # The format of chromeOptions is defined at https://chromedriver.chromium.org/capabilities + - MINK_DRIVER_ARGS_WEBDRIVER=[\"chrome\", {\"browserName\":\"chrome\",\"goog:chromeOptions\":{\"w3c\":true,\"args\":[\"--disable-dev-shm-usage\",\"--disable-gpu\",\"--headless\",\"--dns-prefetch-disable\"]}}, \"http://selenium-chrome:4444/wd/hub\"] + # Nightwatch + - DRUPAL_TEST_BASE_URL=http://web + - DRUPAL_TEST_DB_URL=mysql://db:db@db/db + - DRUPAL_TEST_WEBDRIVER_HOSTNAME=selenium-chrome + - DRUPAL_TEST_WEBDRIVER_PORT=4444 + - DRUPAL_TEST_WEBDRIVER_PATH_PREFIX=/wd/hub + - DRUPAL_TEST_WEBDRIVER_W3C=true + # --window-size=1920,1080 is needed to fix random timeouts in tests. See: https://community.latenode.com/t/selenium-webdriver-timeout-issue-when-running-in-headless-mode-with-c/21952/4 + - DRUPAL_TEST_WEBDRIVER_CHROME_ARGS=--disable-dev-shm-usage --disable-gpu --headless --dns-prefetch-disable --window-size=1920,1080 + - DRUPAL_TEST_CHROMEDRIVER_AUTOSTART=false + - DRUPAL_NIGHTWATCH_SEARCH_DIRECTORY=../ + - DRUPAL_NIGHTWATCH_IGNORE_DIRECTORIES=node_modules,vendor,.*,sites/*/files,sites/*/private,sites/simpletest + - DRUPAL_NIGHTWATCH_OUTPUT=reports/nightwatch + # DTT + - DTT_BASE_URL=http://web + - DTT_MINK_DRIVER_ARGS=[\"chrome\", {\"browserName\":\"chrome\",\"goog:chromeOptions\":{\"w3c\":true,\"args\":[\"--disable-dev-shm-usage\",\"--disable-gpu\",\"--headless\",\"--dns-prefetch-disable\"]}}, \"http://selenium-chrome:4444/wd/hub\"] diff --git a/.ddev/config.yaml b/.ddev/config.yaml index eb025a134..800a36f97 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -1,6 +1,6 @@ name: tide-core type: drupal10 -docroot: docroot +docroot: web php_version: "8.3" webserver_type: nginx-fpm xdebug_enabled: false @@ -13,9 +13,11 @@ use_dns_when_possible: true composer_version: "2" router_http_port: "8080" router_https_port: "8443" -web_environment: - - DRUPAL_MODULE_PREFIX= corepack_enable: false +web_environment: + # Drupal core version used by `ddev poser` (drupal.org gitlab_templates + # expand_composer_json.php). Keep in sync with drupal/core in composer.json. + - DRUPAL_CORE=10.6.x hooks: post-import-db: diff --git a/.ddev/docker-compose.clamav.yaml b/.ddev/docker-compose.clamav.yaml new file mode 100644 index 000000000..5ce3d90d8 --- /dev/null +++ b/.ddev/docker-compose.clamav.yaml @@ -0,0 +1,21 @@ +# ClamAV daemon for the drupal/clamav module (hard dependency of tide_core). +# Replaces the `clamav` service from the legacy Ahoy docker-compose stack. +# The hostname override to this service is applied by `ddev install-site`. +services: + clamav: + container_name: ddev-${DDEV_SITENAME}-clamav + hostname: clamav + image: clamav/clamav-debian:stable + expose: + - "3310" + environment: + - CLAMAV_NO_MILTERD=true + labels: + com.ddev.site-name: ${DDEV_SITENAME} + com.ddev.approot: ${DDEV_APPROOT} + volumes: + - clamav:/var/lib/clamav + - ".:/mnt/ddev_config" + +volumes: + clamav: diff --git a/.ddev/docker-compose.elasticsearch.yaml b/.ddev/docker-compose.elasticsearch.yaml new file mode 100644 index 000000000..3625600eb --- /dev/null +++ b/.ddev/docker-compose.elasticsearch.yaml @@ -0,0 +1,28 @@ +#ddev-generated +services: + elasticsearch: + container_name: ddev-${DDEV_SITENAME}-elasticsearch + hostname: ${DDEV_SITENAME}-elasticsearch + image: ${ELASTICSEARCH_DOCKER_IMAGE:-elasticsearch:7.17.14} + expose: + - "9200" + - "9300" + environment: + - cluster.name=docker-cluster + - discovery.type=single-node + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + - VIRTUAL_HOST=${DDEV_HOSTNAME} + - HTTP_EXPOSE=9200:9200 + - HTTPS_EXPOSE=9201:9200 + labels: + com.ddev.site-name: ${DDEV_SITENAME} + com.ddev.approot: ${DDEV_APPROOT} + volumes: + - elasticsearch:/usr/share/elasticsearch/data + - ".:/mnt/ddev_config" + healthcheck: + test: ["CMD-SHELL", "curl --fail -s elasticsearch:9200"] + +volumes: + elasticsearch: diff --git a/.ddev/docker-compose.selenium-chrome.yaml b/.ddev/docker-compose.selenium-chrome.yaml new file mode 100644 index 000000000..9da12f422 --- /dev/null +++ b/.ddev/docker-compose.selenium-chrome.yaml @@ -0,0 +1,37 @@ +#ddev-generated +# Remove the line above if you don't want this file to be overwritten when you run +# ddev get ddev/ddev-selenium-standalone-chrome +# +# This file comes from https://github.com/ddev/ddev-selenium-standalone-chrome +# +services: + selenium-chrome: + image: selenium/standalone-chromium:138.0 + container_name: ddev-${DDEV_SITENAME}-selenium-chrome + expose: + # The internal noVNC port, which operates over HTTP so it can be exposed + # through the router. + - 7900 + environment: + - VIRTUAL_HOST=$DDEV_HOSTNAME + - HTTPS_EXPOSE=7900:7900 + - HTTP_EXPOSE=7910:7900 + - VNC_NO_PASSWORD=1 + # Enables multiple parallel connections to the Selenium. + - SE_NODE_MAX_SESSIONS=12 + - SE_NODE_OVERRIDE_MAX_SESSIONS=true + # To enable VNC access for traditional VNC clients like macOS "Screen Sharing", + # uncomment the following two lines. + #ports: + # - "5900:5900" + labels: + com.ddev.site-name: ${DDEV_SITENAME} + com.ddev.approot: $DDEV_APPROOT + volumes: + # To enable file uploads in E2E tests. + - ${DDEV_APPROOT}:/var/www/html:r + - ".:/mnt/ddev_config" + + web: + links: + - selenium-chrome diff --git a/.ddev/docker-compose.selenium-chrome_extras.yaml b/.ddev/docker-compose.selenium-chrome_extras.yaml new file mode 100644 index 000000000..4b8e2336f --- /dev/null +++ b/.ddev/docker-compose.selenium-chrome_extras.yaml @@ -0,0 +1,5 @@ +#ddev-generated +services: + selenium-chrome: + external_links: + - "ddev-router:${DDEV_PROJECT}.${DDEV_TLD}" diff --git a/.ddev/elasticsearch/config/elasticsearch8.yml b/.ddev/elasticsearch/config/elasticsearch8.yml new file mode 100644 index 000000000..3a612d3db --- /dev/null +++ b/.ddev/elasticsearch/config/elasticsearch8.yml @@ -0,0 +1,15 @@ +#ddev-generated +# This file contains the configuration settings for Elasticsearch 8. +# For more information, see https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html + +# https://www.elastic.co/guide/en/elasticsearch/reference/current/important-settings.html#cluster-name +cluster.name: "docker-cluster" + +# https://www.elastic.co/guide/en/elasticsearch/reference/current/important-settings.html#network.host +network.host: 0.0.0.0 + +# Disable security features +# https://www.elastic.co/guide/en/elasticsearch/reference/current/security-settings.html#general-security-settings +xpack.security.enabled: false +xpack.security.autoconfiguration.enabled: false +xpack.security.enrollment.enabled: false diff --git a/.ddev/elasticsearch/docker-compose.elasticsearch8.yaml b/.ddev/elasticsearch/docker-compose.elasticsearch8.yaml new file mode 100644 index 000000000..9e864c365 --- /dev/null +++ b/.ddev/elasticsearch/docker-compose.elasticsearch8.yaml @@ -0,0 +1,6 @@ +#ddev-generated +services: + elasticsearch: + image: ${ELASTICSEARCH_DOCKER_IMAGE:-elasticsearch:8.10.2} + volumes: + - ./elasticsearch/config/elasticsearch8.yml:/usr/share/elasticsearch/config/elasticsearch.yml diff --git a/.gitignore b/.gitignore index d176ddf50..49fc5511a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ # https://help.github.com/articles/ignoring-files/#create-a-global-gitignore /composer.lock +/composer.contrib.json +/composer.contrib.lock +/web /composer.build.json /composer.build.lock /docroot diff --git a/README.md b/README.md index 55a27bc66..e8ebbffd8 100644 --- a/README.md +++ b/README.md @@ -50,13 +50,25 @@ is a maintainer of this package. [Open an issue](https://github.com/dpc-sdp) on GitHub or submit a pull request with suggested changes. ## Development and maintenance -Development is powered by [Dev-Tools](https://github.com/dpc-sdp/dev-tools). Please refer to Dev-Tools' -page for [system requirements](https://github.com/dpc-sdp/dev-tools/#prerequisites) and other details. +Local development is powered by [DDEV](https://ddev.readthedocs.io/) with the +[ddev-drupal-contrib](https://github.com/ddev/ddev-drupal-contrib) add-on. The module +repository is the project root; a disposable Drupal site is built into `web/` and the +module is made available to it via per-file symlinks — code changes at the repository +root take effect immediately, no sync step required. -To start local development stack: -1. Checkout this project -2. Run `./dev-tools.sh` -3. Run `ahoy build` +To start the local development stack: +1. Checkout this project. +2. Run `ddev start` — starts web, db, elasticsearch, selenium-chrome and clamav services. +3. Run `ddev poser` — installs Drupal core (version pinned by `DRUPAL_CORE` in `.ddev/config.yaml`) plus all module dependencies into `web/` and `vendor/`. +4. Run `ddev symlink-project` — symlinks this module into `web/modules/custom/tide_core` (re-run after adding/removing root-level files; also runs automatically on `ddev start`). +5. Run `ddev install-site` — installs a fresh site (`testing` profile) and enables `tide_core` and `tide_test`. + +Day-to-day commands: +- `ddev drush ` — run Drush. +- `ddev phpunit --testsuite unit` — run PHPUnit unit tests. +- `ddev exec vendor/bin/behat --strict --colors [path/to.feature]` — run Behat tests (add `--profile=suggest` for the suggest profile). +- `ddev phpcs` / `ddev phpcbf` — lint / auto-fix coding standards. +- `ddev ssh` — shell into the web container. ## Related projects - [tide](https://github.com/dpc-sdp/tide) diff --git a/behat.yml b/behat.yml index 523d379ef..8c444a085 100644 --- a/behat.yml +++ b/behat.yml @@ -33,22 +33,22 @@ default: Drupal\MinkExtension: files_path: '%paths.base%/tests/behat/fixtures' selenium2: - wd_host: "http://chrome:4444/wd/hub" + wd_host: "http://selenium-chrome:4444/wd/hub" capabilities: { "browser": "chrome", "version": "*", "marionette": true } browserkit_http: ~ ajax_timeout: 5 browser_name: chrome javascript_session: selenium2 - base_url: http://nginx:8080 + base_url: http://web # Provides integration with Drupal APIs. Drupal\DrupalExtension: blackbox: ~ api_driver: drupal drush_driver: drush drupal: - drupal_root: docroot + drupal_root: web drush: - root: docroot + root: web selectors: message_selector: '.messages' error_message_selector: '.messages.messages--error' @@ -80,7 +80,7 @@ default: purge: false Imbo\BehatApiExtension: apiClient: - base_uri: http://nginx:8080 + base_uri: http://web timeout: 5.0 verify: false # Set to true if using production HTTPS locally diff --git a/composer.json b/composer.json index 5eb12b1b4..150d2a276 100644 --- a/composer.json +++ b/composer.json @@ -461,10 +461,25 @@ } }, "installer-paths": { - "docroot/libraries/{$name}": [ + "web/core": [ + "type:drupal-core" + ], + "web/libraries/{$name}": [ "type:drupal-library", "type:bower-asset", "type:npm-asset" + ], + "web/modules/contrib/{$name}": [ + "type:drupal-module" + ], + "web/profiles/contrib/{$name}": [ + "type:drupal-profile" + ], + "web/themes/contrib/{$name}": [ + "type:drupal-theme" + ], + "drush/{$name}": [ + "type:drupal-drush" ] }, "installer-types": ["bower-asset", "npm-asset"] @@ -472,10 +487,49 @@ "config": { "allow-plugins": { "composer/installers": true, - "oomphinc/composer-installers-extender": true + "oomphinc/composer-installers-extender": true, + "php-http/discovery": true, + "cweagans/composer-patches": true, + "drupal/core-composer-scaffold": true, + "dealerdirect/phpcodesniffer-composer-installer": true, + "phpstan/extension-installer": true, + "tbachert/spi": true }, "audit": { "block-insecure": false } + }, + "require-dev": { + "behat/behat": "~3.5", + "behat/mink": "^1.11", + "behat/mink-browserkit-driver": "^2.2", + "behat/mink-selenium2-driver": "^1.4", + "squizlabs/php_codesniffer": "3.7.1", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "doctrine/persistence": "^3.3", + "drupal/coder": "^8.3.10", + "drupal/drupal-extension": "^5.0.0rc1", + "drevops/behat-screenshot": "^1.0", + "drevops/behat-steps": "^1.2.0", + "drush/drush": "^13", + "phpcompatibility/php-compatibility": "^9.1", + "imbo/behat-api-extension": "^6.0", + "symfony/filesystem": "^6.2", + "php-http/curl-client": "*", + "phpunit/phpunit": "^8.5.14 || ^9", + "phpspec/prophecy-phpunit": "^2", + "weitzman/drupal-test-traits": "^1.5", + "php-http/message": "~1.13", + "php-http/message-factory": "^1.1", + "guzzlehttp/psr7": "~2.8.0", + "drupal/test_helpers": "^1.2" + }, + "provide": { + "drupal/ckeditor": "*" + }, + "autoload-dev": { + "psr-4": { + "Tide\\Tests\\Context\\": "tests/behat/bootstrap/" + } } } diff --git a/phpcs.xml b/phpcs.xml index 14f338705..e25881ddd 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -14,7 +14,7 @@ key "config.platform.php".--> - */docroot/* + */web/* */console/* settings.generated.php */vendor/* diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a7bf38ba5..bcd7a0c97 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -4,18 +4,17 @@ or your current system user. See core/tests/README.md and https://www.drupal.org/node/2116263 for details. --> - + - ./dpc-sdp + ./src + ./modules/*/src ./modules/*/src/Tests ./modules/*/tests - ../modules/*/src/Tests - ../modules/*/tests - ../modules/*/*/src/Tests - ../modules/*/*/tests + ./modules/*/*/src/Tests + ./modules/*/*/tests @@ -24,9 +23,9 @@ - + - + From fd30653c72fe78f4e0283d7dab709d99ff579231 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Sat, 4 Jul 2026 18:12:43 +1000 Subject: [PATCH 03/12] Removed legacy Ahoy/Lagoon/Bay development tooling. Replaced by DDEV (see previous commit). CircleCI scripts still reference ahoy and need a follow-up rewrite. --- .ahoy.yml | 203 ------------ .docker/Caddyfile | 9 - .docker/Dockerfile.cli | 27 -- .docker/Dockerfile.elasticsearch | 13 - .docker/Dockerfile.nginx-drupal | 10 - .docker/Dockerfile.php | 8 - .docker/elasticsearch.ci.yml | 14 - .docker/elasticsearch.yml | 13 - .dockerignore | 11 - .env | 62 ---- Brewfile | 8 - composer.dev.json | 482 ---------------------------- docker-compose.yml | 172 ---------- scripts/bay-deploy.sh | 19 -- scripts/composer-merge.sh | 26 -- scripts/composer/DrupalSettings.php | 216 ------------- scripts/composer/ScriptHandler.php | 138 -------- scripts/doctor.sh | 114 ------- scripts/drupal-init-module.sh | 60 ---- scripts/drupal-init-profile.sh | 38 --- scripts/drupal/import-db.sh | 15 - scripts/drupal/install-new-site.sh | 17 - scripts/drush-download-db.sh | 42 --- scripts/link-package.sh | 34 -- scripts/rebuild-env.sh | 13 - 25 files changed, 1764 deletions(-) delete mode 100644 .ahoy.yml delete mode 100644 .docker/Caddyfile delete mode 100644 .docker/Dockerfile.cli delete mode 100644 .docker/Dockerfile.elasticsearch delete mode 100644 .docker/Dockerfile.nginx-drupal delete mode 100644 .docker/Dockerfile.php delete mode 100644 .docker/elasticsearch.ci.yml delete mode 100644 .docker/elasticsearch.yml delete mode 100644 .dockerignore delete mode 100644 .env delete mode 100644 Brewfile delete mode 100644 composer.dev.json delete mode 100644 docker-compose.yml delete mode 100755 scripts/bay-deploy.sh delete mode 100755 scripts/composer-merge.sh delete mode 100644 scripts/composer/DrupalSettings.php delete mode 100644 scripts/composer/ScriptHandler.php delete mode 100755 scripts/doctor.sh delete mode 100755 scripts/drupal-init-module.sh delete mode 100755 scripts/drupal-init-profile.sh delete mode 100755 scripts/drupal/import-db.sh delete mode 100755 scripts/drupal/install-new-site.sh delete mode 100755 scripts/drush-download-db.sh delete mode 100755 scripts/link-package.sh delete mode 100755 scripts/rebuild-env.sh diff --git a/.ahoy.yml b/.ahoy.yml deleted file mode 100644 index bbc5428dd..000000000 --- a/.ahoy.yml +++ /dev/null @@ -1,203 +0,0 @@ ---- -ahoyapi: v2 - -commands: - build: - usage: Build or rebuild project. - cmd: | - ahoy clean \ - && if [ "$COMPOSER" != "composer.json" ]; then ahoy composer-merge; fi \ - && if [ "$COMPOSER" != "composer.json" ]; then ahoy link-package; fi \ - && (docker network prune -f > /dev/null && docker network inspect amazeeio-network > /dev/null || docker network create amazeeio-network) \ - && ahoy up -- --build --force-recreate \ - && ahoy install-dev \ - && if [ "$COMPOSER" != "composer.json" ] && [ "$DRUPAL_PROFILE" ]; then ahoy init-profile; fi \ - && ahoy install-site \ - && if [ "$COMPOSER" != "composer.json" ]; then ahoy init-module; fi \ - && if [ "$COMPOSER" != "composer.json" ]; then ahoy drush pm-enable tide_test -y; fi \ - && ahoy line "Build complete" \ - && ahoy info 1 - - info: - usage: Print information about this project. - cmd: | - ahoy line "Site URL : " ${LOCALDEV_URL}:${LOCAL_PORT:-80}/ - ahoy line "Path to project : " ${APP} - ahoy line "Path to docroot : " ${APP}/${WEBROOT} - ahoy line "DB port on host : " $(docker port $(docker-compose ps -q mariadb) 3306 | cut -d : -f 2) - ahoy line "Mailhog URL : " http://mailhog.docker.internal:${LOCAL_PORT:-80}/ - if [ "$1" ]; then - ahoy line "One-time login : " $(ahoy login -- --no-browser) - fi - - up: - usage: Build and start Docker containers. - cmd: | - docker-compose up -d "$@" \ - && ahoy cli "dockerize -wait tcp://mariadb:3306 -timeout 1m" \ - && if docker-compose logs | grep -q "\[Error\]"; then docker-compose logs; exit 1; fi \ - && docker ps -a --filter name=^/${COMPOSE_PROJECT_NAME}_ && - # Add Bay SSH key before fetching DB. - # During local development, pygmy injects SSH key from the host, so specifying - # key as $BAY_KEY environment variable is not required (the host key of every - # developer must be added to Bay during project onboarding). - if [ "$BAY_KEY" ]; then - ahoy cli "mkdir -p /home/.ssh && echo -e \"$BAY_KEY\" > /home/.ssh/key && chmod 600 /home/.ssh/key;" - fi - - down: - usage: Stop Docker containers and remove container, images, volumes and networks. - cmd: docker-compose down --volumes - - start: - usage: Start existing Docker containers. - cmd: docker-compose start "$@" - - stop: - usage: Stop running Docker containers. - cmd: docker-compose stop "$@" - - restart: - usage: Restart all stopped and running Docker containers. - cmd: docker-compose restart - - logs: - usage: Show Docker logs. - cmd: docker-compose logs "$@" - - pull: - usage: Pull latest docker images. - cmd: | - docker image ls --format \"{{.Repository}}:{{.Tag}}\" | grep singledigital/ | grep -v none | xargs -n1 docker pull | cat \ - && docker image ls --format \"{{.Repository}}:{{.Tag}}\" | grep amazeeio/ | grep -v none | xargs -n1 docker pull | cat - - cli: - usage: Start a shell inside CLI container or run a command. - cmd: if \[ "$@" \]; then docker exec -i $(docker-compose ps -q cli) bash -c "$@"; else docker exec -it $(docker-compose ps -q cli) bash; fi - - drush: - usage: Run drush commands in the CLI service container. - cmd: docker exec -i $(docker-compose ps -q cli) drush -r ${APP}/${WEBROOT} -l ${LOCALDEV_URL} "$@" - - login: - usage: Login to a website. - cmd: ahoy drush user:unblock -q "$(ahoy drush user:information --uid=1 --fields=name --format=string)" 2>/dev/null && ahoy drush user:login --no-browser - - doctor: - usage: Find problems with current project setup. - cmd: scripts/doctor.sh - - # @note: Call this on the host before starting containers. - composer-merge: - usage: Merge composer files. - cmd: scripts/composer-merge.sh - - install-dev: - usage: Install dependencies. - cmd: ahoy cli "composer install -n --ansi --prefer-dist --no-suggest" - - install-site: - usage: Install site. - cmd: | - ahoy flush-redis - if [ "$INSTALL_NEW_SITE" == "1" ]; then - ahoy cli -- ./scripts/drupal/install-new-site.sh - else - ahoy cli -- ./scripts/rebuild-env.sh - fi - - db-import: - usage: Import the production database. - cmd: ahoy cli -- ./scripts/rebuild-env.sh - - fix-bay-token: - usage: Fix the bay token by re-importing. - cmd: | - pygmy stop \ - && sleep 1 \ - && pygmy start \ - && docker ps -a | grep Exit | cut -d ' ' -f 1 | xargs docker rm \ - && docker-compose up -d --force \ - && pygmy stop \ - && sleep 1 \ - && pygmy start - - link-package: - usage: Link package from current repository root. - cmd: scripts/link-package.sh - hide: true - - init-module: - usage: Install a module from current repository root. - cmd: ahoy cli "INSTALL_SUGGEST=$INSTALL_SUGGEST scripts/drupal-init-module.sh" - hide: true - - init-profile: - usage: Install a profile from current repository root. - cmd: ahoy cli "INSTALL_SUGGEST=$INSTALL_SUGGEST scripts/drupal-init-profile.sh" - hide: true - - clean: - usage: Remove all build files. - cmd: | - ahoy down \ - && ([ -d .git ] && git ls-files --directory --other -i --exclude-from=.gitignore ${WEBROOT} | grep -v "settings.local.php" | grep -v "services.local.yml" | xargs chmod -Rf 777 || true) \ - && ([ -d .git ] && git ls-files --directory --other -i --exclude-from=.gitignore ${WEBROOT} | grep -v "settings.local.php" | grep -v "services.local.yml" | xargs rm -Rf || true) \ - && rm -Rf vendor \ - && rm -Rf screenshots \ - && rm -Rf composer.build.* - - clean-full: - usage: Remove all development files. - cmd: | - ahoy clean \ - && ([ -d .git ] && git ls-files --directory --other . | grep -v ".idea" | xargs chmod -Rf 777 || true) \ - && ([ -d .git ] && git ls-files --directory --other . | grep -v ".idea" | xargs rm -Rf || true) - - deploy: - usage: Deploy or re-deploy a branch in Bay. - cmd: ./scripts/bay-deploy.sh "$@" - - lint: - usage: Lint code. - cmd: ahoy cli "vendor/bin/phpcs ${PHPCS_TARGETS}" - - lint-fix: - usage: Fix lint errors. - cmd: ahoy cli "vendor/bin/phpcbf ${PHPCS_TARGETS}" - - test-behat: - usage: Run Behat tests. - cmd: ahoy cli "./vendor/bin/behat --strict --colors ${BEHAT_PROFILE} $@" - - flush-redis: - usage: Flush Redis cache. - cmd: docker exec -i $(docker-compose ps -q redis) redis-cli flushall > /dev/null - - # Utilities. - line: - cmd: printf "$(tput -Txterm setaf 2)${1}$(tput -Txterm sgr0)${2}\n" - hide: true - -entrypoint: - - bash - - "-c" - - | - [ -f .env ] && export $(grep -v '^#' .env | xargs) && [ -f .env.local ] && export $(grep -v '^#' .env.local | xargs) - export DOCKER_BUILDKIT=0 - export COMPOSE_DOCKER_CLI_BUILD=0 - export PROJECT_NAME=${PROJECT_NAME:-$(basename $(pwd))} - export APP=${APP:-/app} - export WEBROOT=${WEBROOT:-docroot} - export MYSQL_HOST=${MYSQL_HOST:-mariadb} - export MYSQL_PORT=${MYSQL_PORT:-3306} - export COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-$PROJECT_NAME} - export LOCALDEV_URL=${LOCALDEV_URL:-http://content-sdp.docker.internal} - export COMPOSER=${COMPOSER:-composer.json} - export DRUPAL_PROFILE=${DRUPAL_PROFILE:-} - export DRUPAL_MODULE_PREFIX=${DRUPAL_MODULE_PREFIX:-mysite} - PHPCS_TARGETS=${PHPCS_TARGETS:-.} && export PHPCS_TARGETS=${PHPCS_TARGETS//,/ } - if [ "$CI" ]; then export ES_TPL=elasticsearch.ci.yml; fi - bash -c "$0" "$@" - - '{{cmd}}' - - '{{name}}' diff --git a/.docker/Caddyfile b/.docker/Caddyfile deleted file mode 100644 index 50311132c..000000000 --- a/.docker/Caddyfile +++ /dev/null @@ -1,9 +0,0 @@ -content-sdp.docker.internal:80 { - reverse_proxy nginx:8080 -} -elasticsearch.docker.internal:80 { - reverse_proxy elasticsearch:9200 -} -mailhog.docker.internal:80 { - reverse_proxy mailhog:8025 -} diff --git a/.docker/Dockerfile.cli b/.docker/Dockerfile.cli deleted file mode 100644 index 3a5a424fa..000000000 --- a/.docker/Dockerfile.cli +++ /dev/null @@ -1,27 +0,0 @@ -ARG BAY_IMAGE_VERSION - -# @see https://github.com/dpc-sdp/bay/blob/master/bay/images/Dockerfile.php -FROM ghcr.io/dpc-sdp/bay/php-cli:${BAY_IMAGE_VERSION} -ARG COMPOSER - -ENV MYSQL_HOST=mariadb \ - COMPOSER=${COMPOSER:-composer.json} \ - DRUPAL_MODULE_PREFIX=${DRUPAL_MODULE_PREFIX:-} - - - -# Antivirus update returns non-zero codes. -# @see https://github.com/clamwin/clamav/blob/0.100.1/freshclam/freshclamcodes.h#L23 -RUN freshclam --no-warnings || true - -ADD patches /app/patches -ADD scripts /app/scripts -ADD dpc-sdp /app/dpc-sdp - -COPY composer.json .env composer.* /app/ - -RUN echo "memory_limit=-1" >> /usr/local/etc/php/conf.d/memory.ini \ - && COMPOSER=$COMPOSER composer install -n --no-dev --ansi --prefer-dist --no-suggest --optimize-autoloader \ - && rm -rf /usr/local/etc/php/conf.d/memory.ini - -COPY . /app diff --git a/.docker/Dockerfile.elasticsearch b/.docker/Dockerfile.elasticsearch deleted file mode 100644 index ac10da6ff..000000000 --- a/.docker/Dockerfile.elasticsearch +++ /dev/null @@ -1,13 +0,0 @@ -ARG BAY_IMAGE_VERSION -ARG ES_TPL - -FROM "ghcr.io/dpc-sdp/bay/elasticsearch:${BAY_IMAGE_VERSION}" - -ENV ES_TPL=${ES_TPL:-elasticsearch.yml} - -COPY .docker/elasticsearch.yml .docker/elasticsearch.* /tmp/elasticsearch/ - -RUN mkdir -p config \ - && cp /tmp/elasticsearch/$ES_TPL config/elasticsearch.yml - -ENV ES_JAVA_OPTS "-Xms1000m -Xmx1000m" diff --git a/.docker/Dockerfile.nginx-drupal b/.docker/Dockerfile.nginx-drupal deleted file mode 100644 index 3af9d20af..000000000 --- a/.docker/Dockerfile.nginx-drupal +++ /dev/null @@ -1,10 +0,0 @@ -# @see https://github.com/dpc-sdp/bay/blob/master/bay/images/Dockerfile.nginx -ARG BAY_IMAGE_VERSION -ARG CLI_IMAGE -FROM ${CLI_IMAGE:-cli} as cli - -FROM "ghcr.io/dpc-sdp/bay/nginx:${BAY_IMAGE_VERSION}" - -ENV WEBROOT=docroot - -COPY --from=cli /app /app diff --git a/.docker/Dockerfile.php b/.docker/Dockerfile.php deleted file mode 100644 index d36d5e056..000000000 --- a/.docker/Dockerfile.php +++ /dev/null @@ -1,8 +0,0 @@ -# @see https://github.com/dpc-sdp/bay/blob/master/bay/images/Dockerfile.php -ARG BAY_IMAGE_VERSION -ARG CLI_IMAGE -FROM ${CLI_IMAGE:-cli} as cli - -FROM ghcr.io/dpc-sdp/bay/php-fpm:${BAY_IMAGE_VERSION} - -COPY --from=cli /app /app diff --git a/.docker/elasticsearch.ci.yml b/.docker/elasticsearch.ci.yml deleted file mode 100644 index b5bcfad63..000000000 --- a/.docker/elasticsearch.ci.yml +++ /dev/null @@ -1,14 +0,0 @@ -cluster.name: "docker-cluster" -network.host: 0.0.0.0 -transport.host: localhost - -discovery.type: single-node -xpack.license.self_generated.type: basic -xpack.security.enabled: false - -path.repo: ["/usr/share/elasticsearch/data/snapshots"] - -http.cors.enabled: true -http.cors.allow-origin: "*" -http.cors.allow-methods : OPTIONS, HEAD, GET -http.cors.allow-headers : X-Requested-With, X-Auth-Token, Content-Type, Content-Length diff --git a/.docker/elasticsearch.yml b/.docker/elasticsearch.yml deleted file mode 100644 index bcdc1d195..000000000 --- a/.docker/elasticsearch.yml +++ /dev/null @@ -1,13 +0,0 @@ -cluster.name: "docker-cluster" -network.host: 0.0.0.0 - -discovery.type: single-node -xpack.license.self_generated.type: basic -xpack.security.enabled: false - -path.repo: ["/usr/share/elasticsearch/data/snapshots"] - -http.cors.enabled: true -http.cors.allow-origin: "*" -http.cors.allow-methods : OPTIONS, HEAD, GET -http.cors.allow-headers : X-Requested-With, X-Auth-Token, Content-Type, Content-Length diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 7b0657504..000000000 --- a/.dockerignore +++ /dev/null @@ -1,11 +0,0 @@ -.circleci -.git -.idea -*.md -docker-compose* -screenshots -node_modules -vendor -/composer.build.lock -/composer.lock -docroot diff --git a/.env b/.env deleted file mode 100644 index 092eb528e..000000000 --- a/.env +++ /dev/null @@ -1,62 +0,0 @@ -## -# File with per-project environment variables. -# -# It is used by Ahoy and other scripts to read default values. -# -# The values must be scalar (cannot be another variable). This file must have -# at least 1 valid (exportable) assignment of value. -# -# You may create .env.local file and store your local environment variables -# there - it will also be loaded by Ahoy and it is excluded from git. -# -# This file may be left as is to assume default values specified in .ahoy.yml. - -# Project name. -# Defaults to the name of the current directory. -# PROJECT_NAME=mysite - -# Docker Compose project name. -# All containers will have this prefix. -# Defaults to $PROJECT_NAME -# COMPOSE_PROJECT_NAME=mysite - -# Drupal module prefix for site-specific modules. -# DRUPAL_MODULE_PREFIX=mysite - -# Path to the root of the project inside of the container. -# APP=/app - -# Path to the site installation relative to the current directory. -# WEBROOT=docroot - -# Local development URL. -# Make sure that there is no trailing slash in the value. -# Defaults to http://.docker.amazee.io -# LOCALDEV_URL=http://mysite.docker.amazee.io - -# Database connection details. -# MYSQL_HOST=mariadb -# MYSQL_PORT=3306 - -# Change to composer.json for site build. -COMPOSER=composer.build.json - -# Uncomment this for site build and set the profile name. -# DRUPAL_PROFILE= - -# Uncomment to run the build in suggest mode. -# In this mode, modules from "suggested" part of composer.json will be -# installed. -# INSTALL_SUGGEST=1 - -# Uncomment to install brand new site. -INSTALL_NEW_SITE=1 - -# Uncomment to refresh search API on deployment. -# DRUPAL_REFRESH_SEARCHAPI=1 - -# Uncomment and add comma-separated list of targets (no spaces). -# PHPCS_TARGETS="src,tests" - -# Uncomment below if Bay integration is enabled. -# BAY_INTEGRATION_ENABLED=1 diff --git a/Brewfile b/Brewfile deleted file mode 100644 index 0b8e8ea44..000000000 --- a/Brewfile +++ /dev/null @@ -1,8 +0,0 @@ -tap "caskroom/cask" -tap "homebrew/bundle" -tap "homebrew/core" -tap "homebrew/php" -brew "docker" -brew "gpatch" -brew "nvm" -cask "docker" diff --git a/composer.dev.json b/composer.dev.json deleted file mode 100644 index 875ffc315..000000000 --- a/composer.dev.json +++ /dev/null @@ -1,482 +0,0 @@ -{ - "name": "myorg/mysite", - "description": "Drupal 8 site for MYSITE", - "license": "proprietary", - "require": { - "composer/installers": "^1.9", - "cweagans/composer-patches": "^1.6.0", - "drupal/core-composer-scaffold": "^11.0", - "drupal/core": "10.6.x", - "drupal/core-recommended": "10.6.x", - "drush/drush": "^13", - "vlucas/phpdotenv": "^4.1", - "webflo/drupal-finder": "^1.0" - }, - "require-dev": { - "behat/behat": "~3.5", - "behat/mink": "^1.11", - "behat/mink-browserkit-driver": "^2.2", - "behat/mink-selenium2-driver": "^1.4", - "chi-teck/drupal-code-generator": "^3.0", - "squizlabs/php_codesniffer": "3.7.1", - "dealerdirect/phpcodesniffer-composer-installer": "^0.7", - "doctrine/persistence": "^3.3", - "drupal/coder": "^8.3.10", - "drupal/drupal-extension": "^5.0.0rc1", - "drevops/behat-screenshot": "^1.0", - "drevops/behat-steps": "^1.2.0", - "phpcompatibility/php-compatibility": "^9.1", - "imbo/behat-api-extension": "^6.0", - "symfony/filesystem": "^6.2", - "php-http/curl-client": "*", - "phpunit/phpunit": "^8.5.14 || ^9", - "drupal/core-dev":"10.6.x", - "phpspec/prophecy-phpunit":"^2", - "weitzman/drupal-test-traits": "^1.5", - "php-http/message": "~1.13", - "php-http/message-factory": "^1.1", - "guzzlehttp/psr7": "~2.8.0", - "dpc-sdp/tide_test": "^4.0.0", - "drupal/test_helpers": "^1.2" - }, - "provide": { - "drupal/ckeditor": "*" - }, - "autoload": { - "psr-4": { - "Tide\\Tests\\Context\\": "tests/behat/bootstrap/" - }, - "classmap": [ - "scripts/composer/" - ] - }, - "prefer-stable": true, - "minimum-stability": "dev", - "config": { - "process-timeout": 0, - "sort-packages": true, - "allow-plugins": { - "composer/installers": true, - "oomphinc/composer-installers-extender": true, - "drupal/*": true, - "cweagans/composer-patches": true, - "zaporylie/composer-drupal-optimizations": false, - "dealerdirect/phpcodesniffer-composer-installer": true, - "php-http/discovery": true, - "phpstan/extension-installer": true - } - }, - "repositories": { - "drupal": { - "type": "composer", - "url": "https://packages.drupal.org/8", - "exclude": ["drupal/token_conditions", "drupal/create_menus_permission"] - }, - "asset-packagist": { - "type": "composer", - "url": "https://asset-packagist.org" - }, - "dpc-sdp/tide": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide.git" - }, - "drupal/create_menus_permission": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/create_menus_permission.git" - }, - "dpc-sdp/tide_alert": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_alert.git" - }, - "dpc-sdp/tide_api": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_api.git" - }, - "dpc-sdp/tide_authenticated_content": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_authenticated_content.git" - }, - "dpc-sdp/tide_core": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_core.git" - }, - "dpc-sdp/tide_data_driven_component": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_data_driven_component.git" - }, - "dpc-sdp/tide_demo_content": { - "url": "https://github.com/dpc-sdp/tide_demo_content.git", - "type": "vcs", - "no-api": true - }, - "dpc-sdp/tide_event": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_event.git" - }, - "dpc-sdp/tide_event_atdw": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_event_atdw.git" - }, - "dpc-sdp/tide_grant": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_grant.git" - }, - "dpc-sdp/tide_landing_page": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_landing_page.git" - }, - "dpc-sdp/tide_media": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_media.git" - }, - "dpc-sdp/tide_monsido": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_monsido.git" - }, - "dpc-sdp/tide_page": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_page.git" - }, - "dpc-sdp/tide_profile": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_profile.git" - }, - "dpc-sdp/tide_publication": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_publication.git" - }, - "dpc-sdp/tide_news": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_news.git" - }, - "dpc-sdp/tide_search": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_search.git" - }, - "dpc-sdp/tide_site": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_site.git" - }, - "dpc-sdp/tide_test": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_test.git" - }, - "dpc-sdp/tide_webform": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/tide_webform.git" - }, - "library/dropzone": { - "type": "package", - "package": { - "name": "library/dropzone", - "version": "4.3.0", - "type": "drupal-library", - "dist": { - "url": "https://github.com/enyo/dropzone/archive/v4.3.0.zip", - "type": "zip" - } - } - }, - "ckeditor.autogrow": { - "_webform": true, - "type": "package", - "package": { - "name": "ckeditor/autogrow", - "version": "4.16.1", - "type": "drupal-library", - "dist": { - "url": "https://download.ckeditor.com/autogrow/releases/autogrow_4.16.1.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "ckeditor.codemirror": { - "_webform": true, - "type": "package", - "package": { - "name": "ckeditor/codemirror", - "version": "v1.17.12", - "type": "drupal-library", - "dist": { - "url": "https://github.com/w8tcha/CKEditor-CodeMirror-Plugin/releases/download/v1.17.12/CKEditor-CodeMirror-Plugin.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "ckeditor.image": { - "_webform": true, - "type": "package", - "package": { - "name": "ckeditor/image", - "version": "4.16.1", - "type": "drupal-library", - "dist": { - "url": "https://download.ckeditor.com/image/releases/image_4.16.1.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "ckeditor.link": { - "_webform": true, - "type": "package", - "package": { - "name": "ckeditor/link", - "version": "4.16.1", - "type": "drupal-library", - "dist": { - "url": "https://download.ckeditor.com/link/releases/link_4.16.1.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "ckeditor/templates": { - "type": "package", - "package": { - "name": "ckeditor/templates", - "type": "drupal-library", - "version": "4.11.1", - "dist": { - "type": "zip", - "url": "https://download.ckeditor.com/templates/releases/templates_4.11.1.zip" - } - } - }, - "jquery.timepicker": { - "_webform": true, - "type": "package", - "package": { - "name": "jquery/timepicker", - "version": "1.14.0", - "type": "drupal-library", - "extra": { - "installer-name": "jquery.timepicker" - }, - "dist": { - "url": "https://github.com/jonthornton/jquery-timepicker/archive/refs/tags/1.14.0.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "jquery.textcounter": { - "_webform": true, - "type": "package", - "package": { - "name": "jquery/textcounter", - "version": "0.9.1", - "type": "drupal-library", - "extra": { - "installer-name": "jquery.textcounter" - }, - "dist": { - "url": "https://github.com/ractoon/jQuery-Text-Counter/archive/0.9.1.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "choices": { - "_webform": true, - "type": "package", - "package": { - "name": "choices/choices", - "version": "9.0.1", - "type": "drupal-library", - "extra": { - "installer-name": "choices" - }, - "dist": { - "url": "https://github.com/jshjohnson/Choices/archive/v9.0.1.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "codemirror": { - "_webform": true, - "type": "package", - "package": { - "name": "codemirror/codemirror", - "version": "5.65.12", - "type": "drupal-library", - "extra": { - "installer-name": "codemirror" - }, - "dist": { - "url": "https://github.com/components/codemirror/archive/5.65.12.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "jquery.inputmask": { - "_webform": true, - "type": "package", - "package": { - "name": "jquery/inputmask", - "version": "5.0.8", - "type": "drupal-library", - "extra": { - "installer-name": "jquery.inputmask" - }, - "dist": { - "url": "https://github.com/RobinHerbots/jquery.inputmask/archive/5.0.8.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "jquery.intl-tel-input": { - "_webform": true, - "type": "package", - "package": { - "name": "jquery/intl-tel-input", - "version": "17.0.19", - "type": "drupal-library", - "extra": { - "installer-name": "jquery.intl-tel-input" - }, - "dist": { - "url": "https://github.com/jackocnr/intl-tel-input/archive/v17.0.19.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "progress-tracker": { - "_webform": true, - "type": "package", - "package": { - "name": "progress-tracker/progress-tracker", - "version": "2.0.7", - "type": "drupal-library", - "extra": { - "installer-name": "progress-tracker" - }, - "dist": { - "url": "https://github.com/NigelOToole/progress-tracker/archive/refs/tags/2.0.7.zip", - "type": "zip" - }, - "require": { - "composer/installers": "~1.0" - } - } - }, - "drupal/token_conditions": { - "type": "vcs", - "no-api": true, - "url": "https://github.com/dpc-sdp/token_conditions.git" - } - }, - "scripts": { - "pre-install-cmd": [ - "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" - ], - "pre-update-cmd": [ - "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" - ], - "post-install-cmd": [ - "composer drupal:scaffold", - "DrupalProject\\composer\\ScriptHandler::createRequiredFiles", - "Utilities\\composer\\DrupalSettings::create" - ], - "post-update-cmd": [ - "composer drupal:scaffold", - "DrupalProject\\composer\\ScriptHandler::createRequiredFiles", - "Utilities\\composer\\DrupalSettings::create" - ] - }, - "extra": { - "drupal-scaffold": { - "allowed-packages": [ - "drupal/core" - ], - "file-mapping": { - "[web-root]/robots.txt": false - }, - "locations": { - "web-root": "./docroot" - } - }, - "enable-patching": true, - "composer-exit-on-patch-failure": true, - "installer-paths": { - "docroot/core": [ - "type:drupal-core" - ], - "docroot/modules/contrib/{$name}": [ - "type:drupal-module" - ], - "docroot/themes/contrib/{$name}": [ - "type:drupal-theme" - ], - "docroot/profiles/contrib/{$name}": [ - "type:drupal-profile" - ], - "docroot/libraries/{$name}": [ - "type:drupal-library" - ], - "drush/contrib/{$name}": [ - "type:drupal-drush" - ] - }, - "preserve-paths": [ - "docroot/modules/custom", - "docroot/themes/custom", - "docroot/drush", - "docroot/sites/default/settings.php", - "docroot/sites/default/default.settings.local.php", - "docroot/sites/default/default.services.local.yml", - "docroot/sites/default/settings.local.php", - "docroot/sites/default/services.local.yml", - "docroot/sites/default/files", - "docroot/robots.txt", - "docroot/.htaccess" - ] - } -} diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 5ea841ded..000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,172 +0,0 @@ -# Docker Compose configuration file. -# -# - Using a single file to work in local, CI and production environments. -# - Local overrides are possible using docker-composer.override.yml file. -# - Use inline comments starting with ### to have the line removed in CI. -version: '2.3' - -x-bay-image-version: - &bay-image-version ${BAY_IMAGE_VERSION:-6.x} - -x-project: - &project ${PROJECT_NAME:-mysite} - -x-volumes: - &default-volumes - # Understanding host mounting in Docker-based projects. - # - # To share application code between services (containers), Docker uses volumes. - # When used in non-development environments, containers have access to - # the same shared files using volumes and these volumes do not need to be - # mounted from the host. But for development environment, when the code - # constantly changes on the host, we need to have these changes synchronized - # into all containers. Since we are using single `docker-compose.yml` file for - # all environments, we have to accommodate both cases, so we are specifying an - # override for the same directory as a mounted volume as a commented-out lines, - # which will be automatically uncommented in CI. - # - # See Docker Compose reference about volumes https://docs.docker.com/compose/compose-file/compose-file-v2/#volume-configuration-reference - volumes: - - .:/app:${VOLUME_FLAGS:-delegated} ### Local overrides to mount host filesystem. Automatically removed in CI and PROD. - - ./docroot/sites/default/files:/app/docroot/sites/default/files:${VOLUME_FLAGS:-delegated} ### Local overrides to mount host filesystem. Automatically removed in CI and PROD. - ##- app:/app - ##- files:/app/docroot/sites/default/files - -x-environment: - &default-environment - LAGOON_PROJECT: *project - # Local dev URL populated from the environment. Do not override here. Instead, - # specify the value in .env file. - LAGOON_LOCALDEV_URL: ${LOCALDEV_URL:-http://mysite.docker.amazee.io} - LAGOON_ROUTE: ${LOCALDEV_URL:-http://mysite.docker.amazee.io} - GITHUB_TOKEN: ${GITHUB_TOKEN:-} - BAY_KEY: ${BAY_KEY:-} - BAY_IMAGE_VERSION: ${BAY_IMAGE_VERSION:-6.x} - LAGOON_ENVIRONMENT_TYPE: ${LAGOON_ENVIRONMENT_TYPE:-local} - DRUPAL_REFRESH_SEARCHAPI: ${DRUPAL_REFRESH_SEARCHAPI:-} - # Uncomment to enable Xdebug and then restart via `ahoy up`. - #XDEBUG_ENABLE: "true" - DOCKERHOST: host.docker.internal - # Comment out the above and uncomment the below if you are using Colima rather than Docker Desktop - #DOCKERHOST: 192.168.5.2 - -services: - - cli: - build: - context: . - dockerfile: .docker/Dockerfile.cli - args: - COMPOSER: ${COMPOSER:-composer.json} - BAY_IMAGE_VERSION: *bay-image-version - image: *project - environment: - << : *default-environment - COMPOSER_MEMORY_LIMIT: -1 - << : *default-volumes - labels: - lagoon.type: cli-persistent - lagoon.persistent: /app/docroot/sites/default/files/ - lagoon.persistent.name: nginx-php - - nginx: - build: - context: . - dockerfile: .docker/Dockerfile.nginx-drupal - args: - CLI_IMAGE: *project - BAY_IMAGE_VERSION: *bay-image-version - << : *default-volumes - environment: - << : *default-environment - depends_on: - - cli - labels: - lagoon.type: nginx-php-persistent - lagoon.persistent: /app/docroot/sites/default/files/ - lagoon.persistent.class: slow - lagoon.name: nginx-php - expose: - - "8080" - ports: - - "8888:8080" - - php: - build: - context: . - dockerfile: .docker/Dockerfile.php - args: - CLI_IMAGE: *project - BAY_IMAGE_VERSION: *bay-image-version - environment: - << : *default-environment - << : *default-volumes - depends_on: - - cli - labels: - lagoon.type: nginx-php-persistent - lagoon.persistent: /app/docroot/sites/default/files/ - lagoon.persistent.class: slow - lagoon.name: nginx-php - - mariadb: - image: "ghcr.io/dpc-sdp/bay/mariadb:${BAY_IMAGE_VERSION:-6.x}" - environment: - << : *default-environment - ports: - - "3306" # Find port on host with `ahoy info` or `docker-compose port mariadb 3306` - labels: - lagoon.type: mariadb-shared - - redis: - image: amazeeio/redis - labels: - lagoon.type: redis - - elasticsearch: - build: - context: . - dockerfile: .docker/Dockerfile.elasticsearch - args: - ES_TPL: ${ES_TPL:-elasticsearch.yml} - BAY_IMAGE_VERSION: *bay-image-version - ports: - - "9200:9200" - labels: - lagoon.type: none - - chrome: - image: seleniarm/standalone-chromium:101.0 - shm_size: '1gb' - environment: - <<: *default-environment - <<: *default-volumes - depends_on: - - cli - labels: - lagoon.type: none - - clamav: - image: "clamav/clamav-debian:stable" - environment: - <<: *default-environment - ports: - - "3310" - labels: - lagoon.type: none - - proxy: - image: caddy:latest - ports: - - "${LOCAL_PORT:-80}:80" - volumes: - - $PWD/.docker:/etc/caddy - - $PWD/.docker/Caddyfile:/etc/caddy/Caddyfile - -networks: - amazeeio-network: - external: true - -volumes: - app: {} - files: {} diff --git a/scripts/bay-deploy.sh b/scripts/bay-deploy.sh deleted file mode 100755 index f3a256df8..000000000 --- a/scripts/bay-deploy.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -BAY_ENDPOINT_DEPLOY=http://rest2tasks-lagoon-master.lagoon.vicsdp.amazee.io/deploy -BAY_BRANCH=${BAY_BRANCH:-$1} - -bay_project=$(awk '$1=="project:"{print $2}' .lagoon.yml) - -if [ -z $BAY_BRANCH ]; then - BAY_BRANCH=$(git symbolic-ref --short -q HEAD) -fi - -branch_sha=$(git ls-remote origin | grep refs/heads/${BAY_BRANCH} | cut -f 1) -[ -z $branch_sha ] && echo "ERROR: Fetching of the remote failed. Please ensure you are connected to the internet and have sufficient permissions to access the repository." && exit 1 - -echo "Project: $bay_project" -echo "Branch: $BAY_BRANCH" -echo "SHA: $branch_sha" - -curl -X POST -d projectName=${bay_project} -d sha=${branch_sha} -d branchName=${BAY_BRANCH} ${BAY_ENDPOINT_DEPLOY} diff --git a/scripts/composer-merge.sh b/scripts/composer-merge.sh deleted file mode 100755 index 4852be303..000000000 --- a/scripts/composer-merge.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -## -# Build composer config file from current and dev composer files. -# -# @note: Composer merge plugin does not merge all sections, so we are using jq. -# -set -e - -COMPOSER_BUILD=${COMPOSER_BUILD:-composer.build.json} -COMPOSER_DEV=${COMPOSER_DEV:-composer.dev.json} - -echo "==> Create a build composer file" -# @note: gojq needs to exist on host as the merging of Composer config is running -# before containers are started. -cat <<< "$(gojq -s --indent 4 -M 'def merge(a;b): - reduce b[] as $item (a; - reduce ($item | keys[]) as $key (.; - $item[$key] as $val | ($val | type) as $type | .[$key] = if ($type == "object") then - merge({}; [if .[$key] == null then {} else .[$key] end, $val]) - elif ($type == "array") then - (.[$key] + $val | unique) - else - $val - end) - ); - merge({}; .)' composer.json $COMPOSER_DEV )" > ${COMPOSER_BUILD} diff --git a/scripts/composer/DrupalSettings.php b/scripts/composer/DrupalSettings.php deleted file mode 100644 index 433230376..000000000 --- a/scripts/composer/DrupalSettings.php +++ /dev/null @@ -1,216 +0,0 @@ -locateRoot(getcwd()); - $drupalRoot = $drupalFinder->getDrupalRoot(); - - $standard_settings_file = $drupalRoot . '/sites/default/settings.php'; - $generated_settings_file_name = 'settings.generated.php'; - - $defaults = [ - 'mysql_database' => 'drupal', - 'mysql_user' => 'drupal', - 'mysql_password' => 'drupal', - 'mysql_host' => 'localhost', - 'mysql_port' => '', - 'mysql_prefix' => '', - 'settings_path' => $drupalRoot . '/sites/default/' . $generated_settings_file_name, - ]; - - $options = self::extractEnvironmentVariables(array_keys($defaults)) - + self::extractCliOptions($event->getArguments(), array_keys($defaults)) - + $defaults; - - if (!$fs->exists($options['settings_path'])) { - $content = self::getDefaultDrupalSettingsContent($options); - $fs->dumpFile($options['settings_path'], $content); - $fs->chmod($options['settings_path'], 0644); - $event->getIO()->write(sprintf('Created file %s with chmod 0644', $options['settings_path'] . PHP_EOL . $content)); - } - else { - $event->getIO()->write(sprintf('Skipping creation of Drupal settings file "%s" - file already exists', $options['settings_path'])); - } - - // Add inclusion of this file to standard settings file if it exists and - // such inclusion has not been added previously. - if ($fs->exists($options['settings_path']) && $fs->exists($standard_settings_file)) { - if (strpos(file_get_contents($standard_settings_file), $generated_settings_file_name) === FALSE) { - $string = <<getIO()->write(sprintf('Added inclusion of generated settings file %s to %s', $generated_settings_file_name, $standard_settings_file)); - } - else { - $event->getIO()->write(sprintf('Skipped inclusion of generated settings file %s to %s - inclusion already present', $generated_settings_file_name, $standard_settings_file)); - } - } - } - - /** - * Delete Drupal settings file. - */ - public static function delete(Event $event) { - $defaults = [ - 'settings_path' => 'docroot/sites/default/settings.generated.php', - ]; - - $options = self::extractEnvironmentVariables(array_keys($defaults)) - + self::extractCliOptions($event->getArguments(), array_keys($defaults)) - + $defaults; - - $fs = new Filesystem(); - if (!$fs->exists($options['settings_path'])) { - $event->getIO()->write('Skipping deletion of Drupal settings file - file does not exists'); - } - else { - $fs->remove($options['settings_path']); - $event->getIO()->write(sprintf('Deleted file %s', $options['settings_path'])); - } - } - - /** - * Return content for default Drupal settings file. - */ - protected static function getDefaultDrupalSettingsContent($options) { - return << - [ - 'default' => - [ - 'database' => '${options['mysql_database']}', - 'username' => '${options['mysql_user']}', - 'password' => '${options['mysql_password']}', - 'host' => '${options['mysql_host']}', - 'port' => '${options['mysql_port']}', - 'driver' => 'mysql', - 'prefix' => '${options['mysql_prefix']}', - ], - ], -]; - -// Allow installing extensions under tests directory. -\$settings['extension_discovery_scan_tests'] = TRUE; - -FILE; - } - - /** - * Extract options from environment variables. - * - * @param bool|array $allowed - * Array of allowed options. - * - * @return array - * Array of extracted options. - */ - protected static function extractEnvironmentVariables(array $allowed) { - $options = []; - - $dotenv = Dotenv::createImmutable(__DIR__ . '/../..'); - $dotenv->load(); - - foreach ($allowed as $name) { - $value = getenv(strtoupper($name)); - if ($value !== FALSE) { - $options[$name] = $value; - } - } - - return $options; - } - - /** - * Extract options from CLI arguments. - * - * @param array $arguments - * Array of arguments. - * @param bool|array $allowed - * Array of allowed options. - * - * @return array - * Array of extracted options. - */ - protected static function extractCliOptions(array $arguments, array $allowed) { - $options = []; - - foreach ($arguments as $argument) { - if (strpos($argument, '--') === 0) { - [$name, $value] = explode('=', $argument); - $name = substr($name, strlen('--')); - $options[$name] = $value; - if (array_key_exists($name, $allowed) && !is_null($value)) { - $options[$name] = $value; - } - } - } - - return $options; - } - - /** - * Appends content to an existing file. - * - * Polyfill for older versions of Filesystem shipped with Composer phar. - * - * @param string $filename - * The file to which to append content. - * @param string $content - * The content to append. - * - * @throws \Symfony\Component\Filesystem\Exception\IOException - * If the file is not writable. - */ - protected static function appendToFile($filename, $content) { - $fs = new Filesystem(); - - $dir = \dirname($filename); - - if (!is_dir($dir)) { - $fs->mkdir($dir); - } - - if (!is_writable($dir)) { - throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, NULL, $dir); - } - - if (FALSE === @file_put_contents($filename, $content, FILE_APPEND)) { - throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, NULL, $filename); - } - } - -} diff --git a/scripts/composer/ScriptHandler.php b/scripts/composer/ScriptHandler.php deleted file mode 100644 index ec5d7585d..000000000 --- a/scripts/composer/ScriptHandler.php +++ /dev/null @@ -1,138 +0,0 @@ -locateRoot(getcwd()); - $drupalRoot = $drupalFinder->getDrupalRoot(); - - $dirs = [ - 'modules', - 'profiles', - 'themes', - ]; - - // Required for unit testing. - foreach ($dirs as $dir) { - if (!$fs->exists($drupalRoot . '/' . $dir)) { - $fs->mkdir($drupalRoot . '/' . $dir); - $fs->touch($drupalRoot . '/' . $dir . '/.gitkeep'); - } - } - - // Prepare the settings file for installation. - if ($fs->exists($drupalRoot . '/sites/default/default.settings.php') && !$fs->exists($drupalRoot . '/sites/default/settings.php')) { - $fs->copy($drupalRoot . '/sites/default/default.settings.php', $drupalRoot . '/sites/default/settings.php'); - $event->getIO()->write('Created a sites/default/settings.php file'); - } - - if (!$fs->exists($drupalRoot . '/sites/default/settings.php')) { - $event->getIO()->writeError('Settings file not found'); - exit(1); - } - - $fs->chmod($drupalRoot . '/sites/default', 0777); - $fs->chmod($drupalRoot . '/sites/default/settings.php', 0666); - - $configPath = Path::makeRelative($drupalFinder->getComposerRoot() . '/config/default', $drupalRoot); - $settings_string = <<exists($drupalRoot . '/sites/default/files')) { - $oldmask = umask(0); - $fs->mkdir($drupalRoot . '/sites/default/files', 0777); - umask($oldmask); - $event->getIO()->write('Created a sites/default/files directory with chmod 0777'); - } - } - - /** - * Checks if the installed version of Composer is compatible. - * - * Composer 1.0.0 and higher consider a `composer install` without having a - * lock file present as equal to `composer update`. We do not ship with a lock - * file to avoid merge conflicts downstream, meaning that if a project is - * installed with an older version of Composer the scaffolding of Drupal will - * not be triggered. We check this here instead of in drupal-scaffold to be - * able to give immediate feedback to the end user, rather than failing the - * installation after going through the lengthy process of compiling and - * downloading the Composer dependencies. - * - * @see https://github.com/composer/composer/pull/5035 - */ - public static function checkComposerVersion(Event $event) { - $composer = $event->getComposer(); - $io = $event->getIO(); - - $version = $composer::VERSION; - - // The dev-channel of composer uses the git revision as version number, - // try to the branch alias instead. - if (preg_match('/^[0-9a-f]{40}$/i', $version)) { - $version = $composer::BRANCH_ALIAS_VERSION; - } - - // If Composer is installed through git we have no easy way to determine if - // it is new enough, just display a warning. - if ($version === '@package_version@' || $version === '@package_branch_alias_version@') { - $io->writeError('You are running a development version of Composer. If you experience problems, please update Composer to the latest stable version.'); - } - elseif (Comparator::lessThan($version, '1.0.0')) { - $io->writeError('Drupal-project requires Composer version 1.0.0 or higher. Please update your Composer before continuing.'); - exit(1); - } - } - - /** - * Appends content to an existing file. - * - * Polyfill for older versions of Filesystem shipped with Composer phar. - * - * @param string $filename - * The file to which to append content. - * @param string $content - * The content to append. - * - * @throws \Symfony\Component\Filesystem\Exception\IOException - * If the file is not writable. - */ - protected static function appendToFile($filename, $content) { - $fs = new Filesystem(); - - $dir = \dirname($filename); - - if (!is_dir($dir)) { - $fs->mkdir($dir); - } - - if (!is_writable($dir)) { - throw new \Exception(sprintf('Unable to write to the "%s" directory.', $dir), 0, NULL, $dir); - } - - if (FALSE === @file_put_contents($filename, $content, FILE_APPEND)) { - throw new \Exception(sprintf('Failed to write file "%s".', $filename), 0, NULL, $filename); - } - } - -} diff --git a/scripts/doctor.sh b/scripts/doctor.sh deleted file mode 100755 index 1e0f50abf..000000000 --- a/scripts/doctor.sh +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env bash -# -# Check Dev Tools project requirements. -# - -LOCALDEV_URL=${LOCALDEV_URL:-http://mysite.docker.amazee.io/} - -################################################################################ -#################### DO NOT CHANGE ANYTHING BELOW THIS LINE #################### -################################################################################ - -# -# Main entry point. -# -main() { - # Check project requirements. - status "Checking project requirements" - - [ $(command_exists docker) == "1" ] && error "Please install Docker." && exit 1 - [ $(command_exists docker-compose) == "1" ] && error "Please install docker-compose." && exit 1 - [ $(command_exists composer) == "1" ] && error "Please install composer: visit https://getcomposer.org/" && exit 1 - [ $(command_exists nvm) == "1" ] && error "Please install nvm" && exit 1 - [ $(command_exists pygmy) == "1" ] && error "Please install pygmy" && exit 1 - - [ ! ~/.bash_profile ] && error " ~/.bash_profile does not exist. Run 'touch ~/.bash_profile && source ~/.bashrc'" && exit 1 - - # Check what is listening on port 80. - if ! lsof -i :80 | grep -q LISTEN; then - error "Nothing is listening on port 80. Run 'pygmy up' to start pygmy." && exit 1 - elif ! lsof -i :80 | grep LISTEN | grep -q om.docke; then - error "Port 80 is occupied by other service. Stop this service and run 'pygmy up'" - else - pygmy_status=$(pygmy status) - [ "$?" == "1" ] && error "pygmy is not running. Run 'pygmy up' to start pygmy." && exit 1 - # @todo: Add more checks for pygmy's services. - fi - - docker exec -i $(docker-compose ps -q cli) bash -c "ssh-add -L|grep -vq 'ssh-rsa'" && error "SSH key was not added into container. Run 'pygmy restart'." - - curl -L -s -o /dev/null -w "%{http_code}" $LOCALDEV_URL | grep -q -v 200 && error "Unable to access $LOCALDEV_URL" && exit 1 - - if curl -L -s -N $LOCALDEV_URL | grep -q "name=\"Generator\" content=\"Drupal 8"; then - success "Successfully bootstrapped $LOCALDEV_URL" - else - error "Website is running, but cannot be bootstrapped. Try pulling latest container images with 'composer bay:pull'" && exit 1 - fi -} - -# -# Check that command exists. -# -command_exists() { - local cmd=$1 - command -v $cmd | grep -ohq $cmd - local res=$? - - # Try homebrew lookup. - if [ "$res" == "1" ] ; then - brew --prefix $cmd > /dev/null - res=$? - fi - - echo $res -} - -# -# Status echo. -# -status() { - cecho blue "==> $1"; -} - -# -# Success echo. -# -success() { - cecho green "✓ $1"; -} - -# -# Error echo. -# -error() { - cecho red "✘ $1"; -} - -# -# Colored echo. -# -cecho() { - local prefix="\033[" - local input_color=$1 - local message="$2" - - local color="" - case "$input_color" in - black | bk) color="${prefix}0;30m";; - red | r) color="${prefix}1;31m";; - green | g) color="${prefix}1;32m";; - yellow | y) color="${prefix}1;33m";; - blue | b) color="${prefix}1;34m";; - purple | p) color="${prefix}1;35m";; - cyan | c) color="${prefix}1;36m";; - gray | gr) color="${prefix}0;37m";; - *) message="$1" - esac - - # Format message with color codes, but only if a correct color was provided. - [ -n "$color" ] && message="${color}${message}${prefix}0m" - - echo -e "$message" -} - -main "$@" diff --git a/scripts/drupal-init-module.sh b/scripts/drupal-init-module.sh deleted file mode 100755 index 8d3f6b0e0..000000000 --- a/scripts/drupal-init-module.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash -## -# Install current module. -# -# This script must run from within container. -# -set -e - -PACKAGE_NAME=${PACKAGE_NAME:-} -PACKAGE_ORG=${PACKAGE_ORG:-dpc-sdp} -LOCAL_REPOS=${LOCAL_REPOS:-$PACKAGE_ORG} -INSTALL_SUGGEST=${INSTALL_SUGGEST:-} -COMPOSER=${COMPOSER:-composer.build.json} -APP=${APP:-/app} -WEBROOT=${WEBROOT:-docroot} -TEST_PACKAGE_NAME=${TEST_PACKAGE_NAME:-tide_test} -TEST_PACKAGE_VERSION=${TEST_PACKAGE_VERSION:-^4.0} -URI=${LOCALDEV_URL:-dev} - -echo "==> COMPOSER_MEMORY_LIMIT=$COMPOSER_MEMORY_LIMIT" - -# Extract module name from the *.info.yml file, if not provided. -if [ "$PACKAGE_NAME" == "" ]; then - PACKAGE_NAME=$(find * -maxdepth 0 -name '*.info.yml'|cut -d. -f1) -fi -[ "$PACKAGE_NAME" == "" ] && "ERROR: Package name is not provided" && exit 1 - -if grep -q 'type: module' *.info.yml; then - echo "==> Started $PACKAGE_NAME module installation" -else - echo "Skipping module installation as current project is not a module" - exit 0 -fi - -# Require an additional test package. -[ "${PACKAGE_NAME}" != "${TEST_PACKAGE_NAME}" ] && composer require --prefer-source ${PACKAGE_ORG}/${TEST_PACKAGE_NAME}:${TEST_PACKAGE_VERSION} - -# Require module from local repository. -composer require --prefer-source ${PACKAGE_ORG}/${PACKAGE_NAME}:@dev - -# If running with suggested modules, install them first. -if [ "$INSTALL_SUGGEST" == "1" ] ; then - composer_suggests=$(cat ${COMPOSER} | gojq -r 'select(.suggest != null) | .suggest | keys[]') - for composer_suggest in $composer_suggests - do - echo "==> Requiring suggested module $composer_suggest" - composer require $composer_suggest - done - - drupal_suggests=$(cat ${COMPOSER} | gojq -r 'select(.suggest != null) | .suggest | keys[]' | sed "s/$PACKAGE_ORG\///" | cut -f1 -d":") - for drupal_suggest in $drupal_suggests - do - echo "==> Enabling suggested module $drupal_suggest" - drush -r ${APP}/${WEBROOT} --uri=${URI} en -y $drupal_suggest - done -fi - -drush -r ${APP}/${WEBROOT} --uri=${URI} en -y ${PACKAGE_NAME} - -echo "==> Finished $PACKAGE_NAME module installation" diff --git a/scripts/drupal-init-profile.sh b/scripts/drupal-init-profile.sh deleted file mode 100755 index 57543c603..000000000 --- a/scripts/drupal-init-profile.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -## -# Install current profile. -# -# This script must run from within container. -# -set -e - -PACKAGE_NAME=${PACKAGE_NAME:-} -PACKAGE_ORG=${PACKAGE_ORG:-dpc-sdp} -LOCAL_REPOS=${LOCAL_REPOS:-$PACKAGE_ORG} -INSTALL_SUGGEST=${INSTALL_SUGGEST:-} -COMPOSER=${COMPOSER:-composer.build.json} -APP=${APP:-/app} -WEBROOT=${WEBROOT:-docroot} - -# Extract module name from the *.info.yml file, if not provided. -if [ "$PACKAGE_NAME" == "" ]; then - PACKAGE_NAME=$(find * -maxdepth 0 -name '*.info.yml'|cut -d. -f1) -fi -[ "$PACKAGE_NAME" == "" ] && "ERROR: Package name is not provided" && exit 1 - -echo "==> Started $PACKAGE_NAME profile installation" - -# Require module from local repository. -composer require --prefer-source ${PACKAGE_ORG}/${PACKAGE_NAME}:@dev - -# If running with suggested modules, install suggested modules first. -if [ "$INSTALL_SUGGEST" == "1" ] ; then - composer_suggests=$(cat ${COMPOSER} | gojq -r 'select(.suggest != null) | .suggest | keys[]') - for composer_suggest in $composer_suggests - do - echo "==> Requiring suggested module $composer_suggest" - composer require $composer_suggest - done -fi - -echo "==> Finished $PACKAGE_NAME profile installation" diff --git a/scripts/drupal/import-db.sh b/scripts/drupal/import-db.sh deleted file mode 100755 index beab2ffe7..000000000 --- a/scripts/drupal/import-db.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -## -# Import prod db. -# - -# Clear cache if db found. -echo "==> Searching for Drupal installation" -[[ "$(drush core-status bootstrap --pipe)" != "" ]] && echo "==> Existing Drupal site found" && drush cr -echo "==> Removing existing database tables" -drush sql-drop -y -echo "==> Importing database" -drush sqlc < /tmp/.data/db.sql -drush sqlsan --sanitize-password=DpcFakePass --sanitize-email=user+%uid@localhost -y -# Ensure cache cleared -drush cr diff --git a/scripts/drupal/install-new-site.sh b/scripts/drupal/install-new-site.sh deleted file mode 100755 index 08d529239..000000000 --- a/scripts/drupal/install-new-site.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -## -# Install new Drupal site. -# - -DRUPAL_PROFILE=${DRUPAL_PROFILE:-testing} -DRUPAL_ADMIN_NAME=${DRUPAL_ADMIN_NAME:-admin} -DRUPAL_ADMIN_PASSWORD=${DRUPAL_ADMIN_PASSWORD:-admin} -APP=${APP:-/app} -WEBROOT=${WEBROOT:-docroot} -URI= ${LOCALDEV_URL:-dev} - -drush -r ${APP}/${WEBROOT} si ${DRUPAL_PROFILE} -y --uri=${URI} --account-name=${DRUPAL_ADMIN_NAME} --account-pass=${DRUPAL_ADMIN_PASSWORD} install_configure_form.enable_update_status_module=NULL install_configure_form.enable_update_status_emails=NULL --site-name="Single Digital Presence Content Management System" -drush -r ${APP}/${WEBROOT} ublk --uri=${URI} 1 -drush -r ${APP}/${WEBROOT} cr --uri=${URI} -y -drush -r ${APP}/${WEBROOT} --uri=${URI} php-eval "\$prefix = getenv('DRUPAL_MODULE_PREFIX'); if (\$prefix) { \$loaded = module_load_install(\$prefix . '_core'); if (\$loaded) { \$func = \$prefix . '_core_enable_modules'; \$func(TRUE); } }" diff --git a/scripts/drush-download-db.sh b/scripts/drush-download-db.sh deleted file mode 100755 index 1b9325b78..000000000 --- a/scripts/drush-download-db.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh -## -# Download latest DB backup via drush. -# - -LOCAL_PATH="/tmp/.data/" -DB_FILE_NAME="db.sql" -LOCAL_DB_PATH=$LOCAL_PATH$DB_FILE_NAME -DUMP_PATH="/tmp/$DB_FILE_NAME" - -fetch_db() { - mkdir -p $LOCAL_PATH - drush -y rsync @production:$DUMP_PATH $LOCAL_PATH > /dev/null - echo $? -} - -dump_db() { - drush @production sql-dump --skip-tables-key=common --result-file=$DUMP_PATH > /dev/null - echo $? -} - -if [ ! -f $LOCAL_DB_PATH ]; then - echo "Fetching production DB dump" - fetched=$(fetch_db) - - if [ "$fetched" != "0" ]; then - echo "Creating new production dump" - dumped=$(dump_db) - if [ "$dumped" != "0" ]; then - echo "Unable to dump DB file in production" - exit 1; - fi - - fetched=$(fetch_db) - if [ "$fetched" != "0" ] || [ ! -f $LOCAL_DB_PATH ]; then - echo "Unable to fetch DB dump" - exit 1; - fi - fi -fi - -[ ! -s $LOCAL_DB_PATH ] && rm -r $LOCAL_DB_PATH && "Invalid file size. Please check production DB" && exit 1 diff --git a/scripts/link-package.sh b/scripts/link-package.sh deleted file mode 100755 index 543dacb04..000000000 --- a/scripts/link-package.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -## -# Link current package. -# -# This script must run from within container. -# -set -e - -CUR_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) - -PACKAGE_NAME=${PACKAGE_NAME:-} -PACKAGE_ORG=${PACKAGE_ORG:-dpc-sdp} -LOCAL_REPOS=${LOCAL_REPOS:-$PACKAGE_ORG} - -# Extract module name from the *.info.yml file, if not provided. -if [ "$PACKAGE_NAME" == "" ]; then - PACKAGE_NAME=$(find * -maxdepth 0 -name '*.info.yml'|cut -d. -f1) -fi -[ "$PACKAGE_NAME" == "" ] && "ERROR: Package name is not provided" && exit 1 - -echo "==> Started $PACKAGE_NAME package linking" - -rm -Rf ${LOCAL_REPOS}/${PACKAGE_NAME} -mkdir -p ${LOCAL_REPOS}/${PACKAGE_NAME} -# Copy code at latest commit into local repository directory, so that it can be -# symlinked as a local package by composer. -git --git-dir=${CUR_DIR}/../.git --work-tree=${CUR_DIR}/.. ls-tree HEAD --name-only | xargs -I '{}' cp -R '{}' ${LOCAL_REPOS}/${PACKAGE_NAME}/ -cp -Rf ${CUR_DIR}/../.git ${LOCAL_REPOS}/${PACKAGE_NAME} - -# Add local package repository to composer configuration. It will by symlinked -# by default, rather then copied. -composer config repositories.${PACKAGE_ORG}/${PACKAGE_NAME} path ${LOCAL_REPOS}/${PACKAGE_NAME} - -echo "==> Finished $PACKAGE_NAME package linking" diff --git a/scripts/rebuild-env.sh b/scripts/rebuild-env.sh deleted file mode 100755 index 083cc9090..000000000 --- a/scripts/rebuild-env.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -## -# Rebuild environment. -# - -# Fetch prod db. -./scripts/drush-download-db.sh - -# Import db. -./scripts/drupal/import-db.sh - -# Deploy drupal. -./scripts/drupal/deploy.sh From 94ba66303bd3ea159d068cae12c90e9a31ea0862 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Sat, 4 Jul 2026 18:13:21 +1000 Subject: [PATCH 04/12] Ignored .phpunit.result.cache. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 49fc5511a..332b7338a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ /dpc-sdp .idea .env.local +.phpunit.result.cache docker-compose.override.yml screenshots vendor From 674bc91b5e1df4d418814911044c69de32734326 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Sat, 4 Jul 2026 18:57:20 +1000 Subject: [PATCH 05/12] Fixed stale TideSiteMenuAutocreateTest expectations for makeMenuName. SD-1341 (44f83b5a) changed makeMenuName() to append term ids and truncate the result to 32 characters, but the test still stubbed only getName(). Stub id() on mocked terms and update the provider to expect id-based, truncated menu names. This was never caught because the legacy CI phpunit suite path (./dpc-sdp/*/tests/src/Unit) did not cover module unit tests. --- .../tests/src/Unit/TideSiteMenuAutocreateTest.php | 11 +++++++---- modules/tide_site/tests/src/Unit/TideSiteTest.php | 5 +++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/modules/tide_site/tests/src/Unit/TideSiteMenuAutocreateTest.php b/modules/tide_site/tests/src/Unit/TideSiteMenuAutocreateTest.php index 7e789293a..621d3cd49 100644 --- a/modules/tide_site/tests/src/Unit/TideSiteMenuAutocreateTest.php +++ b/modules/tide_site/tests/src/Unit/TideSiteMenuAutocreateTest.php @@ -78,14 +78,17 @@ public function testMakeMenuName($menu_title, $parents, $expected) { /** * Data provider to test makeMenuName() method. + * + * Menu names are built from term ids (mocked sequentially from 1, ordered + * from the term to the "oldest" parent) and truncated to 32 characters. */ public function providerMakeMenuName() { return [ ['abc', [], 'site-abc'], - ['abc', ['t1'], 'site-abc-t1'], - ['abc', ['t1', 'p1'], 'site-abc-p1-t1'], - ['abc', ['t1', 'p1', 'p2'], 'site-abc-p2-p1-t1'], - ['abc', ['t1', 'p1 p11', 'p2 p21'], 'site-abc-p2-p21-p1-p11-t1'], + ['abc', ['t1'], 'site-abc-1'], + ['abc', ['t1', 'p1'], 'site-abc-2-1'], + ['abc', ['t1', 'p1', 'p2'], 'site-abc-3-2-1'], + ['a very long menu title indeed', ['t1', 'p1'], 'site-a-very-long-menu-title-inde'], ]; } diff --git a/modules/tide_site/tests/src/Unit/TideSiteTest.php b/modules/tide_site/tests/src/Unit/TideSiteTest.php index 581acc06a..994f5e792 100644 --- a/modules/tide_site/tests/src/Unit/TideSiteTest.php +++ b/modules/tide_site/tests/src/Unit/TideSiteTest.php @@ -14,7 +14,7 @@ abstract class TideSiteTest extends UnitTestCase { * * @param array $parents * Array of term and it's parents names, ordered from term to the "oldest" - * parent. + * parent. Mocked term ids are assigned sequentially starting from 1. * * @return array * Array of mocked term objects. @@ -22,9 +22,10 @@ abstract class TideSiteTest extends UnitTestCase { protected function prepareMockTermParents(array $parents) { $list = []; - foreach ($parents as $name) { + foreach (array_values($parents) as $index => $name) { $mock = self::createMock('\Drupal\taxonomy\Entity\Term'); $mock->method('getName')->willReturn($name); + $mock->method('id')->willReturn((string) ($index + 1)); $list[] = $mock; } From d8e3ef5864383d32221d8888aa47cb707cb642ef Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Sat, 4 Jul 2026 18:57:20 +1000 Subject: [PATCH 06/12] Replaced ahoy-based CI with a DDEV-based GitHub Actions workflow. The tide_build job now provisions the same DDEV environment as local development (start, poser, symlink-project, install-site), lints with phpcs and runs the tide_core unit and Behat suites. Per-module Behat suites and the export_config job are commented out pending follow-up. Also excluded DDEV-generated files from phpcs. --- .github/workflows/build.yml | 80 ++++++++++++++++++++++++++++++++----- phpcs.xml | 1 + 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b1ba3e166..bc02cce24 100755 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,15 +4,77 @@ on: push: workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: tide_build: name: tide_build - secrets: inherit - uses: dpc-sdp/github-actions/.github/workflows/tide_build.yml@v1.6.5 - with: - module_build: true - runner: biggy-tide - export_config: - name: export_config - secrets: inherit - uses: dpc-sdp/github-actions/.github/workflows/export_config.yml@v1.6.5 + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Validate composer configuration + run: composer validate --ansi --strict --no-check-all --no-check-lock + + - name: Install DDEV + uses: ddev/github-action-setup-ddev@v1 + with: + autostart: false + + - name: Start DDEV + run: ddev start -y + + - name: Build Drupal site (poser) + run: ddev poser + + - name: Symlink module into the site + run: ddev symlink-project + + - name: Install site + run: ddev install-site + + - name: Lint code + run: ddev exec vendor/bin/phpcs . + + - name: Run PHPUnit unit tests + run: ddev exec vendor/bin/phpunit --testsuite unit + + - name: Run Behat tests (tide_core) + run: ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' tests + + - name: Upload Behat screenshots + if: failure() + uses: actions/upload-artifact@v4 + with: + name: behat-screenshots + path: screenshots + if-no-files-found: ignore + + # TODO: per-module Behat suites are deferred while the DDEV migration + # settles. Re-enable by uncommenting; the sequence mirrors the legacy + # .circleci/test.sh (progressively enable each module, then run its + # Behat suite). + # + # - name: Run Behat tests (per module) + # run: | + # for m in tide_webform tide_media tide_event tide_grant tide_news tide_landing_page; do + # ddev drush en -y "$m" + # ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' "modules/$m" + # done + # ddev drush en -y tide_site + # ddev exec vendor/bin/behat --strict --colors modules/tide_site + # ddev drush en -y tide_ui_restriction + # ddev exec vendor/bin/behat --strict --colors modules/tide_ui_restriction + # ddev drush en -y tide_api tide_content_collection_ui tide_share_link + # ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_api + + # TODO: export_config previously used the ahoy-based reusable workflow + # (dpc-sdp/github-actions/.github/workflows/export_config.yml) and needs a + # DDEV-based rewrite before this branch is merged. + # export_config: + # name: export_config + # secrets: inherit + # uses: dpc-sdp/github-actions/.github/workflows/export_config.yml@v1.6.5 diff --git a/phpcs.xml b/phpcs.xml index e25881ddd..a217b226e 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -15,6 +15,7 @@ */web/* + */\.ddev/* */console/* settings.generated.php */vendor/* From d46f566d238c978b3bf66bb2c2ece5ed7cd01c78 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Sat, 4 Jul 2026 20:21:09 +1000 Subject: [PATCH 07/12] Enabled the full per-module Behat test sequence in CI. --- .github/workflows/build.yml | 63 ++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc02cce24..6d1285c62 100755 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,6 +45,51 @@ jobs: - name: Run Behat tests (tide_core) run: ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' tests + - name: Run Behat tests (tide_webform) + run: | + ddev drush en -y tide_webform + ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_webform + + - name: Run Behat tests (tide_media) + run: | + ddev drush en -y tide_media + ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_media + + - name: Run Behat tests (tide_event) + run: | + ddev drush en -y tide_event + ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_event + + - name: Run Behat tests (tide_grant) + run: | + ddev drush en -y tide_grant + ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_grant + + - name: Run Behat tests (tide_news) + run: | + ddev drush en -y tide_news + ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_news + + - name: Run Behat tests (tide_landing_page) + run: | + ddev drush en -y tide_landing_page + ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_landing_page + + - name: Run Behat tests (tide_site) + run: | + ddev drush en -y tide_site + ddev exec vendor/bin/behat --strict --colors modules/tide_site + + - name: Run Behat tests (tide_ui_restriction) + run: | + ddev drush en -y tide_ui_restriction + ddev exec vendor/bin/behat --strict --colors modules/tide_ui_restriction + + - name: Run Behat tests (tide_api) + run: | + ddev drush en -y tide_api tide_content_collection_ui tide_share_link + ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_api + - name: Upload Behat screenshots if: failure() uses: actions/upload-artifact@v4 @@ -53,24 +98,6 @@ jobs: path: screenshots if-no-files-found: ignore - # TODO: per-module Behat suites are deferred while the DDEV migration - # settles. Re-enable by uncommenting; the sequence mirrors the legacy - # .circleci/test.sh (progressively enable each module, then run its - # Behat suite). - # - # - name: Run Behat tests (per module) - # run: | - # for m in tide_webform tide_media tide_event tide_grant tide_news tide_landing_page; do - # ddev drush en -y "$m" - # ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' "modules/$m" - # done - # ddev drush en -y tide_site - # ddev exec vendor/bin/behat --strict --colors modules/tide_site - # ddev drush en -y tide_ui_restriction - # ddev exec vendor/bin/behat --strict --colors modules/tide_ui_restriction - # ddev drush en -y tide_api tide_content_collection_ui tide_share_link - # ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_api - # TODO: export_config previously used the ahoy-based reusable workflow # (dpc-sdp/github-actions/.github/workflows/export_config.yml) and needs a # DDEV-based rewrite before this branch is merged. From cd0ea416ca6ad24454cccb72f4c49d3fec038b0d Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Sun, 5 Jul 2026 21:58:36 +1000 Subject: [PATCH 08/12] simulate `ahoy build` --- .ddev/commands/host/build | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 .ddev/commands/host/build diff --git a/.ddev/commands/host/build b/.ddev/commands/host/build new file mode 100755 index 000000000..7ab514706 --- /dev/null +++ b/.ddev/commands/host/build @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +## Description: Full rebuild from scratch: wipe web/ and vendor/, then start, poser, symlink-project and install-site. +## Usage: build +## Example: "ddev build" + +set -eu -o pipefail + +cd "${DDEV_APPROOT}" + +# Drupal locks sites/default read-only after install; unlock it so rm can succeed. +if [ -d web/sites/default ]; then + chmod -R u+w web/sites/default +fi +rm -rf web vendor + +ddev start +ddev poser +ddev symlink-project +ddev install-site From 53f24e7d2acb0bd4cfdfd7941f8d0255c6a72f3c Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Tue, 7 Jul 2026 22:18:19 +1000 Subject: [PATCH 09/12] Moved administrator-role-dependent tide_site views to optional config. views.view.media_report and views.view.tide_content_report depend on user.role.administrator, which tide_core only provides as optional config. During a site installation with the tide profile, optional config is deferred to the end of the install, so tide_site's install-time config failed validation with an UnmetDependenciesException. As optional config, the views are imported at the end of installation, after the role exists. Updated tide_site_update_10005/10006/10007 to read the view config from config/optional accordingly. Verified with a fresh 'drush si tide' via the tide repo DDEV build. --- .../{install => optional}/views.view.media_report.yml | 0 .../views.view.tide_content_report.yml | 0 modules/tide_site/tide_site.install | 6 +++--- 3 files changed, 3 insertions(+), 3 deletions(-) rename modules/tide_site/config/{install => optional}/views.view.media_report.yml (100%) rename modules/tide_site/config/{install => optional}/views.view.tide_content_report.yml (100%) diff --git a/modules/tide_site/config/install/views.view.media_report.yml b/modules/tide_site/config/optional/views.view.media_report.yml similarity index 100% rename from modules/tide_site/config/install/views.view.media_report.yml rename to modules/tide_site/config/optional/views.view.media_report.yml diff --git a/modules/tide_site/config/install/views.view.tide_content_report.yml b/modules/tide_site/config/optional/views.view.tide_content_report.yml similarity index 100% rename from modules/tide_site/config/install/views.view.tide_content_report.yml rename to modules/tide_site/config/optional/views.view.tide_content_report.yml diff --git a/modules/tide_site/tide_site.install b/modules/tide_site/tide_site.install index 85b837451..754cddc0c 100644 --- a/modules/tide_site/tide_site.install +++ b/modules/tide_site/tide_site.install @@ -185,7 +185,7 @@ function tide_site_update_10005() { $view = View::load('tide_content_report'); if (!$view) { \Drupal::moduleHandler()->loadInclude('tide_core', 'inc', 'includes/helpers'); - $config_location = [\Drupal::service('extension.list.module')->getPath('tide_site') . '/config/install']; + $config_location = [\Drupal::service('extension.list.module')->getPath('tide_site') . '/config/optional']; $config_read = _tide_read_config('views.view.tide_content_report', $config_location, TRUE); $storage = \Drupal::entityTypeManager()->getStorage('view'); $id = $storage->getIDFromConfigName('views.view.tide_content_report', $storage->getEntityType()->getConfigPrefix()); @@ -228,7 +228,7 @@ function tide_site_update_10006() { } \Drupal::moduleHandler()->loadInclude('tide_core', 'inc', 'includes/helpers'); - $config_location = [\Drupal::service('extension.list.module')->getPath('tide_site') . '/config/install']; + $config_location = [\Drupal::service('extension.list.module')->getPath('tide_site') . '/config/optional']; $view_config = _tide_read_config('views.view.tide_content_report', $config_location, FALSE); if (empty($view_config['display']['default']['display_options']['fields']['view_node'])) { return; @@ -243,7 +243,7 @@ function tide_site_update_10006() { */ function tide_site_update_10007() { \Drupal::moduleHandler()->loadInclude('tide_core', 'inc', 'includes/helpers'); - $config_location = [\Drupal::service('extension.list.module')->getPath('tide_site') . '/config/install']; + $config_location = [\Drupal::service('extension.list.module')->getPath('tide_site') . '/config/optional']; $config_read = _tide_read_config('views.view.media_report', $config_location, TRUE); $has_secure_file = (bool) \Drupal::entityTypeManager() From e2e0e4150979e98f2396ed8ab6fe791e9b00fbcd Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Thu, 30 Jul 2026 15:11:55 +1000 Subject: [PATCH 10/12] fixes test issues and introduce opensearch --- .circleci/test.sh | 54 +++++++++---------- .../elasticsearch/manifest.yaml | 9 ---- .ddev/docker-compose.elasticsearch.yaml | 28 ---------- .ddev/docker-compose.opensearch.yaml | 34 ++++++++++++ .ddev/elasticsearch/config/elasticsearch8.yml | 15 ------ .../docker-compose.elasticsearch8.yaml | 6 --- .ddev/opensearch/Dockerfile | 6 +++ .github/workflows/build.yml | 11 +++- README.md | 2 +- behat.yml | 1 + .../behat/features/media_browser.feature | 3 +- ...ch_connector.cluster.elasticsearch_bay.yml | 4 +- ....dataset_destination.sdp_elasticsearch.yml | 4 +- .../tests/behat/features/search.feature | 20 +++---- tests/behat/bootstrap/TideCommonTrait.php | 23 ++++++++ 15 files changed, 117 insertions(+), 103 deletions(-) delete mode 100644 .ddev/addon-metadata/elasticsearch/manifest.yaml delete mode 100644 .ddev/docker-compose.elasticsearch.yaml create mode 100644 .ddev/docker-compose.opensearch.yaml delete mode 100644 .ddev/elasticsearch/config/elasticsearch8.yml delete mode 100644 .ddev/elasticsearch/docker-compose.elasticsearch8.yaml create mode 100644 .ddev/opensearch/Dockerfile diff --git a/.circleci/test.sh b/.circleci/test.sh index c41028d77..7af5a9b59 100755 --- a/.circleci/test.sh +++ b/.circleci/test.sh @@ -2,35 +2,35 @@ ## # Run tests in CI. # -set -e +set -eu -o pipefail echo "==> Lint code" -ahoy lint +ddev exec vendor/bin/phpcs . echo "==> Run Behat tests" mkdir -p /tmp/artifacts/behat -ahoy cli "./vendor/bin/behat --strict --colors --tags="~@skipped" tests" -ahoy cli "drush en tide_webform -y" -ahoy cli "./vendor/bin/behat --strict --colors --tags="~@skipped" modules/tide_webform" -ahoy cli "drush en tide_media -y" -ahoy cli "drush en tide_media_secure_files -y" -ahoy cli "drush en tide_media_file_overwrite -y" -ahoy cli "./vendor/bin/behat --strict --colors --tags="~@skipped" modules/tide_media" -ahoy cli "drush en tide_event -y" -ahoy cli "./vendor/bin/behat --strict --colors --tags="~@skipped" modules/tide_event" -ahoy cli "drush en tide_grant -y" -ahoy cli "./vendor/bin/behat --strict --colors --tags="~@skipped" modules/tide_grant" -ahoy cli "drush en tide_news -y" -ahoy cli "./vendor/bin/behat --strict --colors --tags="~@skipped" modules/tide_news" -ahoy cli "drush en tide_landing_page -y" -ahoy cli "./vendor/bin/behat --strict --colors --tags="~@skipped" modules/tide_landing_page" -ahoy cli "drush en tide_site -y" -ahoy cli "./vendor/bin/behat --strict --colors modules/tide_site" -ahoy cli "drush en tide_ui_restriction -y" -ahoy cli "./vendor/bin/behat --strict --colors modules/tide_ui_restriction" -ahoy cli "drush en tide_api -y" -ahoy cli "drush en tide_content_collection_ui -y" -ahoy cli "drush en tide_share_link -y" -ahoy cli "./vendor/bin/behat --strict --colors --tags="~@skipped" modules/tide_api" -ahoy cli "drush en tide_external_site_link -y" -ahoy cli "./vendor/bin/behat --strict --colors --tags="~@skipped" modules/tide_external_site_link" +ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' tests +ddev drush en -y tide_webform +ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_webform +ddev drush en -y tide_media +ddev drush en -y tide_media_secure_files +ddev drush en -y tide_media_file_overwrite +ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_media +ddev drush en -y tide_event +ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_event +ddev drush en -y tide_grant +ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_grant +ddev drush en -y tide_news +ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_news +ddev drush en -y tide_landing_page +ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_landing_page +ddev drush en -y tide_site +ddev exec vendor/bin/behat --strict --colors modules/tide_site +ddev drush en -y tide_ui_restriction +ddev exec vendor/bin/behat --strict --colors modules/tide_ui_restriction +ddev drush en -y tide_api +ddev drush en -y tide_content_collection_ui +ddev drush en -y tide_share_link +ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_api +ddev drush en -y tide_external_site_link +ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_external_site_link diff --git a/.ddev/addon-metadata/elasticsearch/manifest.yaml b/.ddev/addon-metadata/elasticsearch/manifest.yaml deleted file mode 100644 index 878c50958..000000000 --- a/.ddev/addon-metadata/elasticsearch/manifest.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: elasticsearch -repository: ddev/ddev-elasticsearch -version: v0.3.3 -install_date: "2026-07-04T17:40:21+10:00" -project_files: - - elasticsearch/ - - docker-compose.elasticsearch.yaml -global_files: [] -removal_actions: [] diff --git a/.ddev/docker-compose.elasticsearch.yaml b/.ddev/docker-compose.elasticsearch.yaml deleted file mode 100644 index 3625600eb..000000000 --- a/.ddev/docker-compose.elasticsearch.yaml +++ /dev/null @@ -1,28 +0,0 @@ -#ddev-generated -services: - elasticsearch: - container_name: ddev-${DDEV_SITENAME}-elasticsearch - hostname: ${DDEV_SITENAME}-elasticsearch - image: ${ELASTICSEARCH_DOCKER_IMAGE:-elasticsearch:7.17.14} - expose: - - "9200" - - "9300" - environment: - - cluster.name=docker-cluster - - discovery.type=single-node - - bootstrap.memory_lock=true - - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - - VIRTUAL_HOST=${DDEV_HOSTNAME} - - HTTP_EXPOSE=9200:9200 - - HTTPS_EXPOSE=9201:9200 - labels: - com.ddev.site-name: ${DDEV_SITENAME} - com.ddev.approot: ${DDEV_APPROOT} - volumes: - - elasticsearch:/usr/share/elasticsearch/data - - ".:/mnt/ddev_config" - healthcheck: - test: ["CMD-SHELL", "curl --fail -s elasticsearch:9200"] - -volumes: - elasticsearch: diff --git a/.ddev/docker-compose.opensearch.yaml b/.ddev/docker-compose.opensearch.yaml new file mode 100644 index 000000000..ec0f47409 --- /dev/null +++ b/.ddev/docker-compose.opensearch.yaml @@ -0,0 +1,34 @@ +# OpenSearch service aligned with the SDP Bay OpenSearch image. +services: + opensearch: + container_name: ddev-${DDEV_SITENAME}-opensearch + hostname: ${DDEV_SITENAME}-opensearch + build: + context: .. + dockerfile: .ddev/opensearch/Dockerfile + args: + BAY_IMAGE_VERSION: ${BAY_IMAGE_VERSION:-6.x} + expose: + - "9200" + environment: + - DISABLE_INSTALL_DEMO_CONFIG=true + - DISABLE_SECURITY_PLUGIN=true + - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" + - VIRTUAL_HOST=${DDEV_HOSTNAME} + - HTTP_EXPOSE=9200:9200 + - HTTPS_EXPOSE=9201:9200 + labels: + com.ddev.site-name: ${DDEV_SITENAME} + com.ddev.approot: ${DDEV_APPROOT} + volumes: + - opensearch:/usr/share/opensearch/data + - ".:/mnt/ddev_config" + healthcheck: + test: ["CMD-SHELL", "curl --fail --silent 'localhost:9200/_cluster/health?wait_for_status=yellow&timeout=5s'"] + + web: + depends_on: + - opensearch + +volumes: + opensearch: diff --git a/.ddev/elasticsearch/config/elasticsearch8.yml b/.ddev/elasticsearch/config/elasticsearch8.yml deleted file mode 100644 index 3a612d3db..000000000 --- a/.ddev/elasticsearch/config/elasticsearch8.yml +++ /dev/null @@ -1,15 +0,0 @@ -#ddev-generated -# This file contains the configuration settings for Elasticsearch 8. -# For more information, see https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html - -# https://www.elastic.co/guide/en/elasticsearch/reference/current/important-settings.html#cluster-name -cluster.name: "docker-cluster" - -# https://www.elastic.co/guide/en/elasticsearch/reference/current/important-settings.html#network.host -network.host: 0.0.0.0 - -# Disable security features -# https://www.elastic.co/guide/en/elasticsearch/reference/current/security-settings.html#general-security-settings -xpack.security.enabled: false -xpack.security.autoconfiguration.enabled: false -xpack.security.enrollment.enabled: false diff --git a/.ddev/elasticsearch/docker-compose.elasticsearch8.yaml b/.ddev/elasticsearch/docker-compose.elasticsearch8.yaml deleted file mode 100644 index 9e864c365..000000000 --- a/.ddev/elasticsearch/docker-compose.elasticsearch8.yaml +++ /dev/null @@ -1,6 +0,0 @@ -#ddev-generated -services: - elasticsearch: - image: ${ELASTICSEARCH_DOCKER_IMAGE:-elasticsearch:8.10.2} - volumes: - - ./elasticsearch/config/elasticsearch8.yml:/usr/share/elasticsearch/config/elasticsearch.yml diff --git a/.ddev/opensearch/Dockerfile b/.ddev/opensearch/Dockerfile new file mode 100644 index 000000000..38c0d1252 --- /dev/null +++ b/.ddev/opensearch/Dockerfile @@ -0,0 +1,6 @@ +ARG BAY_IMAGE_VERSION +FROM "ghcr.io/dpc-sdp/bay/opensearch:${BAY_IMAGE_VERSION}" + +USER root +RUN chown opensearch /usr/share/opensearch/config/opensearch.yml +USER opensearch diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6d1285c62..64d63752b 100755 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,6 +53,8 @@ jobs: - name: Run Behat tests (tide_media) run: | ddev drush en -y tide_media + ddev drush en -y tide_media_secure_files + ddev drush en -y tide_media_file_overwrite ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_media - name: Run Behat tests (tide_event) @@ -87,9 +89,16 @@ jobs: - name: Run Behat tests (tide_api) run: | - ddev drush en -y tide_api tide_content_collection_ui tide_share_link + ddev drush en -y tide_api + ddev drush en -y tide_content_collection_ui + ddev drush en -y tide_share_link ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_api + - name: Run Behat tests (tide_external_site_link) + run: | + ddev drush en -y tide_external_site_link + ddev exec vendor/bin/behat --strict --colors --tags='~@skipped' modules/tide_external_site_link + - name: Upload Behat screenshots if: failure() uses: actions/upload-artifact@v4 diff --git a/README.md b/README.md index e8ebbffd8..0bbacc9f9 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ root take effect immediately, no sync step required. To start the local development stack: 1. Checkout this project. -2. Run `ddev start` — starts web, db, elasticsearch, selenium-chrome and clamav services. +2. Run `ddev start` — starts web, db, OpenSearch, selenium-chrome and clamav services. 3. Run `ddev poser` — installs Drupal core (version pinned by `DRUPAL_CORE` in `.ddev/config.yaml`) plus all module dependencies into `web/` and `vendor/`. 4. Run `ddev symlink-project` — symlinks this module into `web/modules/custom/tide_core` (re-run after adding/removing root-level files; also runs automatically on `ddev start`). 5. Run `ddev install-site` — installs a fresh site (`testing` profile) and enables `tide_core` and `tide_test`. diff --git a/behat.yml b/behat.yml index 8f59a8e53..0c373b42b 100644 --- a/behat.yml +++ b/behat.yml @@ -46,6 +46,7 @@ default: blackbox: ~ api_driver: drupal drush_driver: drush + login_wait: 5 drupal: drupal_root: web drush: diff --git a/modules/tide_media/tests/behat/features/media_browser.feature b/modules/tide_media/tests/behat/features/media_browser.feature index 61696aebe..b29afbacb 100644 --- a/modules/tide_media/tests/behat/features/media_browser.feature +++ b/modules/tide_media/tests/behat/features/media_browser.feature @@ -30,8 +30,7 @@ Feature: Media browser When I click on iFramed element ".views-field-entity-browser-select .form-checkbox" within "entity_browser_iframe_tide_media_browser_iframe" Then I click on iFramed element "#edit-submit" within "entity_browser_iframe_tide_media_browser_iframe" - And I wait for AJAX to finish - Then I should see the text "Embed media item" + And I wait for the dialog title "Embed media item" to appear When I check "Display last update date" Then I click on the element ".ui-dialog-buttonpane .button--primary" diff --git a/modules/tide_search/config/install/elasticsearch_connector.cluster.elasticsearch_bay.yml b/modules/tide_search/config/install/elasticsearch_connector.cluster.elasticsearch_bay.yml index 09c7350cf..4a41e6960 100644 --- a/modules/tide_search/config/install/elasticsearch_connector.cluster.elasticsearch_bay.yml +++ b/modules/tide_search/config/install/elasticsearch_connector.cluster.elasticsearch_bay.yml @@ -2,8 +2,8 @@ langcode: en status: '1' dependencies: { } cluster_id: elasticsearch_bay -name: 'ElasticSearch on Bay' -url: 'http://elasticsearch:9200' +name: 'OpenSearch on Bay' +url: 'http://opensearch:9200' options: multiple_nodes_connection: false use_authentication: 0 diff --git a/modules/tide_search/modules/tide_data_pipeline/config/install/data_pipelines.dataset_destination.sdp_elasticsearch.yml b/modules/tide_search/modules/tide_data_pipeline/config/install/data_pipelines.dataset_destination.sdp_elasticsearch.yml index dfbdf3bc6..3da465fee 100644 --- a/modules/tide_search/modules/tide_data_pipeline/config/install/data_pipelines.dataset_destination.sdp_elasticsearch.yml +++ b/modules/tide_search/modules/tide_data_pipeline/config/install/data_pipelines.dataset_destination.sdp_elasticsearch.yml @@ -2,10 +2,10 @@ langcode: en status: true dependencies: { } id: sdp_elasticsearch -label: 'SDP ElasticSearch' +label: 'SDP OpenSearch' destination: elasticsearch destinationSettings: - url: 'http://elasticsearch:9200' + url: 'http://opensearch:9200' username: null password: null prefix: sdp_data_pipelines_ diff --git a/modules/tide_search/tests/behat/features/search.feature b/modules/tide_search/tests/behat/features/search.feature index e0e65daf4..6f7962426 100644 --- a/modules/tide_search/tests/behat/features/search.feature +++ b/modules/tide_search/tests/behat/features/search.feature @@ -1,24 +1,24 @@ -Feature: Ensure Search API on Bay Elasticsearch work. +Feature: Ensure Search API on Bay OpenSearch works. @api - Scenario: Assert that Elasticsearch configuration exists in Drupal + Scenario: Assert that OpenSearch configuration exists in Drupal Given I am logged in as a user with the "administrator" role When I go to "admin/config/search/elasticsearch-connector" Then I save screenshot - And I should see the text "ElasticSearch on Bay" + And I should see the text "OpenSearch on Bay" When I go to "admin/config/search/search-api" Then I save screenshot - When I visit "http://elasticsearch:9200/_cat/indices?v" + When I visit "http://opensearch:9200/_cat/indices?v" Then the response status code should be 200 And the response should contain "elasticsearch_index_drupal_node" - When I visit "http://elasticsearch:9200/_cat/aliases?v" + When I visit "http://opensearch:9200/_cat/aliases?v" Then the response status code should be 200 And the response should contain "search--elasticsearch-index-drupal-node-alias" - When I send a GET request to "http://elasticsearch:9200/elasticsearch_index_drupal_node/_mapping" + When I send a GET request to "http://opensearch:9200/elasticsearch_index_drupal_node/_mapping" Then the response status code should be 200 And the response should be in JSON And the JSON node "elasticsearch_index_drupal_node" should exist @@ -33,7 +33,7 @@ Feature: Ensure Search API on Bay Elasticsearch work. And the JSON node "elasticsearch_index_drupal_node.mappings.properties.title.fields.prefix.analyzer" should be equal to "i_prefix" @api - Scenario: Assert that Elasticsearch can index content. + Scenario: Assert that OpenSearch can index content. Given topic terms: | name | parent | | Test Topic | 0 | @@ -53,11 +53,11 @@ Feature: Ensure Search API on Bay Elasticsearch work. And I wait for 5 seconds # Published Test content should be in search results. - When I visit "http://elasticsearch:9200/elasticsearch_index_drupal_node/_search?q=title:testtitlepublished" + When I visit "http://opensearch:9200/elasticsearch_index_drupal_node/_search?q=title:testtitlepublished" Then the response status code should be 200 And I save screenshot - When I send a GET request to "http://elasticsearch:9200/elasticsearch_index_drupal_node/_search?q=title:testtitlepublished" + When I send a GET request to "http://opensearch:9200/elasticsearch_index_drupal_node/_search?q=title:testtitlepublished" Then the response status code should be 200 And the response should be in JSON And the JSON node "hits" should exist @@ -77,7 +77,7 @@ Feature: Ensure Search API on Bay Elasticsearch work. And I wait for 5 seconds # Unpublished Test content should not be in search results. - When I send a GET request to "http://elasticsearch:9200/elasticsearch_index_drupal_node/_search?q=title:testtitlepublished" + When I send a GET request to "http://opensearch:9200/elasticsearch_index_drupal_node/_search?q=title:testtitlepublished" Then the response status code should be 200 And the response should be in JSON And the JSON node "hits" should exist diff --git a/tests/behat/bootstrap/TideCommonTrait.php b/tests/behat/bootstrap/TideCommonTrait.php index 3e37a7993..29a2cba98 100644 --- a/tests/behat/bootstrap/TideCommonTrait.php +++ b/tests/behat/bootstrap/TideCommonTrait.php @@ -75,6 +75,29 @@ function isAjaxing(instance) { } } + /** + * Wait for a dialog title to appear. + * + * @Then /^I wait for the dialog title "([^"]*)" to appear$/ + */ + public function waitForDialogTitle(string $title) { + $encoded_title = json_encode($title, JSON_THROW_ON_ERROR); + $condition = <<getMinkParameter('ajax_timeout'); + $result = $this->getSession()->wait($timeout * 1000, $condition); + + if (!$result) { + throw new \RuntimeException(sprintf('Dialog title "%s" did not appear.', $title)); + } + } + /** * @When I scroll :selector into view * @When I scroll selector :selector into view From 5e67c0a043688e1bcb16077276f792cbc4c4d3cc Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Thu, 30 Jul 2026 15:36:53 +1000 Subject: [PATCH 11/12] Fixes invalid key issue. more details: 1. https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/api-overview 2. https://git.drupalcode.org/project/drupal/-/blob/main/core/modules/jsonapi/src/JsonApiResource/LinkCollection.php?ref_type=heads#L90 --- .../JsonApiResourceTypeSubscriber.php | 37 ++++++++++++ .../tide_data_pipeline.services.yml | 4 ++ .../JsonApiResourceTypeSubscriberTest.php | 56 +++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 modules/tide_search/modules/tide_data_pipeline/src/EventSubscriber/JsonApiResourceTypeSubscriber.php create mode 100644 modules/tide_search/tests/src/Unit/EventSubscriber/JsonApiResourceTypeSubscriberTest.php diff --git a/modules/tide_search/modules/tide_data_pipeline/src/EventSubscriber/JsonApiResourceTypeSubscriber.php b/modules/tide_search/modules/tide_data_pipeline/src/EventSubscriber/JsonApiResourceTypeSubscriber.php new file mode 100644 index 000000000..dcda19e3f --- /dev/null +++ b/modules/tide_search/modules/tide_data_pipeline/src/EventSubscriber/JsonApiResourceTypeSubscriber.php @@ -0,0 +1,37 @@ + ['disableInvalidResourceTypes'], + ]; + } + + /** + * Disables resource types whose Data Pipeline bundle contains a colon. + * + * Data Pipeline bundle IDs are source plugin IDs such as "json:file". + * JSON:API uses resource type names as link keys, where colons are invalid. + */ + public function disableInvalidResourceTypes(ResourceTypeBuildEvent $event): void { + $resource_type_name = $event->getResourceTypeName(); + + if (str_starts_with($resource_type_name, 'data_pipelines--') && str_contains($resource_type_name, ':')) { + $event->disableResourceType(); + } + } + +} diff --git a/modules/tide_search/modules/tide_data_pipeline/tide_data_pipeline.services.yml b/modules/tide_search/modules/tide_data_pipeline/tide_data_pipeline.services.yml index d45bdfe41..1a187af53 100644 --- a/modules/tide_search/modules/tide_data_pipeline/tide_data_pipeline.services.yml +++ b/modules/tide_search/modules/tide_data_pipeline/tide_data_pipeline.services.yml @@ -3,3 +3,7 @@ services: class: Drupal\tide_data_pipeline\Source\FileResource\PrivateFile tags: - { name: data_pipelines_source_resource } + tide_data_pipeline.jsonapi_resource_type_subscriber: + class: Drupal\tide_data_pipeline\EventSubscriber\JsonApiResourceTypeSubscriber + tags: + - { name: event_subscriber } diff --git a/modules/tide_search/tests/src/Unit/EventSubscriber/JsonApiResourceTypeSubscriberTest.php b/modules/tide_search/tests/src/Unit/EventSubscriber/JsonApiResourceTypeSubscriberTest.php new file mode 100644 index 000000000..56a28b1a6 --- /dev/null +++ b/modules/tide_search/tests/src/Unit/EventSubscriber/JsonApiResourceTypeSubscriberTest.php @@ -0,0 +1,56 @@ +createMock(ResourceTypeBuildEvent::class); + $event->expects($this->once()) + ->method('getResourceTypeName') + ->willReturn($resource_type_name); + $event->expects($should_be_disabled ? $this->once() : $this->never()) + ->method('disableResourceType'); + + (new JsonApiResourceTypeSubscriber())->disableInvalidResourceTypes($event); + } + + /** + * Provides JSON:API resource type names. + * + * @return array + * Resource type names and their expected disabled state. + */ + public static function resourceTypeProvider(): array { + return [ + 'JSON file source' => ['data_pipelines--json:file', TRUE], + 'CSV private file source' => ['data_pipelines--csv:private_file', TRUE], + 'valid Data Pipeline type' => ['data_pipelines--custom_source', FALSE], + 'unrelated resource type' => ['node--landing_page', FALSE], + ]; + } + +} From 8b6057152ce8b5b6c309427b1ab19d5dd75a324a Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Mon, 3 Aug 2026 12:36:43 +1000 Subject: [PATCH 12/12] Update readme --- README.md | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0bbacc9f9..4566f6a1b 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,18 @@ repository is the project root; a disposable Drupal site is built into `web/` an module is made available to it via per-file symlinks — code changes at the repository root take effect immediately, no sync step required. -To start the local development stack: +To build a fresh local development site in one step: + 1. Checkout this project. -2. Run `ddev start` — starts web, db, OpenSearch, selenium-chrome and clamav services. -3. Run `ddev poser` — installs Drupal core (version pinned by `DRUPAL_CORE` in `.ddev/config.yaml`) plus all module dependencies into `web/` and `vendor/`. -4. Run `ddev symlink-project` — symlinks this module into `web/modules/custom/tide_core` (re-run after adding/removing root-level files; also runs automatically on `ddev start`). -5. Run `ddev install-site` — installs a fresh site (`testing` profile) and enables `tide_core` and `tide_test`. +2. Run `ddev build` — removes the generated `web/` and `vendor/` directories, starts + the services, installs the dependencies, symlinks the module and installs the site. + +Alternatively, run each build step separately: + +1. Run `ddev start` — starts web, db, OpenSearch, selenium-chrome and clamav services. +2. Run `ddev poser` — installs Drupal core (version pinned by `DRUPAL_CORE` in `.ddev/config.yaml`) plus all module dependencies into `web/` and `vendor/`. +3. Run `ddev symlink-project` — symlinks this module into `web/modules/custom/tide_core` (re-run after adding/removing root-level files; also runs automatically on `ddev start`). +4. Run `ddev install-site` — installs a fresh site (`testing` profile) and enables `tide_core` and `tide_test`. Day-to-day commands: - `ddev drush ` — run Drush. @@ -69,6 +75,31 @@ Day-to-day commands: - `ddev exec vendor/bin/behat --strict --colors [path/to.feature]` — run Behat tests (add `--profile=suggest` for the suggest profile). - `ddev phpcs` / `ddev phpcbf` — lint / auto-fix coding standards. - `ddev ssh` — shell into the web container. + +### Troubleshooting OpenSearch startup + +If `ddev start` reports that the OpenSearch container exited or failed to become +healthy, inspect its logs: + +```bash +ddev logs -s opensearch +``` + +If the logs report that `vm.max_map_count` is too low: + +```text +ERROR: [1] bootstrap checks failed +[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144] +``` + +Increase the limit and start DDEV again: + +```bash +docker run --privileged --rm --pid=host alpine sysctl -w vm.max_map_count=262144 +ddev start +``` + +The setting may need to be applied again after restarting Docker. ## Related projects - [tide](https://github.com/dpc-sdp/tide)