From c04c728f8f98cecfc6f4afc06d8bd41a2ac2801e Mon Sep 17 00:00:00 2001 From: Marcus Johansson Date: Wed, 19 Nov 2025 10:45:02 +0100 Subject: [PATCH 1/9] Install Postgres+PGVector on setup --- .devpanel/custom_package_installer.sh | 4 +++ .devpanel/pgvector_installer.sh | 37 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 .devpanel/pgvector_installer.sh diff --git a/.devpanel/custom_package_installer.sh b/.devpanel/custom_package_installer.sh index bc5e167c..1b4506db 100755 --- a/.devpanel/custom_package_installer.sh +++ b/.devpanel/custom_package_installer.sh @@ -38,6 +38,10 @@ if ! php --ri uploadprogress > /dev/null 2>&1; then sudo pecl install uploadprogress echo 'extension=uploadprogress.so' | sudo tee /usr/local/etc/php/conf.d/uploadprogress.ini fi + +# Install the pgvector extension. +source .devpanel/pgvector_installer.sh + # Reload Apache if it's running. if $PECL_UPDATED && sudo /etc/init.d/apache2 status > /dev/null; then sudo /etc/init.d/apache2 reload diff --git a/.devpanel/pgvector_installer.sh b/.devpanel/pgvector_installer.sh new file mode 100644 index 00000000..9dab4a36 --- /dev/null +++ b/.devpanel/pgvector_installer.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +#Update sudo (might be overkill). +time sudo apt-get update + +# Prepare so it works in devpanel also. +sudo apt -y install curl ca-certificates apt-transport-https +sudo install -d /usr/share/postgresql-common/pgdg +sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc +. /etc/os-release +sudo sh -c "echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $VERSION_CODENAME-pgdg main' > /etc/apt/sources.list.d/pgdg.list" +sudo apt-get update + +#== Install postgresql on the host. +echo 'PostgreSQL is not installed. Installing it now.' +time sudo apt-get install -y postgresql postgresql-17-pgvector postgresql-client +#== Make it less promiscuous in DDEV only. +if env | grep -q DDEV_PROJECT; then + sudo chmod 0755 /usr/bin + sudo chmod 0755 /usr/sbin + #== Start the PostgreSQL service. + env PATH="/usr/sbin:/usr/bin:/sbin:/bin" sudo service postgresql start +else + #== In Devpanel we always install fresh. So we skip the check. + #== Start the postgresql service. + sudo service postgresql start + #== Create the user. + sudo su postgres -c "psql -c \"CREATE ROLE db WITH LOGIN PASSWORD 'db';\"" + #== Create the database. + sudo su postgres -c "psql -c \"CREATE DATABASE db WITH OWNER db ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE template0;\"" + #== Enable pgvector extension. + sudo su postgres -c "psql -d db -c \"CREATE EXTENSION IF NOT EXISTS vector;\"" +fi + +# Make sure that php has pgsql installed. +sudo apt install -y libpq-dev +sudo -E docker-php-ext-install pgsql From ac6a5d8de7d306f543bad68fd7e07ee4a3c48857 Mon Sep 17 00:00:00 2001 From: Marcus Johansson Date: Thu, 20 Nov 2025 11:44:37 +0100 Subject: [PATCH 2/9] Added Github actions --- .ddev/config.yaml | 4 ++++ .github/workflows/docker-publish-tempate.yml | 14 ++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 .github/workflows/docker-publish-tempate.yml diff --git a/.ddev/config.yaml b/.ddev/config.yaml index 88209b1b..e6016478 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -9,6 +9,10 @@ additional_fqdns: [] database: type: mariadb version: "10.11" +hooks: + post-start: + # Run initial setup tasks. + - exec: .devpanel/init.sh use_dns_when_possible: true composer_version: "2" web_environment: diff --git a/.github/workflows/docker-publish-tempate.yml b/.github/workflows/docker-publish-tempate.yml new file mode 100644 index 00000000..87448813 --- /dev/null +++ b/.github/workflows/docker-publish-tempate.yml @@ -0,0 +1,14 @@ +name: Docker build and push template +on: + push: + branches: + - "main" + - test/* + workflow_dispatch: +jobs: + build-application: + uses: drupalforge/docker_publish_action/.github/workflows/docker-publish.yml@main + with: + dockerhub_username: ${{ vars.DOCKERHUB_USERNAME }} + secrets: + dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }} From 7476f6bd3afe38e3e91448e6e04360aac3025c1b Mon Sep 17 00:00:00 2001 From: Tawny Bartlett Date: Sat, 22 Nov 2025 00:22:19 +0000 Subject: [PATCH 3/9] Playing with CMS/recommended different composer starters for different images --- .ddev/config.yaml | 1 + .devpanel/composer_setup.sh | 301 ++++++++++++++++++++++++++++++++++-- .devpanel/fallback_setup.sh | 3 +- .devpanel/init.sh | 87 +++++++++++ 4 files changed, 378 insertions(+), 14 deletions(-) diff --git a/.ddev/config.yaml b/.ddev/config.yaml index e6016478..e22af92a 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -18,6 +18,7 @@ composer_version: "2" web_environment: - APP_ROOT=$DDEV_COMPOSER_ROOT - WEB_ROOT=$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT + - DP_STARTER_TEMPLATE=cms - DB_HOST=db - DB_PORT=3306 - DB_USER=db diff --git a/.devpanel/composer_setup.sh b/.devpanel/composer_setup.sh index 10fca381..532a355d 100755 --- a/.devpanel/composer_setup.sh +++ b/.devpanel/composer_setup.sh @@ -2,22 +2,54 @@ set -eu -o pipefail cd $APP_ROOT -# For versions end with x - add `-dev` suffix (ie. 9.3.x-dev) -# For versions without x - add `~` prefix (ie. ~9.2.0) -d="$DP_CORE_VERSION" -case $d in -*.x) - install_version="$d"-dev - ;; -*) - install_version=~"$d" - ;; -esac +# Determine which starter template to use (default: recommended-project) +# Options: "recommended" or "cms" +STARTER_TEMPLATE="${DP_STARTER_TEMPLATE:-recommended}" + +# Set the composer package based on template choice +if [ "$STARTER_TEMPLATE" = "cms" ]; then + COMPOSER_PROJECT="drupal/cms" + # For Drupal CMS, use latest version if DP_CORE_VERSION is set to a Drupal core version + # CMS has its own versioning (1.0.0, 1.1.0, etc) separate from core + # If DP_CORE_VERSION is empty or looks like a core version, use latest CMS + if [ -z "$DP_CORE_VERSION" ] || [[ "$DP_CORE_VERSION" =~ ^[0-9]+\.[0-9]+\. ]]; then + install_version="" # Use latest + else + # Allow explicit CMS versions like "1.1.x-dev" or "1.0.0" + d="$DP_CORE_VERSION" + case $d in + *.x) + install_version="$d"-dev + ;; + *) + install_version=~"$d" + ;; + esac + fi +else + COMPOSER_PROJECT="drupal/recommended-project" + # For versions end with x - add `-dev` suffix (ie. 9.3.x-dev) + # For versions without x - add `~` prefix (ie. ~9.2.0) + d="$DP_CORE_VERSION" + case $d in + *.x) + install_version="$d"-dev + ;; + *) + install_version=~"$d" + ;; + esac +fi if [ ! -f composer.json ]; then # Create required composer.json and composer.lock files - time composer create-project -n --no-install drupal/recommended-project:"$install_version" temp-composer-files - cp "$APP_ROOT"/temp-composer-files/* "$APP_ROOT"/. + if [ -n "$install_version" ]; then + time composer create-project -n --no-install "$COMPOSER_PROJECT":"$install_version" temp-composer-files + else + time composer create-project -n --no-install "$COMPOSER_PROJECT" temp-composer-files + fi + # Copy all files and directories (including hidden files) from temp directory + cp -r "$APP_ROOT"/temp-composer-files/. "$APP_ROOT"/. rm -rf "$APP_ROOT"/temp-composer-files fi @@ -51,3 +83,246 @@ composer config -jm extra.drupal-scaffold.file-mapping '{ }' composer config scripts.post-drupal-scaffold-cmd \ 'cd web/sites/default && test -z "$(grep '\''include \$devpanel_settings;'\'' settings.php)" && patch -Np1 -r /dev/null < $APP_ROOT/.devpanel/drupal-settings.patch || :' + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# AI DEPENDENCIES +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +# Enable Composer Patches plugin (useful for applying patches from drupal.org) +composer config --no-plugins allow-plugins.cweagans/composer-patches true + +if [ "$STARTER_TEMPLATE" = "cms" ]; then + echo "Adding CMS AI dependencies (full setup with webform libraries)..." + + # Add JavaScript library repositories for Webform support + composer config repositories.tippyjs '{ + "type": "package", + "package": { + "name": "tippyjs/tippyjs", + "version": "6.3.7", + "type": "drupal-library", + "extra": { + "installer-name": "tippyjs" + }, + "dist": { + "url": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "type": "tar" + }, + "license": "MIT" + } + }' + + composer config repositories.tabby '{ + "type": "package", + "package": { + "name": "tabby/tabby", + "version": "12.0.3", + "type": "drupal-library", + "extra": { + "installer-name": "tabby" + }, + "dist": { + "url": "https://github.com/cferdinandi/tabby/archive/refs/tags/v12.0.3.zip", + "type": "zip" + }, + "license": "MIT" + } + }' + + composer config repositories.signature_pad '{ + "type": "package", + "package": { + "name": "signature_pad/signature_pad", + "version": "2.3.0", + "type": "drupal-library", + "extra": { + "installer-name": "signature_pad" + }, + "dist": { + "url": "https://github.com/szimek/signature_pad/archive/refs/tags/v2.3.0.zip", + "type": "zip" + }, + "license": "MIT" + } + }' + + composer config repositories.progress-tracker '{ + "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" + }, + "license": "MIT" + } + }' + + composer config repositories.popperjs '{ + "type": "package", + "package": { + "name": "popperjs/popperjs", + "version": "2.11.6", + "type": "drupal-library", + "extra": { + "installer-name": "popperjs" + }, + "dist": { + "url": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "type": "tar" + }, + "license": "MIT" + } + }' + + composer config repositories."jquery.timepicker" '{ + "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" + }, + "license": "MIT" + } + }' + + composer config repositories."jquery.textcounter" '{ + "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/refs/tags/0.9.1.zip", + "type": "zip" + }, + "license": "MIT" + } + }' + + composer config repositories."jquery.select2" '{ + "type": "package", + "package": { + "name": "jquery/select2", + "version": "4.0.13", + "type": "drupal-library", + "extra": { + "installer-name": "jquery.select2" + }, + "dist": { + "url": "https://github.com/select2/select2/archive/refs/tags/4.0.13.zip", + "type": "zip" + }, + "license": "MIT" + } + }' + + composer config repositories."jquery.rateit" '{ + "type": "package", + "package": { + "name": "jquery/rateit", + "version": "1.1.5", + "type": "drupal-library", + "extra": { + "installer-name": "jquery.rateit" + }, + "dist": { + "url": "https://github.com/gjunge/rateit.js/archive/refs/tags/1.1.5.zip", + "type": "zip" + }, + "license": "MIT" + } + }' + + composer config repositories."jquery.intl-tel-input" '{ + "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/refs/tags/v17.0.19.zip", + "type": "zip" + }, + "license": "MIT" + } + }' + + composer config repositories."jquery.inputmask" '{ + "type": "package", + "package": { + "name": "jquery/inputmask", + "version": "5.0.9", + "type": "drupal-library", + "extra": { + "installer-name": "jquery.inputmask" + }, + "dist": { + "url": "https://github.com/RobinHerbots/jquery.inputmask/archive/refs/tags/5.0.9.zip", + "type": "zip" + }, + "license": "MIT" + } + }' + + composer config repositories.codemirror '{ + "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/refs/tags/5.65.12.zip", + "type": "zip" + }, + "license": "MIT" + } + }' + + # Require all CMS dependencies (AI + Webform libraries) + composer require -n --no-update \ + cweagans/composer-patches:^2@beta \ + drupal/ai_provider_litellm:@beta \ + codemirror/codemirror \ + jquery/inputmask \ + jquery/intl-tel-input \ + jquery/rateit \ + jquery/select2 \ + jquery/textcounter \ + jquery/timepicker \ + popperjs/popperjs \ + progress-tracker/progress-tracker \ + signature_pad/signature_pad \ + tabby/tabby \ + tippyjs/tippyjs + +else + echo "Adding Core AI dependencies (lean setup for quick PR/issue testing)..." + + # Core variant: AI + Search only, no webform bloat + composer require -n --no-update \ + cweagans/composer-patches:^2@beta \ + drupal/ai_provider_litellm:@beta \ + drupal/search_api \ + drupal/search_api_db +fi diff --git a/.devpanel/fallback_setup.sh b/.devpanel/fallback_setup.sh index e591b12a..1dfa0734 100755 --- a/.devpanel/fallback_setup.sh +++ b/.devpanel/fallback_setup.sh @@ -5,6 +5,7 @@ set -eu -o pipefail export DP_INSTALL_PROFILE='demo_umami' export DP_PROJECT_TYPE='project_core' export DP_PROJECT_NAME="drupal" -export DP_CORE_VERSION=${DP_CORE_VERSION:='11.2.5'} +export DP_CORE_VERSION=${DP_CORE_VERSION:='11.2.8'} +export DP_STARTER_TEMPLATE=${DP_STARTER_TEMPLATE:='recommended'} export DP_EXTRA_DEVEL=1 export DP_EXTRA_ADMIN_TOOLBAR=1 diff --git a/.devpanel/init.sh b/.devpanel/init.sh index c34262ff..6fb08fea 100755 --- a/.devpanel/init.sh +++ b/.devpanel/init.sh @@ -7,6 +7,7 @@ set -eu -o pipefail : "${DP_EXTRA_DEVEL:=}" : "${DP_EXTRA_ADMIN_TOOLBAR:=}" : "${DP_PROJECT_TYPE:=}" +: "${DP_STARTER_TEMPLATE:=}" : "${DEVEL_NAME:=}" : "${DEVEL_PACKAGE:=}" : "${ADMIN_TOOLBAR_NAME:=}" @@ -119,6 +120,92 @@ if [ "$DP_PROJECT_TYPE" == "project_theme" ]; then cd "${APP_ROOT}" && drush config-set -y system.theme default "$DP_PROJECT_NAME" fi +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# AI SETUP +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +# Enable AI base modules (ready for configuration) +cd "${APP_ROOT}" && drush en -y ai ai_provider_litellm + +# If API key is provided via environment variable, auto-configure AI +if [ -n "${DP_AI_VIRTUAL_KEY:-}" ]; then + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "🤖 Auto-configuring AI provider..." + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + # Save API key + drush -n key-save litellm_api_key --label="LiteLLM API key" --key-provider=env --key-provider-settings='{ + "env_variable": "DP_AI_VIRTUAL_KEY", + "base64_encoded": false, + "strip_line_breaks": true + }' + + # Configure LiteLLM provider + drush -n cset ai_provider_litellm.settings api_key litellm_api_key + drush -n cset ai_provider_litellm.settings moderation false --input-format yaml + drush -n cset ai_provider_litellm.settings host "${DP_AI_HOST:="https://ai.drupalforge.org"}" + + # CMS: Apply recipe and configure all providers + if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then + echo "Applying Drupal CMS AI recipe..." + drush -q recipe ../recipes/drupal_cms_ai --input=drupal_cms_ai.provider=litellm + + # Configure all AI providers for production use + drush -n cset ai.settings default_providers.chat.provider_id litellm + drush -n cset ai.settings default_providers.chat.model_id openai/gpt-4o-mini + drush -n cset ai.settings default_providers.chat_with_complex_json.provider_id litellm + drush -n cset ai.settings default_providers.chat_with_complex_json.model_id openai/gpt-4o-mini + drush -n cset ai.settings default_providers.chat_with_image_vision.provider_id litellm + drush -n cset ai.settings default_providers.chat_with_image_vision.model_id openai/gpt-4o-mini + drush -n cset ai.settings default_providers.chat_with_structured_response.provider_id litellm + drush -n cset ai.settings default_providers.chat_with_structured_response.model_id openai/gpt-4o-mini + drush -n cset ai.settings default_providers.chat_with_tools.provider_id litellm + drush -n cset ai.settings default_providers.chat_with_tools.model_id openai/gpt-4o-mini + drush -n cset ai.settings default_providers.embeddings.provider_id litellm + drush -n cset ai.settings default_providers.embeddings.model_id openai/text-embedding-3-small + drush -n cset ai.settings default_providers.text_to_speech.provider_id litellm + drush -n cset ai.settings default_providers.text_to_speech.model_id openai/gpt-4o-mini-realtime-preview + drush -n cset ai_assistant_api.ai_assistant.drupal_cms_assistant llm_provider __default__ + drush -n cset klaro.klaro_app.deepchat status 0 + + echo "✅ AI configured for Drupal CMS" + else + # Core: Just configure embeddings for AI Search + echo "Configuring AI Search for Core variant..." + drush -n cset ai.settings default_providers.embeddings.provider_id litellm + drush -n cset ai.settings default_providers.embeddings.model_id openai/text-embedding-3-small + + echo "✅ AI configured for AI Search" + fi + + # Configure Automatic Updates to trust patches + drush -n cset --input-format=yaml package_manager.settings additional_trusted_composer_plugins '["cweagans/composer-patches"]' + drush -n cset --input-format=yaml package_manager.settings additional_known_files_in_project_root '["patches.json", "patches.lock.json"]' +else + # AI modules installed but not configured - display instructions + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "🤖 AI Modules Ready (Not Configured)" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + echo "AI modules installed: ✓ ai, ✓ ai_provider_litellm" + if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then + echo "PostgreSQL + pgvector: ✓ Ready for AI Search" + else + echo "PostgreSQL + pgvector: ✓ Ready for AI Search" + echo "Search API: ✓ Available for semantic search" + fi + echo "" + echo "To enable AI features:" + echo " 1. Get API key from: https://ai.drupalforge.org" + echo " 2. Run: ddev setup-ai" + echo " OR set env var: export DP_AI_VIRTUAL_KEY=sk-your-key" + echo "" + echo "QA Tip: Test AI Search performance with PostgreSQL + pgvector!" + echo "" +fi + # Finish measuring script time. script_end_time=$(date +%s) runtime=$((script_end_time - script_start_time)) From e581e60b4b05c35a1d7207e8a47d1cd4b926ce48 Mon Sep 17 00:00:00 2001 From: LittlePixieZ Date: Mon, 24 Nov 2025 22:43:19 +0000 Subject: [PATCH 4/9] Added ability to choose between CMS/core, choose version, removed core from being built from source for speed, only contrib (need to add AI from source), added in dependencies and scripts from AI demo --- .ddev/config.yaml | 16 +- .ddev/launch.json | 52 +++ .devpanel/composer_setup.sh | 73 ++--- .devpanel/contrib_modules_setup.sh | 4 +- .devpanel/fallback_setup.sh | 58 +++- .devpanel/git_setup.sh | 31 +- .devpanel/init-container.sh | 6 +- .devpanel/init.sh | 309 +++++++----------- .devpanel/warm | 17 + .github/workflows/docker-publish-image.yml | 2 +- .gitignore | 30 +- .gitpod.yml | 77 ----- .gitpod/README.md | 33 -- .gitpod/drupal/drupalpod-setup/cleanup.sh | 8 - .../drupal/drupalpod-setup/composer_setup.sh | 46 --- .../drupalpod-setup/contrib_modules_setup.sh | 34 -- .gitpod/drupal/drupalpod-setup/ddev_setup.sh | 20 -- .../drupalpod-setup/drupal_setup_contrib.sh | 28 -- .../drupalpod-setup/drupal_setup_core.sh | 59 ---- .../drupal/drupalpod-setup/drupalpod-setup.md | 18 - .../drupal/drupalpod-setup/drupalpod-setup.sh | 137 -------- .../drupal/drupalpod-setup/fallback_setup.sh | 10 - .gitpod/drupal/drupalpod-setup/git_setup.sh | 71 ---- .gitpod/drupal/install-essential-packages.sh | 52 --- .../drupal/ssh/00-interactive-ssh-setup.sh | 58 ---- .gitpod/drupal/ssh/01-check-private-ssh.sh | 29 -- .gitpod/drupal/ssh/02-setup-private-ssh.sh | 28 -- .../03-generate-drupal-ssh-instructions.sh | 11 - .gitpod/drupal/ssh/04-confirm-ssh-setup.sh | 37 --- .gitpod/drupal/ssh/05-set-repo-as-ssh.sh | 9 - .gitpod/drupal/ssh/instructions-template.md | 14 - .gitpod/drupal/templates/git-exclude.template | 10 - .gitpod/images/Dockerfile | 40 --- .gitpod/images/push.sh | 25 -- .gitpod/utils/ddev-in-gitpod-setup.sh | 7 - .gitpod/utils/env-setup.sh | 36 -- .../ddev-composer.template.sh | 3 - .../script-templates/ddev-drush.template.sh | 3 - .../script-templates/ddev-node.template.sh | 3 - .../script-templates/ddev-npx.template.sh | 3 - .../script-templates/ddev-nvm.template.sh | 3 - .../script-templates/ddev-php.template.sh | 3 - .../script-templates/ddev-yarn.template.sh | 3 - .../script-templates/phpstorm.template.sh | 14 - .../script-templates/preview.template.sh | 7 - .../protect-my-git.template.sh | 7 - .gitpod/utils/send-a-message-gcs.sh | 32 -- .gitpod/utils/send-a-message-gitpod.sh | 28 -- .gitpod/utils/set-base-environment.sh | 11 - .vscode/launch.json | 40 ++- README.md | 103 +++++- 51 files changed, 466 insertions(+), 1292 deletions(-) create mode 100644 .ddev/launch.json create mode 100755 .devpanel/warm delete mode 100644 .gitpod.yml delete mode 100644 .gitpod/README.md delete mode 100644 .gitpod/drupal/drupalpod-setup/cleanup.sh delete mode 100644 .gitpod/drupal/drupalpod-setup/composer_setup.sh delete mode 100644 .gitpod/drupal/drupalpod-setup/contrib_modules_setup.sh delete mode 100644 .gitpod/drupal/drupalpod-setup/ddev_setup.sh delete mode 100644 .gitpod/drupal/drupalpod-setup/drupal_setup_contrib.sh delete mode 100644 .gitpod/drupal/drupalpod-setup/drupal_setup_core.sh delete mode 100644 .gitpod/drupal/drupalpod-setup/drupalpod-setup.md delete mode 100755 .gitpod/drupal/drupalpod-setup/drupalpod-setup.sh delete mode 100644 .gitpod/drupal/drupalpod-setup/fallback_setup.sh delete mode 100644 .gitpod/drupal/drupalpod-setup/git_setup.sh delete mode 100755 .gitpod/drupal/install-essential-packages.sh delete mode 100755 .gitpod/drupal/ssh/00-interactive-ssh-setup.sh delete mode 100755 .gitpod/drupal/ssh/01-check-private-ssh.sh delete mode 100755 .gitpod/drupal/ssh/02-setup-private-ssh.sh delete mode 100755 .gitpod/drupal/ssh/03-generate-drupal-ssh-instructions.sh delete mode 100755 .gitpod/drupal/ssh/04-confirm-ssh-setup.sh delete mode 100755 .gitpod/drupal/ssh/05-set-repo-as-ssh.sh delete mode 100644 .gitpod/drupal/ssh/instructions-template.md delete mode 100644 .gitpod/drupal/templates/git-exclude.template delete mode 100644 .gitpod/images/Dockerfile delete mode 100755 .gitpod/images/push.sh delete mode 100755 .gitpod/utils/ddev-in-gitpod-setup.sh delete mode 100755 .gitpod/utils/env-setup.sh delete mode 100755 .gitpod/utils/script-templates/ddev-composer.template.sh delete mode 100755 .gitpod/utils/script-templates/ddev-drush.template.sh delete mode 100755 .gitpod/utils/script-templates/ddev-node.template.sh delete mode 100755 .gitpod/utils/script-templates/ddev-npx.template.sh delete mode 100755 .gitpod/utils/script-templates/ddev-nvm.template.sh delete mode 100755 .gitpod/utils/script-templates/ddev-php.template.sh delete mode 100755 .gitpod/utils/script-templates/ddev-yarn.template.sh delete mode 100755 .gitpod/utils/script-templates/phpstorm.template.sh delete mode 100755 .gitpod/utils/script-templates/preview.template.sh delete mode 100755 .gitpod/utils/script-templates/protect-my-git.template.sh delete mode 100755 .gitpod/utils/send-a-message-gcs.sh delete mode 100755 .gitpod/utils/send-a-message-gitpod.sh delete mode 100755 .gitpod/utils/set-base-environment.sh diff --git a/.ddev/config.yaml b/.ddev/config.yaml index e22af92a..8a7642c0 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -1,5 +1,4 @@ -name: DrupalPod -type: drupal +type: drupal11 docroot: web php_version: "8.3" webserver_type: apache-fpm @@ -7,26 +6,33 @@ xdebug_enabled: false additional_hostnames: [] additional_fqdns: [] database: - type: mariadb - version: "10.11" + type: mysql + version: "8.0" hooks: post-start: + # Set up debugging. + - exec: test -f .vscode/launch.json || mkdir -p .vscode && cp .ddev/launch.json .vscode/ # Run initial setup tasks. - exec: .devpanel/init.sh use_dns_when_possible: true composer_version: "2" web_environment: + # Set up DevPanel variables. - APP_ROOT=$DDEV_COMPOSER_ROOT - WEB_ROOT=$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT - DP_STARTER_TEMPLATE=cms + - DP_VERSION=2.0.x - DB_HOST=db - DB_PORT=3306 - DB_USER=db - DB_PASSWORD=db - DB_NAME=db - - DP_APP_ID=drupalpod + - DP_APP_ID=drupalpod_ai_qa - DB_DRIVER=mysql + - DP_AI_VIRTUAL_KEY= + - DP_REBUILD=1 corepack_enable: false +ddev_version_constraint: '>=1.24.0' # Key features of DDEV's config.yaml: diff --git a/.ddev/launch.json b/.ddev/launch.json new file mode 100644 index 00000000..923c99bf --- /dev/null +++ b/.ddev/launch.json @@ -0,0 +1,52 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "name": "Listen for Xdebug", + "type": "php", + "request": "launch", + "port": 9003, + "pathMappings": { + "/var/www/html": "${workspaceFolder}" + } + }, + { + "name": "Launch currently open script", + "type": "php", + "request": "launch", + "program": "${file}", + "cwd": "${fileDirname}", + "port": 0, + "runtimeArgs": [ + "-dxdebug.start_with_request=yes" + ], + "env": { + "XDEBUG_MODE": "debug,develop", + "XDEBUG_CONFIG": "client_port=${port}" + } + }, + { + "name": "Launch Built-in web server", + "type": "php", + "request": "launch", + "runtimeArgs": [ + "-dxdebug.mode=debug", + "-dxdebug.start_with_request=yes", + "-S", + "localhost:0" + ], + "program": "", + "cwd": "${workspaceRoot}", + "port": 9003, + "serverReadyAction": { + "pattern": "Development Server \\(http://localhost:([0-9]+)\\) started", + "uriFormat": "http://localhost:%s", + "action": "openExternally" + } + } + ] +} diff --git a/.devpanel/composer_setup.sh b/.devpanel/composer_setup.sh index 532a355d..d75dd5a5 100755 --- a/.devpanel/composer_setup.sh +++ b/.devpanel/composer_setup.sh @@ -2,35 +2,27 @@ set -eu -o pipefail cd $APP_ROOT -# Determine which starter template to use (default: recommended-project) -# Options: "recommended" or "cms" -STARTER_TEMPLATE="${DP_STARTER_TEMPLATE:-recommended}" +# Determine which starter template to use +# Options: "cms" or "core" +STARTER_TEMPLATE="${DP_STARTER_TEMPLATE:-cms}" -# Set the composer package based on template choice +# Determine the composer package and version if [ "$STARTER_TEMPLATE" = "cms" ]; then COMPOSER_PROJECT="drupal/cms" - # For Drupal CMS, use latest version if DP_CORE_VERSION is set to a Drupal core version - # CMS has its own versioning (1.0.0, 1.1.0, etc) separate from core - # If DP_CORE_VERSION is empty or looks like a core version, use latest CMS - if [ -z "$DP_CORE_VERSION" ] || [[ "$DP_CORE_VERSION" =~ ^[0-9]+\.[0-9]+\. ]]; then - install_version="" # Use latest - else - # Allow explicit CMS versions like "1.1.x-dev" or "1.0.0" - d="$DP_CORE_VERSION" - case $d in - *.x) - install_version="$d"-dev - ;; - *) - install_version=~"$d" - ;; - esac - fi + # For CMS versions: 1.x, 1.0.0, 2.0.0, etc. + d="$DP_VERSION" + case $d in + *.x) + install_version="$d"-dev + ;; + *) + install_version="$d" + ;; + esac else COMPOSER_PROJECT="drupal/recommended-project" - # For versions end with x - add `-dev` suffix (ie. 9.3.x-dev) - # For versions without x - add `~` prefix (ie. ~9.2.0) - d="$DP_CORE_VERSION" + # For core versions: 11.x, 11.2.8, etc. + d="$DP_VERSION" case $d in *.x) install_version="$d"-dev @@ -41,17 +33,18 @@ else esac fi -if [ ! -f composer.json ]; then - # Create required composer.json and composer.lock files - if [ -n "$install_version" ]; then - time composer create-project -n --no-install "$COMPOSER_PROJECT":"$install_version" temp-composer-files - else - time composer create-project -n --no-install "$COMPOSER_PROJECT" temp-composer-files - fi - # Copy all files and directories (including hidden files) from temp directory - cp -r "$APP_ROOT"/temp-composer-files/. "$APP_ROOT"/. - rm -rf "$APP_ROOT"/temp-composer-files +# Always regenerate composer.json from the selected template +if [ -n "$install_version" ]; then + time composer create-project -n --no-install "$COMPOSER_PROJECT":"$install_version" temp-composer-files +else + time composer create-project -n --no-install "$COMPOSER_PROJECT" temp-composer-files fi +# Copy all files and directories (including hidden files) from temp directory +cp -r "$APP_ROOT"/temp-composer-files/. "$APP_ROOT"/. +rm -rf "$APP_ROOT"/temp-composer-files + +# Set minimum-stability to dev to allow alpha/beta packages (needed for CMS 2.x) +composer config minimum-stability dev # Programmatically fix Composer 2.2 allow-plugins to avoid errors composer config --no-plugins allow-plugins.composer/installers true @@ -64,16 +57,6 @@ composer config --no-plugins allow-plugins.mglaman/composer-drupal-lenient true composer config --no-plugins allow-plugins.php-http/discovery true composer config --no-plugins allow-plugins.tbachert/spi false -# Add project source code as symlink (to repos/name_of_project) -# double quotes explained - https://stackoverflow.com/a/1250279/5754049 -if [ -n "$DP_PROJECT_NAME" ]; then - composer --no-plugins config \ - repositories.core1 \ - '{"type": "path", "url": "repos/'"$DP_PROJECT_NAME"'", "options": {"symlink": true}}' - - composer --no-plugins config minimum-stability dev -fi - # Scaffold settings.php. composer config -jm extra.drupal-scaffold.file-mapping '{ "[web-root]/sites/default/settings.php": { @@ -303,6 +286,7 @@ if [ "$STARTER_TEMPLATE" = "cms" ]; then composer require -n --no-update \ cweagans/composer-patches:^2@beta \ drupal/ai_provider_litellm:@beta \ + drush/drush:^13.6 \ codemirror/codemirror \ jquery/inputmask \ jquery/intl-tel-input \ @@ -323,6 +307,7 @@ else composer require -n --no-update \ cweagans/composer-patches:^2@beta \ drupal/ai_provider_litellm:@beta \ + drush/drush:^13.6 \ drupal/search_api \ drupal/search_api_db fi diff --git a/.devpanel/contrib_modules_setup.sh b/.devpanel/contrib_modules_setup.sh index 6892b60a..42418adb 100755 --- a/.devpanel/contrib_modules_setup.sh +++ b/.devpanel/contrib_modules_setup.sh @@ -13,7 +13,7 @@ export DP_EXTRA_DEVEL=1 export DP_EXTRA_ADMIN_TOOLBAR=1 # Adding support for composer-drupal-lenient - https://packagist.org/packages/mglaman/composer-drupal-lenient -if [[ "$DP_CORE_VERSION" =~ ^10(\..*)?$ ]]; then +if [[ "$DP_VERSION" =~ ^10(\..*)?$ ]]; then if [ "$DP_PROJECT_TYPE" != "project_core" ]; then export COMPOSER_DRUPAL_LENIENT=mglaman/composer-drupal-lenient else @@ -22,7 +22,7 @@ if [[ "$DP_CORE_VERSION" =~ ^10(\..*)?$ ]]; then fi # Adding support for composer-drupal-lenient - https://packagist.org/packages/mglaman/composer-drupal-lenient -if [[ "$DP_CORE_VERSION" =~ ^11(\..*)?$ ]]; then +if [[ "$DP_VERSION" =~ ^11(\..*)?$ ]]; then # admin_toolbar and devel are not compatible yet with Drupal 11 export DP_EXTRA_ADMIN_TOOLBAR= export DP_EXTRA_DEVEL= diff --git a/.devpanel/fallback_setup.sh b/.devpanel/fallback_setup.sh index 1dfa0734..47e177c5 100755 --- a/.devpanel/fallback_setup.sh +++ b/.devpanel/fallback_setup.sh @@ -1,11 +1,57 @@ #!/usr/bin/env bash set -eu -o pipefail -# Set a default setup (when project type is not specified) -export DP_INSTALL_PROFILE='demo_umami' -export DP_PROJECT_TYPE='project_core' -export DP_PROJECT_NAME="drupal" -export DP_CORE_VERSION=${DP_CORE_VERSION:='11.2.8'} -export DP_STARTER_TEMPLATE=${DP_STARTER_TEMPLATE:='recommended'} +# Set defaults for DrupalPod AI QA +export DP_STARTER_TEMPLATE=${DP_STARTER_TEMPLATE:='cms'} + +# Set default version based on starter template +if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then + # CMS versions: 1.0.0, 1.1.x, 2.0.0, etc. + export DP_VERSION=${DP_VERSION:='1.x'} +else + # Core versions: 11.2.8, 11.x, 10.1.5, etc. + export DP_VERSION=${DP_VERSION:='11.2.8'} +fi + +# Optional: Enable extra modules (disabled for Drupal 11) export DP_EXTRA_DEVEL=1 export DP_EXTRA_ADMIN_TOOLBAR=1 + +# Default install profile (can be overridden) +if [ -z "${DP_INSTALL_PROFILE:-}" ]; then + if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then + # For CMS, empty string means auto-detect drupal_cms_installer + export DP_INSTALL_PROFILE='' + else + # For core, use standard profile by default + export DP_INSTALL_PROFILE='standard' + fi +fi + +# Validate version format matches template choice +if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then + # CMS versions should be like 1.x, 2.x, 1.0.0, 2.0.0, not like 9.x or higher (which are core) + if [[ "$DP_VERSION" =~ ^[0-9]+ ]]; then + major_version=$(echo "$DP_VERSION" | cut -d. -f1) + if [ "$major_version" -ge 9 ]; then + echo "ERROR: Version '$DP_VERSION' looks like a Drupal core version, but you selected CMS template." + echo "CMS versions should be like: 1.0.0, 1.1.x, 1.x-dev, 2.0.0, 2.x, etc." + exit 1 + fi + fi +else + # Core versions should be like 9.x, 10.x, 11.2.8, not like 1.0.0 or 2.0.0 + if [[ "$DP_VERSION" =~ ^[1-2]\. ]]; then + echo "ERROR: Version '$DP_VERSION' looks like a CMS version, but you selected core template." + echo "Core versions should be like: 11.2.8, 11.x, 10.1.5, 10.x, 9.x" + exit 1 + fi +fi + +# Set install profile based on starter template +# For CMS, don't specify a profile - let Drupal auto-detect the distribution +if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then + export DP_INSTALL_PROFILE='' +else + export DP_INSTALL_PROFILE='standard' +fi diff --git a/.devpanel/git_setup.sh b/.devpanel/git_setup.sh index 1231324b..35cd09ed 100755 --- a/.devpanel/git_setup.sh +++ b/.devpanel/git_setup.sh @@ -11,9 +11,34 @@ echo "$SSHKey" >>~/.ssh/known_hosts cp "${APP_ROOT}"/.gitpod/drupal/templates/git-exclude.template "${APP_ROOT}"/.git/info/exclude # Get the required repo ready -if [ "$DP_PROJECT_TYPE" == "project_core" ]; then +if [ "$DP_STARTER_TEMPLATE" = "cms" ] && [ "$DP_PROJECT_TYPE" == "project_core" ]; then + # Clone Drupal CMS repo + if git submodule status repos/cms > /dev/null 2>&1; then + time git submodule update --init --recursive + else + time git submodule add -f https://git.drupalcode.org/project/cms.git repos/cms + time git config -f .gitmodules submodule."repos/cms".ignore dirty + fi + + # For CMS, check out the version branch/tag + d="$DP_VERSION" + case $d in + *.x) + checkout_type=origin + ;; + *) + checkout_type=tags + ;; + esac + + cd "${APP_ROOT}"/repos/cms && + git fetch origin && + git fetch --all --tags && + git checkout "$checkout_type"/"$DP_VERSION" + +elif [ "$DP_PROJECT_TYPE" == "project_core" ]; then # Find if requested core version is dev or stable - d="$DP_CORE_VERSION" + d="$DP_VERSION" case $d in *.x) # If dev - use git checkout origin/* @@ -37,7 +62,7 @@ if [ "$DP_PROJECT_TYPE" == "project_core" ]; then cd "${APP_ROOT}"/repos/drupal && git fetch origin && git fetch --all --tags && - git checkout "$checkout_type"/"$DP_CORE_VERSION" + git checkout "$checkout_type"/"$DP_VERSION" # Ignore specific directories during Drupal core development cp "${APP_ROOT}"/.gitpod/drupal/templates/git-exclude.template "${APP_ROOT}"/.git/modules/repos/drupal/info/exclude diff --git a/.devpanel/init-container.sh b/.devpanel/init-container.sh index d7fb60fb..568fefa7 100755 --- a/.devpanel/init-container.sh +++ b/.devpanel/init-container.sh @@ -26,7 +26,7 @@ fi if [[ -n "$DB_SYNC_VOL" ]]; then if [[ ! -f "/var/www/build/.devpanel/init-container.sh" ]]; then echo 'Sync volume...' - sudo chown -R 1000:1000 /var/www/build + sudo chown -R 1000:1000 /var/www/build rsync -av --delete --delete-excluded $APP_ROOT/ /var/www/build fi fi @@ -35,3 +35,7 @@ drush -n updb echo echo 'Run cron.' drush cron +echo +echo 'Populate caches.' +drush cache:warm +$APP_ROOT/.devpanel/warm diff --git a/.devpanel/init.sh b/.devpanel/init.sh index 6fb08fea..b28052ea 100755 --- a/.devpanel/init.sh +++ b/.devpanel/init.sh @@ -1,212 +1,151 @@ #!/usr/bin/env bash +if [ -n "${DEBUG_SCRIPT:-}" ]; then + set -x +fi set -eu -o pipefail +cd $APP_ROOT + +mkdir -p logs +LOG_FILE="logs/init-$(date +%F-%T).log" +exec > >(tee $LOG_FILE) 2>&1 -# Initialize all variables with null if they do not exist -: "${DEBUG_SCRIPT:=}" -: "${DP_INSTALL_PROFILE:=}" -: "${DP_EXTRA_DEVEL:=}" -: "${DP_EXTRA_ADMIN_TOOLBAR:=}" -: "${DP_PROJECT_TYPE:=}" -: "${DP_STARTER_TEMPLATE:=}" -: "${DEVEL_NAME:=}" -: "${DEVEL_PACKAGE:=}" -: "${ADMIN_TOOLBAR_NAME:=}" -: "${ADMIN_TOOLBAR_PACKAGE:=}" -: "${COMPOSER_DRUPAL_LENIENT:=}" -: "${DP_CORE_VERSION:=}" -: "${DP_ISSUE_BRANCH:=}" -: "${DP_ISSUE_FORK:=}" -: "${DP_MODULE_VERSION:=}" -: "${DP_PATCH_FILE:=}" +TIMEFORMAT=%lR +# For faster performance, don't audit dependencies automatically. +export COMPOSER_NO_AUDIT=1 +# For faster performance, don't install dev dependencies. +export COMPOSER_NO_DEV=1 # Assuming .sh files are in the same directory as this script DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi +# Always source fallback_setup to set all defaults +# This ensures DP_INSTALL_PROFILE and other variables are initialized +source "$DIR/fallback_setup.sh" -convert_version() { - local version=$1 - if [[ $version =~ "-" ]]; then - # Remove the part after the dash and replace the last numeric segment with 'x' - local base_version=${version%-*} - echo "${base_version%.*}.x" - else - echo "$version" - fi -} - -# Test cases -# echo $(convert_version "9.2.5-dev1") # Output: 9.2.x -# echo $(convert_version "9.2.5") # Output: 9.2.5 -# echo $(convert_version "10.1.0-beta1") # Output: 10.1.x -# echo $(convert_version "11.0-dev") # Output: 11.x - -# Set a default setup if project type wasn't specified -if [ -z "$DP_PROJECT_TYPE" ]; then - source "$DIR/fallback_setup.sh" +# Install VSCode Extensions +if [ -n "${DP_VSCODE_EXTENSIONS:-}" ]; then + IFS=',' + for value in $DP_VSCODE_EXTENSIONS; do + time code-server --install-extension $value + done fi -source "$DIR/git_setup.sh" - -# If this is an issue fork of Drupal core - set the drupal core version based on that issue fork -if [ "$DP_PROJECT_TYPE" == "project_core" ] && [ -n "$DP_ISSUE_FORK" ]; then - VERSION_FROM_GIT=$(grep 'const VERSION' "${APP_ROOT}"/repos/drupal/core/lib/Drupal.php | awk -F "'" '{print $2}') - DP_CORE_VERSION=$(convert_version "$VERSION_FROM_GIT") - export DP_CORE_VERSION +#== Clean rebuild if requested. +if [ "${DP_REBUILD:-0}" = "1" ]; then + echo + echo 'Performing clean rebuild...' + echo 'Removing vendor and web directories...' + time rm -rf vendor web/core web/modules/contrib web/themes/contrib web/profiles/contrib composer.lock + echo 'Rebuild mode enabled.' + echo fi -# Measure the time it takes to go through the script -script_start_time=$(date +%s) - -# Remove root-owned files. -sudo rm -rf $APP_ROOT/lost+found - -source "$DIR/contrib_modules_setup.sh" -source "$DIR/cleanup.sh" -source "$DIR/composer_setup.sh" - -if [ -n "$DP_PATCH_FILE" ]; then - echo Applying selected patch "$DP_PATCH_FILE" - cd "${WORK_DIR}" && curl "$DP_PATCH_FILE" | patch -p1 +#== Remove root-owned files. +echo +echo Remove root-owned files. +time sudo rm -rf lost+found + +#== Composer install. +echo +if [ "${DP_REBUILD:-0}" = "1" ] || [ ! -f composer.json ]; then + echo 'Generate composer.json.' + time source .devpanel/composer_setup.sh + echo +elif [ -f composer.json ]; then + if composer show --locked cweagans/composer-patches ^2 &> /dev/null; then + echo 'Update patches.lock.json.' + time composer prl + echo + fi fi - -# Prepare special setup to work with Drupal core -if [ "$DP_PROJECT_TYPE" == "project_core" ]; then - source "$DIR/drupal_setup_core.sh" -# Prepare special setup to work with Drupal contrib -elif [ -n "$DP_PROJECT_NAME" ]; then - source "$DIR/drupal_setup_contrib.sh" +echo 'Running composer update...' +time composer -n update --no-dev --no-progress || { echo "Composer update failed!"; exit 1; } + +#== Create the private files directory. +if [ ! -d private ]; then + echo + echo 'Create the private files directory.' + time mkdir private fi -time "${DIR}"/install-essential-packages.sh -# Configure phpcs for drupal. -cd "$APP_ROOT" && - vendor/bin/phpcs --config-set installed_paths vendor/drupal/coder/coder_sniffer - -if [ -z "$(drush status --field=db-status)" ] || \ - [ $DP_INSTALL_PROFILE != 'demo_umami' ] || \ - ! printf "11.2.2\n$DP_CORE_VERSION" | sort -C; then - # New site install, different install profile, or lower core version. - time drush -n si --account-pass=admin --site-name="DrupalPod" "$DP_INSTALL_PROFILE" -elif [ $DP_CORE_VERSION != '11.2.2' ]; then - # Run database updates if the core version is different. - time drush -n updb +#== Create the config sync directory. +if [ ! -d config/sync ]; then + echo + echo 'Create the config sync directory.' + time mkdir -p config/sync fi -# Install devel and admin_toolbar modules. -if [ "$DP_EXTRA_DEVEL" != '1' ]; then - DEVEL_NAME= +#== Generate hash salt. +if [ ! -f .devpanel/salt.txt ]; then + echo + echo 'Generate hash salt.' + time openssl rand -hex 32 > .devpanel/salt.txt fi -if [ "$DP_EXTRA_ADMIN_TOOLBAR" != '1' ]; then - ADMIN_TOOLBAR_NAME= -fi - -# Enable extra modules. -cd "${APP_ROOT}" && - drush en -y \ - $ADMIN_TOOLBAR_NAME \ - $DEVEL_NAME -# Enable the requested module. -if [ "$DP_PROJECT_TYPE" == "project_module" ]; then - cd "${APP_ROOT}" && drush en -y "$DP_PROJECT_NAME" -fi - -# Enable the requested theme. -if [ "$DP_PROJECT_TYPE" == "project_theme" ]; then - cd "${APP_ROOT}" && drush then -y "$DP_PROJECT_NAME" - cd "${APP_ROOT}" && drush config-set -y system.theme default "$DP_PROJECT_NAME" -fi - -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# AI SETUP -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -# Enable AI base modules (ready for configuration) -cd "${APP_ROOT}" && drush en -y ai ai_provider_litellm - -# If API key is provided via environment variable, auto-configure AI -if [ -n "${DP_AI_VIRTUAL_KEY:-}" ]; then - echo "" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "🤖 Auto-configuring AI provider..." - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - - # Save API key +#== Install Drupal. +echo +if [ "${DP_REBUILD:-0}" = "1" ] || ! drush status --field=bootstrap | grep -q "Drupal bootstrap"; then + if [ -z "$DP_INSTALL_PROFILE" ]; then + echo 'Install Drupal.' + time drush -n si + else + echo 'Install Drupal with profile: '"$DP_INSTALL_PROFILE" + time drush -n si "$DP_INSTALL_PROFILE" + fi + + #== Apply the AI recipe. + if [ -n "${DP_AI_VIRTUAL_KEY:-}" ]; then + echo + time drush -n en ai_provider_litellm drush -n key-save litellm_api_key --label="LiteLLM API key" --key-provider=env --key-provider-settings='{ - "env_variable": "DP_AI_VIRTUAL_KEY", - "base64_encoded": false, - "strip_line_breaks": true + "env_variable": "DP_AI_VIRTUAL_KEY", + "base64_encoded": false, + "strip_line_breaks": true }' - - # Configure LiteLLM provider drush -n cset ai_provider_litellm.settings api_key litellm_api_key drush -n cset ai_provider_litellm.settings moderation false --input-format yaml drush -n cset ai_provider_litellm.settings host "${DP_AI_HOST:="https://ai.drupalforge.org"}" - - # CMS: Apply recipe and configure all providers - if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then - echo "Applying Drupal CMS AI recipe..." - drush -q recipe ../recipes/drupal_cms_ai --input=drupal_cms_ai.provider=litellm - - # Configure all AI providers for production use - drush -n cset ai.settings default_providers.chat.provider_id litellm - drush -n cset ai.settings default_providers.chat.model_id openai/gpt-4o-mini - drush -n cset ai.settings default_providers.chat_with_complex_json.provider_id litellm - drush -n cset ai.settings default_providers.chat_with_complex_json.model_id openai/gpt-4o-mini - drush -n cset ai.settings default_providers.chat_with_image_vision.provider_id litellm - drush -n cset ai.settings default_providers.chat_with_image_vision.model_id openai/gpt-4o-mini - drush -n cset ai.settings default_providers.chat_with_structured_response.provider_id litellm - drush -n cset ai.settings default_providers.chat_with_structured_response.model_id openai/gpt-4o-mini - drush -n cset ai.settings default_providers.chat_with_tools.provider_id litellm - drush -n cset ai.settings default_providers.chat_with_tools.model_id openai/gpt-4o-mini - drush -n cset ai.settings default_providers.embeddings.provider_id litellm - drush -n cset ai.settings default_providers.embeddings.model_id openai/text-embedding-3-small - drush -n cset ai.settings default_providers.text_to_speech.provider_id litellm - drush -n cset ai.settings default_providers.text_to_speech.model_id openai/gpt-4o-mini-realtime-preview - drush -n cset ai_assistant_api.ai_assistant.drupal_cms_assistant llm_provider __default__ - drush -n cset klaro.klaro_app.deepchat status 0 - - echo "✅ AI configured for Drupal CMS" - else - # Core: Just configure embeddings for AI Search - echo "Configuring AI Search for Core variant..." - drush -n cset ai.settings default_providers.embeddings.provider_id litellm - drush -n cset ai.settings default_providers.embeddings.model_id openai/text-embedding-3-small - - echo "✅ AI configured for AI Search" - fi - - # Configure Automatic Updates to trust patches - drush -n cset --input-format=yaml package_manager.settings additional_trusted_composer_plugins '["cweagans/composer-patches"]' - drush -n cset --input-format=yaml package_manager.settings additional_known_files_in_project_root '["patches.json", "patches.lock.json"]' + drush -q recipe ../recipes/drupal_cms_ai --input=drupal_cms_ai.provider=litellm + drush -n cset ai.settings default_providers.chat.provider_id litellm + drush -n cset ai.settings default_providers.chat.model_id openai/gpt-4o-mini + drush -n cset ai.settings default_providers.chat_with_complex_json.provider_id litellm + drush -n cset ai.settings default_providers.chat_with_complex_json.model_id openai/gpt-4o-mini + drush -n cset ai.settings default_providers.chat_with_image_vision.provider_id litellm + drush -n cset ai.settings default_providers.chat_with_image_vision.model_id openai/gpt-4o-mini + drush -n cset ai.settings default_providers.chat_with_structured_response.provider_id litellm + drush -n cset ai.settings default_providers.chat_with_structured_response.model_id openai/gpt-4o-mini + drush -n cset ai.settings default_providers.chat_with_tools.provider_id litellm + drush -n cset ai.settings default_providers.chat_with_tools.model_id openai/gpt-4o-mini + drush -n cset ai.settings default_providers.embeddings.provider_id litellm + drush -n cset ai.settings default_providers.embeddings.model_id openai/text-embedding-3-small + drush -n cset ai.settings default_providers.text_to_speech.provider_id litellm + drush -n cset ai.settings default_providers.text_to_speech.model_id openai/gpt-4o-mini-realtime-preview + drush -n cset ai_assistant_api.ai_assistant.drupal_cms_assistant llm_provider __default__ + drush -n cset klaro.klaro_app.deepchat status 0 + fi + + echo + echo 'Tell Automatic Updates about patches.' + drush -n cset --input-format=yaml package_manager.settings additional_trusted_composer_plugins '["cweagans/composer-patches"]' + drush -n cset --input-format=yaml package_manager.settings additional_known_files_in_project_root '["patches.json", "patches.lock.json"]' + time drush ev '\Drupal::moduleHandler()->invoke("automatic_updates", "modules_installed", [[], FALSE])' else - # AI modules installed but not configured - display instructions - echo "" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "🤖 AI Modules Ready (Not Configured)" - echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "" - echo "AI modules installed: ✓ ai, ✓ ai_provider_litellm" - if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then - echo "PostgreSQL + pgvector: ✓ Ready for AI Search" - else - echo "PostgreSQL + pgvector: ✓ Ready for AI Search" - echo "Search API: ✓ Available for semantic search" - fi - echo "" - echo "To enable AI features:" - echo " 1. Get API key from: https://ai.drupalforge.org" - echo " 2. Run: ddev setup-ai" - echo " OR set env var: export DP_AI_VIRTUAL_KEY=sk-your-key" - echo "" - echo "QA Tip: Test AI Search performance with PostgreSQL + pgvector!" - echo "" + echo 'Update database.' + time drush -n updb fi -# Finish measuring script time. -script_end_time=$(date +%s) -runtime=$((script_end_time - script_start_time)) -echo "init.sh script ran for" $runtime "seconds" +#== Warm up caches. +echo +echo 'Run cron.' +time drush cron +echo +echo 'Populate caches.' +time drush cache:warm +time .devpanel/warm + +#== Finish measuring script time. +INIT_DURATION=$SECONDS +INIT_HOURS=$(($INIT_DURATION / 3600)) +INIT_MINUTES=$(($INIT_DURATION % 3600 / 60)) +INIT_SECONDS=$(($INIT_DURATION % 60)) +printf "\nTotal elapsed time: %d:%02d:%02d\n" $INIT_HOURS $INIT_MINUTES $INIT_SECONDS diff --git a/.devpanel/warm b/.devpanel/warm new file mode 100755 index 00000000..78b88de4 --- /dev/null +++ b/.devpanel/warm @@ -0,0 +1,17 @@ +#!/usr/bin/env php + TRUE, 1); +require 'index.php'; +ob_end_clean(); +echo "Warmed cache for " . $_SERVER['REQUEST_URI'] . "\n"; diff --git a/.github/workflows/docker-publish-image.yml b/.github/workflows/docker-publish-image.yml index fb516022..51583280 100644 --- a/.github/workflows/docker-publish-image.yml +++ b/.github/workflows/docker-publish-image.yml @@ -33,7 +33,7 @@ jobs: DB_USER: user DB_PASSWORD: password DB_DRIVER: mysql - DP_CORE_VERSION: ${{ inputs.drupal_core_version || '' }} + DP_VERSION: ${{ inputs.drupal_core_version || '' }} ports: - 80:80 volumes: diff --git a/.gitignore b/.gitignore index 89cf65ea..6b896c57 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,15 @@ -# Drupal -/web/ +/.devpanel/dumps/ +/.devpanel/salt.txt +/.editorconfig +/.gitattributes +/.vscode/ +/composer.json +/composer.lock +/config/ +/logs/* +/patches.lock.json +/private/ +/README.md +/recipes/ /vendor/ -composer.json -composer.lock -.editorconfig -.gitattributes - -# DrupalPod -.drupalpod_initiated -src/**/node_modules/ -src/**/package-lock.json -src/**/out/ -src/**/*.vsix -src/**/.vscode-test/ -drush/ -.ddev/config.gitpod.yaml +/web/ diff --git a/.gitpod.yml b/.gitpod.yml deleted file mode 100644 index 6c358201..00000000 --- a/.gitpod.yml +++ /dev/null @@ -1,77 +0,0 @@ -image: drupalpod/drupalpod-gitpod-base:20250309 - -# DDEV and composer are running as part of the prebuild -# when starting a workspace all docker images are ready -tasks: - - init: | - .gitpod/utils/send-a-message-gcs.sh > /tmp/output1.txt - .gitpod/utils/ddev-in-gitpod-setup.sh - .gitpod/utils/set-base-environment.sh - command: | - # Temporary fix for wrong value of GITPOD_REPO_ROOT when opening a Gitpod snapshot - # Todo: remove this when this issue is resolved - https://github.com/gitpod-io/gitpod/issues/9804 - if [ "$GITPOD_REPO_ROOT" == '/workspace' ]; then - export GITPOD_REPO_ROOT="$THEIA_WORKSPACE_ROOT" - fi - .gitpod/utils/ddev-in-gitpod-setup.sh - .gitpod/utils/env-setup.sh - .gitpod/drupal/ssh/01-check-private-ssh.sh - .gitpod/drupal/drupalpod-setup/drupalpod-setup.sh - -# VScode xdebug extension -vscode: - extensions: - # PHP extensions. - - felixfbecker.php-debug - - wongjn.php-sniffer - - neilbrayfield.php-docblocker - - bmewburn.vscode-intelephense-client - - andrewdavidblum.drupal-smart-snippets - - # Twig extensions. - - mblode.twig-language-2 - - # Help extensions. - - drupal-mentoring.drupalpod-ext - - # Bash extensions. - - timonwong.shellcheck - - rogalmic.bash-debug - -ports: - # Used by JS projects - - port: 3000 - onOpen: ignore - # Used by DDEV - local db clients - - port: 3306 - name: Database - description: Access for local database clients - onOpen: ignore - # Used by JS projects - - port: 5000 - onOpen: ignore - # Used by MailHog - - port: 8027 - name: MailHog - description: MailHog - onOpen: ignore - # Used by phpMyAdmin - - port: 8036 - name: phpMyAdmin - description: phpMyAdmin - onOpen: ignore - # Direct-connect DDEV-webserver port that is the main port - - port: 8080 - name: website - description: website - onOpen: ignore - # Ignore host https port - - port: 8443 - name: (not used) - description: host https port - onOpen: ignore - # xdebug port - - port: 9003 - name: xdebug - description: xdebug - onOpen: ignore diff --git a/.gitpod/README.md b/.gitpod/README.md deleted file mode 100644 index 658c01bd..00000000 --- a/.gitpod/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Setting up a new version for DrupalPod - -## Build custom Gitpod image - -1. Update `.gitpod/images/Dockerfile`: - - 1. Update `ddev` latest version. - 1. Update `minio` latest version. - 1. Update `gitui` latest version. - 1. Update `lazygit` latest version. - -1. Generate new custom docker image: - - 1. Run `docker login` to authenticate and push new images to docker hub. - 1. In `/.gitpod/images` run `./push.sh` command to build and push the new custom docker image. - 1. Confirm the process run without errors and that the new custom image gets uploaded to . - 1. Update `/.gitpod.yml` with the new image file. - -1. Push code, and re-open Gitpod workspace, to use latest custom docker image. - -1. Run manual prebuild (to load ddev's images) - -1. Confirm latest setup - 1. Open new workspace. - 1. Check if there are any updates (ie. DDEV's default settings files). - -1. Test various scenarios with DrupalPod browser extension - 1. Confirm core issues work as expected. - 1. Confirm contrib issue work as expected. - -1. Merge PR into `main` branch - -1. Confirm `main` branch work as expected 🎉 diff --git a/.gitpod/drupal/drupalpod-setup/cleanup.sh b/.gitpod/drupal/drupalpod-setup/cleanup.sh deleted file mode 100644 index c9546351..00000000 --- a/.gitpod/drupal/drupalpod-setup/cleanup.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Remove site that was installed before (for debugging) -rm -rf "${GITPOD_REPO_ROOT}"/web -rm -rf "${GITPOD_REPO_ROOT}"/vendor -rm -f "${GITPOD_REPO_ROOT}"/composer.json -rm -f "${GITPOD_REPO_ROOT}"/composer.lock diff --git a/.gitpod/drupal/drupalpod-setup/composer_setup.sh b/.gitpod/drupal/drupalpod-setup/composer_setup.sh deleted file mode 100644 index 4504c102..00000000 --- a/.gitpod/drupal/drupalpod-setup/composer_setup.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# For versions end with x - add `-dev` suffix (ie. 9.3.x-dev) -# For versions without x - add `~` prefix (ie. ~9.2.0) -d="$DP_CORE_VERSION" -case $d in -*.x) - install_version="$d"-dev - ;; -*) - install_version=~"$d" - ;; -esac - -# Create required composer.json and composer.lock files -cd "$GITPOD_REPO_ROOT" && time ddev . composer create -n --no-install drupal/recommended-project:"$install_version" temp-composer-files -cp "$GITPOD_REPO_ROOT"/temp-composer-files/* "$GITPOD_REPO_ROOT"/. -rm -rf "$GITPOD_REPO_ROOT"/temp-composer-files - -# Programmatically fix Composer 2.2 allow-plugins to avoid errors -ddev composer config --no-plugins allow-plugins.composer/installers true -ddev composer config --no-plugins allow-plugins.drupal/core-project-message true -ddev composer config --no-plugins allow-plugins.drupal/core-vendor-hardening true -ddev composer config --no-plugins allow-plugins.drupal/core-composer-scaffold true - -ddev composer config --no-plugins allow-plugins.dealerdirect/phpcodesniffer-composer-installer true -ddev composer config --no-plugins allow-plugins.phpstan/extension-installer true - -ddev composer config --no-plugins allow-plugins.mglaman/composer-drupal-lenient true - -ddev composer config --no-plugins allow-plugins.php-http/discovery true - -ddev composer config --no-plugins allow-plugins.tbachert/spi true - -# Add project source code as symlink (to repos/name_of_project) -# double quotes explained - https://stackoverflow.com/a/1250279/5754049 -if [ -n "$DP_PROJECT_NAME" ]; then - cd "${GITPOD_REPO_ROOT}" && - ddev composer config \ - repositories.core1 \ - '{"type": "path", "url": "repos/'"$DP_PROJECT_NAME"'", "options": {"symlink": true}}' - - cd "$GITPOD_REPO_ROOT" && - ddev composer config minimum-stability dev -fi diff --git a/.gitpod/drupal/drupalpod-setup/contrib_modules_setup.sh b/.gitpod/drupal/drupalpod-setup/contrib_modules_setup.sh deleted file mode 100644 index 6892b60a..00000000 --- a/.gitpod/drupal/drupalpod-setup/contrib_modules_setup.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Check if additional modules should be installed -export DEVEL_NAME="devel" -export DEVEL_PACKAGE="drupal/devel" - -export ADMIN_TOOLBAR_NAME="admin_toolbar_tools" -export ADMIN_TOOLBAR_PACKAGE="drupal/admin_toolbar" - -# TODO: once Drupalpod extension supports additional modules - remove these 2 lines -export DP_EXTRA_DEVEL=1 -export DP_EXTRA_ADMIN_TOOLBAR=1 - -# Adding support for composer-drupal-lenient - https://packagist.org/packages/mglaman/composer-drupal-lenient -if [[ "$DP_CORE_VERSION" =~ ^10(\..*)?$ ]]; then - if [ "$DP_PROJECT_TYPE" != "project_core" ]; then - export COMPOSER_DRUPAL_LENIENT=mglaman/composer-drupal-lenient - else - export COMPOSER_DRUPAL_LENIENT='' - fi -fi - -# Adding support for composer-drupal-lenient - https://packagist.org/packages/mglaman/composer-drupal-lenient -if [[ "$DP_CORE_VERSION" =~ ^11(\..*)?$ ]]; then - # admin_toolbar and devel are not compatible yet with Drupal 11 - export DP_EXTRA_ADMIN_TOOLBAR= - export DP_EXTRA_DEVEL= - if [ "$DP_PROJECT_TYPE" != "project_core" ]; then - export COMPOSER_DRUPAL_LENIENT=mglaman/composer-drupal-lenient - else - export COMPOSER_DRUPAL_LENIENT='' - fi -fi diff --git a/.gitpod/drupal/drupalpod-setup/ddev_setup.sh b/.gitpod/drupal/drupalpod-setup/ddev_setup.sh deleted file mode 100644 index 691a98c1..00000000 --- a/.gitpod/drupal/drupalpod-setup/ddev_setup.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# set PHP version, based on https://www.drupal.org/docs/getting-started/system-requirements/php-requirements#versions -major_version=$(echo "$DP_CORE_VERSION" | cut -d '.' -f 1) -minor_version=$(echo "$DP_CORE_VERSION" | cut -d '.' -f 2) - -# Before Drupal 10.2, we should use php 8.2, otherwise use php 8.3 -if (( major_version < 10 )) || { (( major_version == 10 )) && (( minor_version < 2 )); }; then - php_version="8.2" -else - php_version="8.3" -fi - -cat < "${GITPOD_REPO_ROOT}"/.ddev/config.gitpod.yaml -#ddev-gitpod-generated -php_version: "$php_version" -CONFIGEND - -time ddev start diff --git a/.gitpod/drupal/drupalpod-setup/drupal_setup_contrib.sh b/.gitpod/drupal/drupalpod-setup/drupal_setup_contrib.sh deleted file mode 100644 index 608e7d6d..00000000 --- a/.gitpod/drupal/drupalpod-setup/drupal_setup_contrib.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Drupal projects with no composer.json, bypass the symlink config, symlink has to be created manually. - -if [ "$DP_PROJECT_TYPE" == "project_module" ]; then - PROJECT_TYPE=modules -elif [ "$DP_PROJECT_TYPE" == "project_theme" ]; then - PROJECT_TYPE=themes -fi - -cat <"${GITPOD_REPO_ROOT}"/repos/add-project-as-symlink.sh -#!/usr/bin/env bash -# This file was dynamically generated by a script -echo "Replace project with a symlink" -rm -rf web/$PROJECT_TYPE/contrib/$DP_PROJECT_NAME -cd web/$PROJECT_TYPE/contrib && ln -s ../../../repos/$DP_PROJECT_NAME . -PROJECTASYMLINK - -chmod +x "${GITPOD_REPO_ROOT}"/repos/add-project-as-symlink.sh - -if [ -n "$COMPOSER_DRUPAL_LENIENT" ]; then - # Add composer_drupal_lenient for modules on Drupal 10 - cd "${GITPOD_REPO_ROOT}" && ddev composer config --merge --json extra.drupal-lenient.allowed-list '["drupal/'"$DP_PROJECT_NAME"'"]' - cd "${GITPOD_REPO_ROOT}" && time ddev . composer require "$COMPOSER_DRUPAL_LENIENT" -fi -# Add the project to composer (it will get the version according to the branch under `/repo/name_of_project`) -cd "${GITPOD_REPO_ROOT}" && time ddev . composer require drupal/"$DP_PROJECT_NAME" --no-interaction --no-install diff --git a/.gitpod/drupal/drupalpod-setup/drupal_setup_core.sh b/.gitpod/drupal/drupalpod-setup/drupal_setup_core.sh deleted file mode 100644 index cea31188..00000000 --- a/.gitpod/drupal/drupalpod-setup/drupal_setup_core.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Add a special path when working on core contributions -# (Without it, /web/modules/contrib is not found by website) -cd "${GITPOD_REPO_ROOT}" && - ddev composer config \ - repositories.drupal-core2 \ - '{"type": "path", "url": "repos/drupal/core"}' - -cd "${GITPOD_REPO_ROOT}" && - ddev composer config \ - repositories.drupal-core3 \ - '{"type": "path", "url": "repos/drupal/composer/Metapackage/CoreRecommended"}' - -cd "${GITPOD_REPO_ROOT}" && - ddev composer config \ - repositories.drupal-core4 \ - '{"type": "path", "url": "repos/drupal/composer/Metapackage/DevDependencies"}' - -cd "${GITPOD_REPO_ROOT}" && - ddev composer config \ - repositories.drupal-core5 \ - '{"type": "path", "url": "repos/drupal/composer/Plugin/ProjectMessage"}' - -cd "${GITPOD_REPO_ROOT}" && - ddev composer config \ - repositories.drupal-core6 \ - '{"type": "path", "url": "repos/drupal/composer/Plugin/VendorHardening"}' - -# Removing the conflict part of composer -echo "$(cat composer.json | jq 'del(.conflict)' --indent 4)" >composer.json - -# If a core issue branch was chosen, we want the version of Drupal core that is in that issue branch -# This is very helpful for issues that started with previous Drupal core versions, and the issue version automatically got updated to latest current drupal version -if [ "$DP_PROJECT_TYPE" == "project_core" ] && [ -n "$DP_ISSUE_BRANCH" ]; then - time composer require drupal/core-recommended:* drupal/core-project-message:* drupal/core-composer-scaffold:* --no-update -fi - -# Only after composer update, /web/core get symlinked to /repos/drupal/core -# repos/drupal/core -> web/core -time composer update - -# vendor -> repos/drupal/vendor -if [ ! -L "$GITPOD_REPO_ROOT"/repos/drupal/vendor ]; then - cd "$GITPOD_REPO_ROOT"/repos/drupal && - ln -s ../../vendor . -fi - -# Create folders for running tests -mkdir -p "$GITPOD_REPO_ROOT"/web/sites/simpletest -mkdir -p "$GITPOD_REPO_ROOT"/web/sites/simpletest/browser_output - -# Symlink the simpletest folder into the Drupal core git repo. -# repos/drupal/sites/simpletest -> ../../../web/sites/simpletest -if [ ! -L "$GITPOD_REPO_ROOT"/repos/drupal/sites/simpletest ]; then - cd "$GITPOD_REPO_ROOT"/repos/drupal/sites && - ln -s ../../../web/sites/simpletest . -fi diff --git a/.gitpod/drupal/drupalpod-setup/drupalpod-setup.md b/.gitpod/drupal/drupalpod-setup/drupalpod-setup.md deleted file mode 100644 index f9047dd7..00000000 --- a/.gitpod/drupal/drupalpod-setup/drupalpod-setup.md +++ /dev/null @@ -1,18 +0,0 @@ -# File Structure - -The drupalpod-setup.sh script can be divided into several logical sections based on the tasks it performs. Here are some potential divisions: - -1. Environment Setup: This section sets up the environment variables and checks for certain conditions. It includes the loading of default environment variables, setting up the default setup during the prebuild process, and checking if additional modules should be installed. - -1. Composer Support: This section adds support for composer-drupal-lenient based on the Drupal core version. - -1. Drupal Setup: This section checks if the setup has already run once and if no special setup is set by the DrupalPod extension. If not, it performs a series of setup tasks, including adding git.drupal.org to known hosts, ignoring specific directories during Drupal core development, and getting the required repo ready. - -1. Drupal Installation: This section handles the installation of Drupal, including enabling extra modules, setting the default admin theme, enabling the requested module or theme, and updating the database if working on core. - -1. Post-Installation: This section takes a snapshot of the database, saves a file to mark the workspace as already initiated, and measures the script time. - -1. Sourced Files: - - `setup_env.sh`: Sets up default environment variables based on a `.env` file. - - `install_modules.sh`: Sets environment variables for installing additional modules in Drupal. - - `drupal_version_specifics.sh`: Adds support for the `composer-drupal-lenient` package based on the Drupal core version. diff --git a/.gitpod/drupal/drupalpod-setup/drupalpod-setup.sh b/.gitpod/drupal/drupalpod-setup/drupalpod-setup.sh deleted file mode 100755 index a9bc05d9..00000000 --- a/.gitpod/drupal/drupalpod-setup/drupalpod-setup.sh +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Initialize all variables with null if they do not exist -: "${DEBUG_SCRIPT:=}" -: "${GITPOD_HEADLESS:=}" -: "${DP_INSTALL_PROFILE:=}" -: "${DP_EXTRA_DEVEL:=}" -: "${DP_EXTRA_ADMIN_TOOLBAR:=}" -: "${DP_PROJECT_TYPE:=}" -: "${DEVEL_NAME:=}" -: "${DEVEL_PACKAGE:=}" -: "${ADMIN_TOOLBAR_NAME:=}" -: "${ADMIN_TOOLBAR_PACKAGE:=}" -: "${COMPOSER_DRUPAL_LENIENT:=}" -: "${DP_CORE_VERSION:=}" -: "${DP_ISSUE_BRANCH:=}" -: "${DP_ISSUE_FORK:=}" -: "${DP_MODULE_VERSION:=}" -: "${DP_PATCH_FILE:=}" - -# Assuming .sh files are in the same directory as this script -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" - -if [ -n "$DEBUG_SCRIPT" ] || [ -n "$GITPOD_HEADLESS" ]; then - set -x -fi - -convert_version() { - local version=$1 - if [[ $version =~ "-" ]]; then - # Remove the part after the dash and replace the last numeric segment with 'x' - local base_version=${version%-*} - echo "${base_version%.*}.x" - else - echo "$version" - fi -} - -# Test cases -# echo $(convert_version "9.2.5-dev1") # Output: 9.2.x -# echo $(convert_version "9.2.5") # Output: 9.2.5 -# echo $(convert_version "10.1.0-beta1") # Output: 10.1.x -# echo $(convert_version "11.0-dev") # Output: 11.x - -# Skip setup if it already ran once and if no special setup is set by DrupalPod extension -if [ ! -f "${GITPOD_REPO_ROOT}"/.drupalpod_initiated ]; then - - # Set a default setup if project type wasn't specified - if [ -z "$DP_PROJECT_TYPE" ]; then - source "$DIR/fallback_setup.sh" - fi - - source "$DIR/git_setup.sh" - - # If this is an issue fork of Drupal core - set the drupal core version based on that issue fork - if [ "$DP_PROJECT_TYPE" == "project_core" ] && [ -n "$DP_ISSUE_FORK" ]; then - VERSION_FROM_GIT=$(grep 'const VERSION' "${GITPOD_REPO_ROOT}"/repos/drupal/core/lib/Drupal.php | awk -F "'" '{print $2}') - DP_CORE_VERSION=$(convert_version "$VERSION_FROM_GIT") - export DP_CORE_VERSION - fi - - source "$DIR/ddev_setup.sh" - - # Measure the time it takes to go through the script - script_start_time=$(date +%s) - - source "$DIR/contrib_modules_setup.sh" - source "$DIR/cleanup.sh" - source "$DIR/composer_setup.sh" - - if [ -n "$DP_PATCH_FILE" ]; then - echo Applying selected patch "$DP_PATCH_FILE" - cd "${WORK_DIR}" && curl "$DP_PATCH_FILE" | patch -p1 - fi - - # Prepare special setup to work with Drupal core - if [ "$DP_PROJECT_TYPE" == "project_core" ]; then - source "$DIR/drupal_setup_core.sh" - # Prepare special setup to work with Drupal contrib - elif [ -n "$DP_PROJECT_NAME" ]; then - source "$DIR/drupal_setup_contrib.sh" - fi - - time "${GITPOD_REPO_ROOT}"/.gitpod/drupal/install-essential-packages.sh - # Configure phpcs for drupal. - cd "$GITPOD_REPO_ROOT" && - vendor/bin/phpcs --config-set installed_paths vendor/drupal/coder/coder_sniffer - - # ddev config auto updates settings.php and generates settings.ddev.php - ddev config --auto - # New site install - time ddev drush si -y --account-pass=admin --site-name="DrupalPod" "$DP_INSTALL_PROFILE" - - # Install devel and admin_toolbar modules - if [ "$DP_EXTRA_DEVEL" != '1' ]; then - DEVEL_NAME= - fi - if [ "$DP_EXTRA_ADMIN_TOOLBAR" != '1' ]; then - ADMIN_TOOLBAR_NAME= - fi - - # Enable extra modules - cd "${GITPOD_REPO_ROOT}" && - ddev drush en -y \ - "$ADMIN_TOOLBAR_NAME" \ - "$DEVEL_NAME" - - # Enable the requested module - if [ "$DP_PROJECT_TYPE" == "project_module" ]; then - cd "${GITPOD_REPO_ROOT}" && ddev drush en -y "$DP_PROJECT_NAME" - fi - - # Enable the requested theme - if [ "$DP_PROJECT_TYPE" == "project_theme" ]; then - cd "${GITPOD_REPO_ROOT}" && ddev drush then -y "$DP_PROJECT_NAME" - cd "${GITPOD_REPO_ROOT}" && ddev drush config-set -y system.theme default "$DP_PROJECT_NAME" - fi - - # Take a snapshot - cd "${GITPOD_REPO_ROOT}" && ddev snapshot - echo "Your database state was locally saved, you can revert to it by typing:" - echo "ddev snapshot restore --latest" - - # Save a file to mark workspace already initiated - touch "${GITPOD_REPO_ROOT}"/.drupalpod_initiated - - # Finish measuring script time - script_end_time=$(date +%s) - runtime=$((script_end_time - script_start_time)) - echo "drupalpod-setup.sh script ran for" $runtime "seconds" -else - cd "${GITPOD_REPO_ROOT}" && ddev start -fi - -# Open internal preview browser with current website -preview diff --git a/.gitpod/drupal/drupalpod-setup/fallback_setup.sh b/.gitpod/drupal/drupalpod-setup/fallback_setup.sh deleted file mode 100644 index b444e567..00000000 --- a/.gitpod/drupal/drupalpod-setup/fallback_setup.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Set a default setup (when project type is not specified) -export DP_INSTALL_PROFILE='demo_umami' -export DP_PROJECT_TYPE='project_core' -export DP_PROJECT_NAME="drupal" -export DP_CORE_VERSION='11.2.5' -export DP_EXTRA_DEVEL=1 -export DP_EXTRA_ADMIN_TOOLBAR=1 diff --git a/.gitpod/drupal/drupalpod-setup/git_setup.sh b/.gitpod/drupal/drupalpod-setup/git_setup.sh deleted file mode 100644 index 3ec3947c..00000000 --- a/.gitpod/drupal/drupalpod-setup/git_setup.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Add git.drupal.org to known_hosts -if [ -z "$GITPOD_HEADLESS" ]; then - mkdir -p ~/.ssh - host=git.drupal.org - SSHKey=$(ssh-keyscan $host 2>/dev/null) - echo "$SSHKey" >>~/.ssh/known_hosts -fi - -# Ignore specific directories during Drupal core development -cp "${GITPOD_REPO_ROOT}"/.gitpod/drupal/templates/git-exclude.template "${GITPOD_REPO_ROOT}"/.git/info/exclude - -# Get the required repo ready -if [ "$DP_PROJECT_TYPE" == "project_core" ]; then - # Find if requested core version is dev or stable - d="$DP_CORE_VERSION" - case $d in - *.x) - # If dev - use git checkout origin/* - checkout_type=origin - ;; - *) - # stable - use git checkout tags/* - checkout_type=tags - ;; - esac - - # Use origin or tags in git checkout command - cd "${GITPOD_REPO_ROOT}"/repos/drupal && - git fetch origin && - git fetch --all --tags && - git checkout "$checkout_type"/"$DP_CORE_VERSION" - - # Ignore specific directories during Drupal core development - cp "${GITPOD_REPO_ROOT}"/.gitpod/drupal/templates/git-exclude.template "${GITPOD_REPO_ROOT}"/repos/drupal/.git/info/exclude -else - # If not core - clone selected project into /repos and remove drupal core - rm -rf "${GITPOD_REPO_ROOT}"/repos/drupal - if [ ! -d repos/"${DP_PROJECT_NAME}" ]; then - mkdir -p repos - cd "${GITPOD_REPO_ROOT}"/repos && time git clone https://git.drupalcode.org/project/"$DP_PROJECT_NAME".git - fi -fi - -# Set WORK_DIR -export WORK_DIR="${GITPOD_REPO_ROOT}"/repos/$DP_PROJECT_NAME - -# Dynamically generate .gitmodules file -cat <"${GITPOD_REPO_ROOT}"/.gitmodules -# This file was dynamically generated by a script -[submodule "$DP_PROJECT_NAME"] -path = repos/$DP_PROJECT_NAME -url = https://git.drupalcode.org/project/$DP_PROJECT_NAME.git -ignore = dirty -GITMODULESEND - -# Checkout specific branch only if there's issue_branch -if [ -n "$DP_ISSUE_BRANCH" ]; then - # If branch already exist only run checkout, - if cd "${WORK_DIR}" && git show-ref -q --heads "$DP_ISSUE_BRANCH"; then - cd "${WORK_DIR}" && git checkout "$DP_ISSUE_BRANCH" - else - cd "${WORK_DIR}" && git remote add "$DP_ISSUE_FORK" https://git.drupalcode.org/issue/"$DP_ISSUE_FORK".git - cd "${WORK_DIR}" && git fetch "$DP_ISSUE_FORK" - cd "${WORK_DIR}" && git checkout -b "$DP_ISSUE_BRANCH" --track "$DP_ISSUE_FORK"/"$DP_ISSUE_BRANCH" - fi -elif [ -n "$DP_MODULE_VERSION" ] && [ "$DP_PROJECT_TYPE" != "project_core" ]; then - cd "${WORK_DIR}" && git checkout "$DP_MODULE_VERSION" -fi diff --git a/.gitpod/drupal/install-essential-packages.sh b/.gitpod/drupal/install-essential-packages.sh deleted file mode 100755 index 590c551d..00000000 --- a/.gitpod/drupal/install-essential-packages.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Initialize all variables with null if they do not exist -: "${DEBUG_SCRIPT:=}" -: "${GITPOD_HEADLESS:=}" -: "${DP_EXTRA_DEVEL:=}" -: "${DP_EXTRA_ADMIN_TOOLBAR:=}" -: "${DEVEL_PACKAGE:=}" -: "${ADMIN_TOOLBAR_PACKAGE:=}" - -if [ -n "$DEBUG_SCRIPT" ] || [ -n "$GITPOD_HEADLESS" ]; then - set -x -fi - -# Install devel and admin_toolbar modules -if [ "$DP_EXTRA_DEVEL" != '1' ]; then - DEVEL_PACKAGE= -fi -if [ "$DP_EXTRA_ADMIN_TOOLBAR" != '1' ]; then - ADMIN_TOOLBAR_PACKAGE= -fi - -cd "${GITPOD_REPO_ROOT}" && time ddev . composer require --dev "drupal/core-dev":* "phpspec/prophecy-phpunit":^2 -W --no-install -cd "${GITPOD_REPO_ROOT}" && time ddev . composer require "drush/drush" "drupal/coder" "$DEVEL_PACKAGE" "$ADMIN_TOOLBAR_PACKAGE" - -# Only for Drupal core - apply special patch -if [ "$DP_PROJECT_TYPE" == "project_core" ]; then - # Patch the scaffold index.php and update.php files - # See https://www.drupal.org/project/drupal/issues/3188703 - # See https://www.drupal.org/project/drupal/issues/1792310 - echo "$(cat composer.json | jq '.scripts."post-install-cmd" |= . + ["src/composer-drupal-core-setup/patch-core-index-and-update.sh"]')" >composer.json - echo "$(cat composer.json | jq '.scripts."post-update-cmd" |= . + ["src/composer-drupal-core-setup/patch-core-index-and-update.sh"]')" >composer.json - - # Run the patch once - time src/composer-drupal-core-setup/patch-core-index-and-update.sh - - # Get the major version of 'drush/drush' - drush_major_version=$(composer show drush/drush --no-ansi | awk '/versions/ {print $NF}' | cut -d '.' -f1) - - drush_command_dir="$GITPOD_REPO_ROOT/drush/Commands/core_development" - mkdir -p "$drush_command_dir" - - # Copy the correct version of DevelopmentProjectCommands.php file to the drush commands directory - cp "$GITPOD_REPO_ROOT/src/drush-commands-core-development/$drush_major_version/DevelopmentProjectCommands.php" "$drush_command_dir/." -else - # Only for contrib - add project as symlink - - echo "$(cat composer.json | jq '.scripts."post-install-cmd" |= . + ["repos/add-project-as-symlink.sh"]')" >composer.json - echo "$(cat composer.json | jq '.scripts."post-update-cmd" |= . + ["repos/add-project-as-symlink.sh"]')" >composer.json - time repos/add-project-as-symlink.sh -fi diff --git a/.gitpod/drupal/ssh/00-interactive-ssh-setup.sh b/.gitpod/drupal/ssh/00-interactive-ssh-setup.sh deleted file mode 100755 index 3b2df726..00000000 --- a/.gitpod/drupal/ssh/00-interactive-ssh-setup.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - - -# Copy your public key -# php -S localhost:8000 id_rsa.backup & sleep 3 & gp preview $(gp url 8000) -# killall php - -# while-menu-dialog: a menu driven system information program - -DIALOG_CANCEL=1 -DIALOG_ESC=255 -HEIGHT=0 -WIDTH=0 - -display_result() { - dialog --title "$1" \ - --no-collapse \ - --msgbox "$result" 0 0 -} - -while true; do - exec 3>&1 - selection=$(dialog \ - --backtitle "Installer/Services menu" \ - --title "Menu" \ - --clear \ - --cancel-label "Exit" \ - --menu "Please select:" $HEIGHT $WIDTH 4 \ - "1" "Setup SSH" \ - 2>&1 1>&3) - exit_status=$? - exec 3>&- - case $exit_status in - $DIALOG_CANCEL) - clear - echo "Program terminated." - exit - ;; - $DIALOG_ESC) - clear - echo "Program aborted." >&2 - exit 1 - ;; - esac - case $selection in - 0 ) - clear - echo "Program terminated." - ;; - 1 ) - result=$(code .gitpod/drupal/ssh/instructions-template.md) - display_result "If you completed the instructions above - click OK" - .gitpod/drupal/ssh/04-confirm-ssh-setup.sh - # gp preview https://drupal.org/user --external - ;; - esac -done - diff --git a/.gitpod/drupal/ssh/01-check-private-ssh.sh b/.gitpod/drupal/ssh/01-check-private-ssh.sh deleted file mode 100755 index 0cd3c587..00000000 --- a/.gitpod/drupal/ssh/01-check-private-ssh.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi - -# Check if ~/.ssh/id_rsa already exist -if [ -f ~/.ssh/id_rsa ]; then - echo "No need to setup a key, SSH key already exists." -else - if [ -z "$DRUPAL_SSH_KEY" ]; then - # DRUPAL_SSH_KEY environment variable is not set, check if SSH ley was create during this session - if [ -f /workspace/id_rsa ] ; then - # Edge case where user already setup key in workspace that timed out. - echo "No need to setup a key, SSH key found." - mkdir -p ~/.ssh - cp /workspace/id_rsa ~/.ssh/. - fi - else - echo "Setting SSH key from environment variable" - mkdir -p ~/.ssh - printenv DRUPAL_SSH_KEY > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - fi - # Ask for SSH keyphrase only once - if ssh-add -l > /dev/null ; then - eval "$(ssh-agent -s)" > /dev/null - ssh-add -q ~/.ssh/id_rsa - fi -fi diff --git a/.gitpod/drupal/ssh/02-setup-private-ssh.sh b/.gitpod/drupal/ssh/02-setup-private-ssh.sh deleted file mode 100755 index 48712708..00000000 --- a/.gitpod/drupal/ssh/02-setup-private-ssh.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi - -SSH_SETUP_REQUIRED=true - -# Add git.drupal.org to known_hosts -mkdir -p ~/.ssh -host=git.drupal.org -SSHKey=$(ssh-keyscan $host 2> /dev/null) -echo "$SSHKey" >> ~/.ssh/known_hosts - -# Validate private SSH key in Gitpod with public SSH key in drupal.org -if ssh -T git@git.drupal.org; then - read -r -p "SSH key was already confirmed with Drupal.org, are you sure you want to recreate SSH key? [y/N]" setup_ssh - if [ "$setup_ssh" != "y" ] && [ "$setup_ssh" != "Y" ]; then - SSH_SETUP_REQUIRED=false - fi -fi - -if $SSH_SETUP_REQUIRED; then - # Create ssh key pairing + instructions to paste public key in drupal.org - ssh-keygen -q -t rsa -b 4096 -f ~/.ssh/id_rsa - .gitpod/drupal/ssh/03-generate-drupal-ssh-instructions.sh - echo "Follow instructions for copying public key to Drupal" - echo "Test SSH by running .gitpod/drupal/ssh/04-confirm-ssh-setup.sh" -fi diff --git a/.gitpod/drupal/ssh/03-generate-drupal-ssh-instructions.sh b/.gitpod/drupal/ssh/03-generate-drupal-ssh-instructions.sh deleted file mode 100755 index 3c0b1044..00000000 --- a/.gitpod/drupal/ssh/03-generate-drupal-ssh-instructions.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi - -# create instructions file with user's public key -cat ~/.ssh/id_rsa.pub > /workspace/public_key.md -cat .gitpod/drupal/ssh/instructions-template.md > /workspace/drupal-public-key-setup.md -cat ~/.ssh/id_rsa.pub >> /workspace/drupal-public-key-setup.md - -gp open /workspace/drupal-public-key-setup.md diff --git a/.gitpod/drupal/ssh/04-confirm-ssh-setup.sh b/.gitpod/drupal/ssh/04-confirm-ssh-setup.sh deleted file mode 100755 index 7a903d02..00000000 --- a/.gitpod/drupal/ssh/04-confirm-ssh-setup.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi - -# Add git.drupal.org to known_hosts -mkdir -p ~/.ssh -host=git.drupal.org -SSHKey=$(ssh-keyscan $host 2> /dev/null) -echo "$SSHKey" >> ~/.ssh/known_hosts - -# Ask for SSH keyphrase only once -if ssh-add -l > /dev/null ; then - eval "$(ssh-agent -s)" > /dev/null - ssh-add -q ~/.ssh/id_rsa -fi - -# Validate private SSH key in Gitpod with public SSH key in drupal.org -if ssh -T git@git.drupal.org; then - echo "Setup was succesful, saving your private key in Gitpod" - # Set private SSH key as Gitpod variable anvironment - gp env "DRUPAL_SSH_KEY=$(cat ~/.ssh/id_rsa)" > /dev/null - # Copy key to /workspace in case this workspace times out - cp ~/.ssh/id_rsa /workspace/. - # Set repo remote branch to SSH (in case it was added as HTTPS) - .gitpod/drupal/ssh/05-set-repo-as-ssh.sh -else - if [ ! -f ~/.ssh/id_rsa.pub ] ; then - echo "Setup failed, create private key again" - rm -f /workspace/id_rsa - rm -rf ~/.ssh - .gitpod/drupal/ssh/02-setup-private-ssh.sh - else - echo "Setup failed, please confirm you copied public key to Drupal" - .gitpod/drupal/ssh/03-generate-drupal-ssh-instructions.sh - fi -fi diff --git a/.gitpod/drupal/ssh/05-set-repo-as-ssh.sh b/.gitpod/drupal/ssh/05-set-repo-as-ssh.sh deleted file mode 100755 index 7b57b25d..00000000 --- a/.gitpod/drupal/ssh/05-set-repo-as-ssh.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi - -# Set a specific branch if there's issue_fork -if [ -n "$DP_ISSUE_FORK" ]; then - cd "${GITPOD_REPO_ROOT}"/repos/"$DP_PROJECT_NAME" && git remote set-url "$DP_ISSUE_FORK" git@git.drupal.org:issue/"$DP_ISSUE_FORK".git -fi diff --git a/.gitpod/drupal/ssh/instructions-template.md b/.gitpod/drupal/ssh/instructions-template.md deleted file mode 100644 index e8434fde..00000000 --- a/.gitpod/drupal/ssh/instructions-template.md +++ /dev/null @@ -1,14 +0,0 @@ -# One-time public key setup -1. Press the OK button in the Terminal below and follow the instructions. -2. Open https://www.drupal.org/user -3. Click on "Git Access" -4. Create a Git username if you don't have one. -5. Click on "SSH keys", -6. Click on "Add a public key" -7. Copy the content below -8. Paste it inside "Key" field -9. Click on "Save" button. -10. Run in Gitpod terminal `.gitpod/drupal/ssh/04-confirm-ssh-setup.sh` - - - diff --git a/.gitpod/drupal/templates/git-exclude.template b/.gitpod/drupal/templates/git-exclude.template deleted file mode 100644 index 1c6ce4a2..00000000 --- a/.gitpod/drupal/templates/git-exclude.template +++ /dev/null @@ -1,10 +0,0 @@ -# git ls-files --others --exclude-from=.git/info/exclude -# Lines that start with '#' are comments. -# For a project mostly in C, the following would be a good set of -# exclude patterns (uncomment them if you want to use them): -# *.[oa] -# *~ -# Exclude the following directories for Drupal core development -vendor -sites/simpletest -sites/default/settings.php diff --git a/.gitpod/images/Dockerfile b/.gitpod/images/Dockerfile deleted file mode 100644 index 298779ba..00000000 --- a/.gitpod/images/Dockerfile +++ /dev/null @@ -1,40 +0,0 @@ -FROM gitpod/workspace-base as workspace-base -SHELL ["/bin/bash", "-c"] - -RUN sudo apt-get -qq update - -# Install dialog (interactive script) -RUN sudo apt-get -qq install -y dialog - -# Install DDEV -USER gitpod -# Add DDEV’s GPG key to your keyring -RUN curl -fsSL https://pkg.ddev.com/apt/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/ddev.gpg > /dev/null -# Add DDEV releases to your package repository -RUN echo "deb [signed-by=/etc/apt/keyrings/ddev.gpg] https://pkg.ddev.com/apt/ * *" | sudo tee /etc/apt/sources.list.d/ddev.list >/dev/null -# Update package information and install DDEV -RUN sudo apt-get update && sudo apt-get install -y ddev - -# Install GitUI (terminal-ui for git) -ARG GITUI_VERSION=v0.27.0 -RUN wget https://github.com/extrawurst/gitui/releases/download/${GITUI_VERSION}/gitui-linux-x86_64.tar.gz -P /tmp -RUN sudo tar xzf /tmp/gitui-linux-x86_64.tar.gz -C /usr/bin - -# Install LazyGit (terminal-ui for git) -ARG LAZYGIT_VERSION=0.48.0 -RUN wget https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz -P /tmp -RUN tar -C /tmp -xf /tmp/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz -RUN sudo install /tmp/lazygit /usr/local/bin - -# (get latest Minio version from https://dl.min.io/client/mc/release/linux-amd64/) -# Install Minio client -ARG MINIO_CLIENT_VERSION=mcli_20250221160046.0.0_amd64.deb -RUN wget https://dl.min.io/client/mc/release/linux-amd64/${MINIO_CLIENT_VERSION} -RUN sudo dpkg -i ${MINIO_CLIENT_VERSION} -RUN sudo mv /usr/local/bin/mcli /usr/local/bin/mc - -# End workspace-base - -FROM scratch as drupalpod-gitpod-base -SHELL ["/bin/bash", "-c"] -COPY --from=workspace-base / / diff --git a/.gitpod/images/push.sh b/.gitpod/images/push.sh deleted file mode 100755 index 8a146fb2..00000000 --- a/.gitpod/images/push.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -eu -o pipefail -# if [ -n "$DEBUG_SCRIPT" ]; then -# set -x -# fi - -# Run `docker login` to authenticate and push new images to docker hub -# Update /.gitpod.yml with the new image file - -# "%Y-%m-%d" -TODAY=$(date +"%Y%m%d") -REPO_NAME=drupalpod/drupalpod-gitpod-base -DOCKER_REPO="$REPO_NAME":"$TODAY" -DOCKER_REPO_LATEST="$REPO_NAME":latest - -echo "Pushing ${DOCKER_REPO}" -set -x -# Build only current architecture and load into docker -# docker buildx build -t "${DOCKER_REPO}" --push --target=drupalpod-gitpod-base --platform=linux/amd64 . -docker build --target drupalpod-gitpod-base -t "${DOCKER_REPO}" -t "${DOCKER_REPO_LATEST}" . -docker image push "${DOCKER_REPO}" -docker image push "${DOCKER_REPO_LATEST}" - -# docker run -it --rm bash -# docker image inspect diff --git a/.gitpod/utils/ddev-in-gitpod-setup.sh b/.gitpod/utils/ddev-in-gitpod-setup.sh deleted file mode 100755 index c03dfe6f..00000000 --- a/.gitpod/utils/ddev-in-gitpod-setup.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ] || [ -n "$GITPOD_HEADLESS" ]; then - set -x -fi - -# Misc housekeeping before start -ddev config global --instrumentation-opt-in=true diff --git a/.gitpod/utils/env-setup.sh b/.gitpod/utils/env-setup.sh deleted file mode 100755 index 84361ac7..00000000 --- a/.gitpod/utils/env-setup.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi - -cd "${GITPOD_REPO_ROOT}"/.gitpod/utils/script-templates || exit - -# Create a phpstorm command -sudo cp phpstorm.template.sh /usr/local/bin/phpstorm - -# Create a preview command -sudo cp preview.template.sh /usr/local/bin/preview - -# Create a protect-my-git command -sudo cp protect-my-git.template.sh /usr/local/bin/protect-my-git - -# Create php command (run php inside ddev container) -sudo cp ddev-php.template.sh /usr/local/bin/php - -# Create drush command (run drush inside ddev container) -sudo cp ddev-drush.template.sh /usr/local/bin/drush - -# Create yarn command (run yarn inside ddev container) -sudo cp ddev-yarn.template.sh /usr/local/bin/yarn - -# Create composer command (run composer inside ddev container) -sudo cp ddev-composer.template.sh /usr/local/bin/composer - -# Create node command (run composer inside ddev container) -sudo cp ddev-node.template.sh /usr/local/bin/node - -# Create nvm command (run composer inside ddev container) -sudo cp ddev-nvm.template.sh /usr/local/bin/nvm - -# Create npx command (run composer inside ddev container) -sudo cp ddev-npx.template.sh /usr/local/bin/npx diff --git a/.gitpod/utils/script-templates/ddev-composer.template.sh b/.gitpod/utils/script-templates/ddev-composer.template.sh deleted file mode 100755 index 138f48b2..00000000 --- a/.gitpod/utils/script-templates/ddev-composer.template.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -echo "Notice: running 'composer $*' in ddev" -ddev exec_d composer "$@" diff --git a/.gitpod/utils/script-templates/ddev-drush.template.sh b/.gitpod/utils/script-templates/ddev-drush.template.sh deleted file mode 100755 index 7ac0f909..00000000 --- a/.gitpod/utils/script-templates/ddev-drush.template.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -echo "Notice: running 'drush $*' in ddev" -ddev exec_d drush "$@" diff --git a/.gitpod/utils/script-templates/ddev-node.template.sh b/.gitpod/utils/script-templates/ddev-node.template.sh deleted file mode 100755 index 5a309527..00000000 --- a/.gitpod/utils/script-templates/ddev-node.template.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -echo "Notice: running 'node $*' in ddev" -ddev exec_d node "$@" diff --git a/.gitpod/utils/script-templates/ddev-npx.template.sh b/.gitpod/utils/script-templates/ddev-npx.template.sh deleted file mode 100755 index 73eeeee0..00000000 --- a/.gitpod/utils/script-templates/ddev-npx.template.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -echo "Notice: running 'npx $*' in ddev" -ddev exec_d npx "$@" diff --git a/.gitpod/utils/script-templates/ddev-nvm.template.sh b/.gitpod/utils/script-templates/ddev-nvm.template.sh deleted file mode 100755 index acd5c457..00000000 --- a/.gitpod/utils/script-templates/ddev-nvm.template.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -echo "Notice: running 'nvm $*' in ddev" -ddev exec_d nvm "$@" diff --git a/.gitpod/utils/script-templates/ddev-php.template.sh b/.gitpod/utils/script-templates/ddev-php.template.sh deleted file mode 100755 index 610926b9..00000000 --- a/.gitpod/utils/script-templates/ddev-php.template.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -echo "Notice: running 'php $*' in ddev" -ddev exec_d php "$@" diff --git a/.gitpod/utils/script-templates/ddev-yarn.template.sh b/.gitpod/utils/script-templates/ddev-yarn.template.sh deleted file mode 100755 index d3ffa815..00000000 --- a/.gitpod/utils/script-templates/ddev-yarn.template.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -echo "Notice: running 'yarn $*' in ddev" -ddev exec_d yarn "$@" diff --git a/.gitpod/utils/script-templates/phpstorm.template.sh b/.gitpod/utils/script-templates/phpstorm.template.sh deleted file mode 100755 index 48c04d26..00000000 --- a/.gitpod/utils/script-templates/phpstorm.template.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi - -if [ ! -x ~/.projector/configs/PhpStorm/run.sh ]; then - echo "PhpStorm runner not found" && exit 1 -fi - -# When port 9999 is ready - open that port in a new browser tab -gp await-port 9999 && gp preview "$(gp url 9999)" --external & - -# Run PHPStorm -~/.projector/configs/PhpStorm/run.sh "$GITPOD_REPO_ROOT" diff --git a/.gitpod/utils/script-templates/preview.template.sh b/.gitpod/utils/script-templates/preview.template.sh deleted file mode 100755 index 916a7fc7..00000000 --- a/.gitpod/utils/script-templates/preview.template.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi - -# Preview port 8080 -gp preview "$(gp url 8080)" diff --git a/.gitpod/utils/script-templates/protect-my-git.template.sh b/.gitpod/utils/script-templates/protect-my-git.template.sh deleted file mode 100755 index d9e7f828..00000000 --- a/.gitpod/utils/script-templates/protect-my-git.template.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi - -# Remove access to user's Git credentials (restore by restart workspace) -git config --global --unset credential.helper diff --git a/.gitpod/utils/send-a-message-gcs.sh b/.gitpod/utils/send-a-message-gcs.sh deleted file mode 100755 index 5c53aba5..00000000 --- a/.gitpod/utils/send-a-message-gcs.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -# Get current user and current branch -branch_user="$GITPOD_GIT_USER_NAME, $(git branch --show-current)" - -# Load env vars during prebuild using `gp env` command -if [ -z "$IFTTT_TOKEN" ]; then - eval "$(gp env -e | grep IFTTT_TOKEN)" -fi - -# Load env vars during prebuild using `gp env` command -if [ -z "$DP_GOOGLE_ACCESS_KEY" ]; then - eval "$(gp env -e | grep DP_GOOGLE_ACCESS_KEY)" -fi - -# Load env vars during prebuild using `gp env` command -if [ -z "$DP_GOOGLE_SECRET" ]; then - eval "$(gp env -e | grep DP_GOOGLE_SECRET)" -fi - -# Establish connection with Google Cloud through Minio client -mc config host add gcs https://storage.googleapis.com "$DP_GOOGLE_ACCESS_KEY" "$DP_GOOGLE_SECRET" - -# If there's a problem send the error code -if mc find gcs/drupalpod/ready-made-envs.tar.gz; then - message="Success: Google Cloud is ready" -else - message="Error: Envs file wasn't found, it will be recreated" -fi - -# Send a message through IFTTT -curl -X POST -H "Content-Type: application/json" -d "{\"value1\":\"$branch_user\",\"value2\":\"$message\"}" https://maker.ifttt.com/trigger/drupalpod_prebuild_initiated/with/key/"$IFTTT_TOKEN" diff --git a/.gitpod/utils/send-a-message-gitpod.sh b/.gitpod/utils/send-a-message-gitpod.sh deleted file mode 100755 index b0de49c8..00000000 --- a/.gitpod/utils/send-a-message-gitpod.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -# Get current user and current branch -branch_user="$GITPOD_GIT_USER_NAME, $(git branch --show-current)" - -# Load env vars during prebuild using `gp env` command -if [ -z "$DP_READY_MADE_ENVS_URL" ]; then - eval "$(gp env -e | grep DP_READY_MADE_ENVS_URL)" -fi - -# Load env vars during prebuild using `gp env` command -if [ -z "$IFTTT_TOKEN" ]; then - eval "$(gp env -e | grep IFTTT_TOKEN)" -fi - -# Check the status of ready-made envs file -# https://stackoverflow.com/a/53358157/5754049 -url_status=$(wget --server-response --spider --quiet "${DP_READY_MADE_ENVS_URL}" 2>&1 | awk 'NR==1{print $2}') - -# If there's a problem send the error code -if [ "$url_status" = '200' ]; then - message="100%" -else - message="Error: $url_status - $DP_READY_MADE_ENVS_URL" -fi - -# Send a message through IFTTT -curl -X POST -H "Content-Type: application/json" -d "{\"value1\":\"$branch_user\",\"value2\":\"$message\"}" https://maker.ifttt.com/trigger/drupalpod_prebuild_initiated/with/key/"$IFTTT_TOKEN" diff --git a/.gitpod/utils/set-base-environment.sh b/.gitpod/utils/set-base-environment.sh deleted file mode 100755 index 6305af81..00000000 --- a/.gitpod/utils/set-base-environment.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -if [ -n "$DEBUG_SCRIPT" ]; then - set -x -fi - -# Load default envs -# export "$(grep -v '^#' "$GITPOD_REPO_ROOT"/.env | xargs -d '\n')" - -# Clone Drupal core repo -mkdir -p "${GITPOD_REPO_ROOT}"/repos -cd "${GITPOD_REPO_ROOT}"/repos && time git clone https://git.drupalcode.org/project/drupal.git diff --git a/.vscode/launch.json b/.vscode/launch.json index 685be73f..923c99bf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,21 +4,49 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { - "name": "Listen for XDebug", + "name": "Listen for Xdebug", "type": "php", "request": "launch", - "hostname": "0.0.0.0", "port": 9003, "pathMappings": { - "/var/www/html": "${workspaceRoot}" + "/var/www/html": "${workspaceFolder}" } }, { - "type": "bashdb", + "name": "Launch currently open script", + "type": "php", + "request": "launch", + "program": "${file}", + "cwd": "${fileDirname}", + "port": 0, + "runtimeArgs": [ + "-dxdebug.start_with_request=yes" + ], + "env": { + "XDEBUG_MODE": "debug,develop", + "XDEBUG_CONFIG": "client_port=${port}" + } + }, + { + "name": "Launch Built-in web server", + "type": "php", "request": "launch", - "name": "Bash-Debug (simplest configuration)", - "program": "${file}" + "runtimeArgs": [ + "-dxdebug.mode=debug", + "-dxdebug.start_with_request=yes", + "-S", + "localhost:0" + ], + "program": "", + "cwd": "${workspaceRoot}", + "port": 9003, + "serverReadyAction": { + "pattern": "Development Server \\(http://localhost:([0-9]+)\\) started", + "uriFormat": "http://localhost:%s", + "action": "openExternally" + } } ] } diff --git a/README.md b/README.md index fcd45761..d62dadb0 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,100 @@ -# DrupalPod +# DrupalPod AI QA -## **IF YOU ARE ON GITHUB THIS IS NOT THE REPOSITORY YOU WANT** -## **THE DRUPALPOD REPOSITORY HAS MOVED TO https://drupal.org/project/DrupalPod** +A flexible QA testing environment for Drupal CMS and AI modules, powered by [DDEV](https://ddev.com). -* Please file issues there. -* Please do Merge Requests there. -* This repo is just a mirror. +This project allows you to quickly spin up different configurations of Drupal CMS or Drupal Core to test AI modules and features across different versions. +## Getting started + +### Prerequisites + +- [DDEV](https://ddev.com/get-started/) installed and running +- Git + +### Quick start + +1. Clone this repository +2. Navigate to the project directory +3. Run `ddev start` +4. Visit https://drupalpod-ai-qa.ddev.site + +That's it! DDEV will automatically run the setup scripts and install Drupal. + +### Configuration + +Control which Drupal setup and version you want to test using environment variables in `.ddev/config.yaml`: + +```yaml +web_environment: + - DP_STARTER_TEMPLATE=cms # "cms" or "core" + - DP_VERSION=1.x # e.g., "1.x", "2.0.0" for CMS; "11.2.8", "11.x" for core + - DP_INSTALL_PROFILE= # Optional: override default profile + - DP_REBUILD=0 # Set to 1 for clean rebuild + - DP_AI_VIRTUAL_KEY= # Optional: AI API key for auto-configuration +``` + +### Common scenarios + +**Test AI modules with Drupal CMS 1.x:** +```yaml +DP_STARTER_TEMPLATE=cms +DP_VERSION=1.x +``` + +**Test AI modules with Drupal CMS 2.x:** +```yaml +DP_STARTER_TEMPLATE=cms +DP_VERSION=2.0.0 +``` + +**Test with Drupal Core:** +```yaml +DP_STARTER_TEMPLATE=core +DP_VERSION=11.2.8 +``` + +**Clean rebuild:** +```bash +DP_REBUILD=1 ddev start +``` + +**Auto-configure AI with API key:** +```yaml +DP_AI_VIRTUAL_KEY=sk-your-key-here +``` + +### Installation details + +The setup is automated via DDEV hooks in `.ddev/config.yaml`: +- `init.sh` - Main orchestration script +- `composer_setup.sh` - Generates composer.json and installs dependencies +- `contrib_modules_setup.sh` - Configures devel and admin_toolbar modules +- `fallback_setup.sh` - Sets default configuration values + +### Installation options + +The Drupal CMS installer offers a list of features preconfigured with smart defaults. You will be able to customize whatever you choose, and add additional features, once you are logged in. + +After the installer is complete, you will land on the dashboard. + +## Documentation + +Coming soon ... [We're working on Drupal CMS specific documentation](https://www.drupal.org/project/drupal_cms/issues/3454527). + +In the meantime, learn more about managing a Drupal-based application in the [Drupal User Guide](https://www.drupal.org/docs/user_guide/en/index.html). + +## Contributing + +Drupal CMS is developed in the open on [Drupal.org](https://www.drupal.org). We are grateful to the community for reporting bugs and contributing fixes and improvements. + +[Report issues in the queue](https://drupal.org/node/add/project-issue/drupal_cms), providing as much detail as you can. You can also join the #drupal-cms-support channel in the [Drupal Slack community](https://www.drupal.org/slack). + +Drupal CMS has adopted a [code of conduct](https://www.drupal.org/dcoc) that we expect all participants to adhere to. + +To contribute to Drupal CMS development, see the [drupal_cms project](https://www.drupal.org/project/drupal_cms). + +## License + +Drupal CMS and all derivative works are licensed under the [GNU General Public License, version 2 or later](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html). + +Learn about the [Drupal trademark and logo policy here](https://www.drupal.com/trademark). From 4bf62c2aca6eb0fadf3fd3d63c1d964cb3c84c33 Mon Sep 17 00:00:00 2001 From: LittlePixieZ Date: Fri, 28 Nov 2025 13:38:13 +0000 Subject: [PATCH 5/9] Starter kit logic finalised, AI modules added (cloned and checked with composer constraints), added bats testing - need to update README --- .ddev/config.yaml | 10 +- .devpanel/clone_ai_modules.sh | 349 +++++++++++++++++++++++++++++ .devpanel/composer_setup.sh | 76 +++++-- .devpanel/contrib_modules_setup.sh | 34 --- .devpanel/drupal_setup_contrib.sh | 29 --- .devpanel/drupal_setup_core.sh | 41 ---- .devpanel/fallback_setup.sh | 93 +++++++- .devpanel/git_setup.sh | 97 -------- .devpanel/init.sh | 66 +++++- .devpanel/repos/.gitkeep | 0 .gitignore | 73 ++++-- .gitmodules | 16 ++ package.json | 20 ++ repos/drupal | 1 - tests/README.md | 105 +++++++++ tests/clone_ai_modules.bats | 178 +++++++++++++++ tests/fallback_setup.bats | 143 ++++++++++++ tests/integration.bats | 215 ++++++++++++++++++ 18 files changed, 1296 insertions(+), 250 deletions(-) create mode 100755 .devpanel/clone_ai_modules.sh delete mode 100755 .devpanel/contrib_modules_setup.sh delete mode 100755 .devpanel/drupal_setup_contrib.sh delete mode 100755 .devpanel/drupal_setup_core.sh delete mode 100755 .devpanel/git_setup.sh create mode 100644 .devpanel/repos/.gitkeep create mode 100644 package.json delete mode 160000 repos/drupal create mode 100644 tests/README.md create mode 100644 tests/clone_ai_modules.bats create mode 100644 tests/fallback_setup.bats create mode 100644 tests/integration.bats diff --git a/.ddev/config.yaml b/.ddev/config.yaml index 8a7642c0..74864580 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -12,16 +12,14 @@ hooks: post-start: # Set up debugging. - exec: test -f .vscode/launch.json || mkdir -p .vscode && cp .ddev/launch.json .vscode/ - # Run initial setup tasks. - - exec: .devpanel/init.sh + # Run initial setup tasks only when needed (DP_REBUILD=1 or Drupal not installed). + - exec: 'if [ "${DP_REBUILD:-0}" = "1" ] || ! drush status --field=bootstrap 2>/dev/null | grep -q "Successful"; then .devpanel/init.sh; fi' use_dns_when_possible: true composer_version: "2" web_environment: # Set up DevPanel variables. - APP_ROOT=$DDEV_COMPOSER_ROOT - WEB_ROOT=$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT - - DP_STARTER_TEMPLATE=cms - - DP_VERSION=2.0.x - DB_HOST=db - DB_PORT=3306 - DB_USER=db @@ -29,8 +27,8 @@ web_environment: - DB_NAME=db - DP_APP_ID=drupalpod_ai_qa - DB_DRIVER=mysql - - DP_AI_VIRTUAL_KEY= - - DP_REBUILD=1 + # AI ecosystem modules to always try to clone (compatibility filtered) + - DP_AI_MODULES=ai_provider_litellm,ai_search,ai_agents corepack_enable: false ddev_version_constraint: '>=1.24.0' diff --git a/.devpanel/clone_ai_modules.sh b/.devpanel/clone_ai_modules.sh new file mode 100755 index 00000000..886d0e18 --- /dev/null +++ b/.devpanel/clone_ai_modules.sh @@ -0,0 +1,349 @@ +#!/usr/bin/env bash +set -eu -o pipefail +cd "${APP_ROOT}" + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Clone AI Modules from Git (Dependency-Driven Architecture) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Automatically clones AI base module + dependencies from git.drupalcode.org +# Supports version branches, tags, and PR testing +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +# Track which modules we clone and which are compatible +export CLONED_AI_MODULES="" +export COMPATIBLE_AI_MODULES="" # Only modules compatible with AI version + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Helper: Clone a module from git +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +clone_module() { + local module_name=$1 + local module_version=${2:-} + local issue_fork=${3:-} + local issue_branch=${4:-} + + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Cloning: $module_name" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + if git submodule status repos/"$module_name" > /dev/null 2>&1; then + echo " ✓ Submodule exists, updating..." + time git submodule update --init --recursive repos/"$module_name" + else + echo " + Adding as submodule..." + time git submodule add -f https://git.drupalcode.org/project/"$module_name".git repos/"$module_name" + time git config -f .gitmodules submodule."repos/$module_name".ignore dirty + fi + + cd "${APP_ROOT}"/repos/"$module_name" + git fetch origin + git fetch --all --tags + + # Checkout specific PR/issue branch if specified + if [ -n "$issue_branch" ] && [ -n "$issue_fork" ]; then + echo " → Checking out PR: $issue_fork/$issue_branch" + if git show-ref -q --heads "$issue_branch"; then + git checkout "$issue_branch" + else + git remote add issue-"$issue_fork" https://git.drupalcode.org/issue/"$issue_fork".git 2>/dev/null || true + git fetch issue-"$issue_fork" + git checkout -b "$issue_branch" --track issue-"$issue_fork"/"$issue_branch" + fi + elif [ -n "$module_version" ]; then + echo " → Checking out version: $module_version" + # Check if it's a branch (*.x) + if [[ "$module_version" == *.x ]]; then + if git show-ref --verify --quiet refs/remotes/origin/"$module_version"; then + git checkout -B "$module_version" origin/"$module_version" + else + echo " ⚠️ Branch $module_version not found, using default" + git checkout $(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5) + fi + else + # Try as tag, then branch + if git rev-parse tags/"$module_version" >/dev/null 2>&1; then + git checkout tags/"$module_version" + elif git show-ref --verify --quiet refs/remotes/origin/"$module_version"; then + git checkout -B "$module_version" origin/"$module_version" + else + echo " ⚠️ Version $module_version not found, using default" + git checkout $(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5) + fi + fi + fi + + cd "${APP_ROOT}" + + # Add to cloned modules list + if [ -z "$CLONED_AI_MODULES" ]; then + export CLONED_AI_MODULES="$module_name" + else + export CLONED_AI_MODULES="$CLONED_AI_MODULES,$module_name" + fi +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Helper: Get AI ecosystem dependencies from composer.json +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +get_ai_dependencies() { + local module_path=$1 + local composer_json="${module_path}/composer.json" + + if [ ! -f "$composer_json" ]; then + return + fi + + # Extract drupal/ai* dependencies from require section + # Use grep and sed to parse JSON (simple approach) + grep -A 100 '"require"' "$composer_json" | \ + grep '"drupal/ai' | \ + sed 's/.*"drupal\/\([^"]*\)".*/\1/' || true +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Helper: Extract compatible version from constraint +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +get_compatible_version() { + local module_path=$1 + local dependency_name=$2 + local composer_json="${module_path}/composer.json" + + if [ ! -f "$composer_json" ]; then + echo "" + return + fi + + # Extract version constraint for the dependency + # e.g., "drupal/ai_provider_litellm": "^1.2" → return "1.2.x" + local constraint=$(grep -A 100 '"require"' "$composer_json" | \ + grep "\"drupal/$dependency_name\"" | \ + sed 's/.*"drupal\/[^"]*": *"\([^"]*\)".*/\1/' | \ + head -1 || true) + + if [ -z "$constraint" ]; then + echo "" + return + fi + + # Convert constraint to branch version + # ^1.2 → 1.2.x + # ^1.2.0 → 1.2.x + # ~1.2.0 → 1.2.x + local version=$(echo "$constraint" | sed -E 's/[\^~>=<]//g' | sed -E 's/^([0-9]+\.[0-9]+).*/\1.x/') + echo "$version" +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Helper: Check if module is compatible with AI version +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +is_compatible_with_ai() { + local module_path=$1 + local ai_version=$2 + local composer_json="${module_path}/composer.json" + + if [ ! -f "$composer_json" ]; then + return 0 # If no composer.json, assume compatible + fi + + # Get the AI requirement constraint (e.g., "^2.0", "^1.2") + local ai_constraint=$(grep -A 100 '"require"' "$composer_json" | \ + grep '"drupal/ai"' | \ + sed 's/.*"drupal\/ai": *"\([^"]*\)".*/\1/' | \ + head -1 || true) + + if [ -z "$ai_constraint" ]; then + return 0 # If no AI requirement, assume compatible + fi + + # Extract major.minor from constraint (e.g., ^2.0 → 2.0, ^1.2 → 1.2) + local required_version=$(echo "$ai_constraint" | sed -E 's/[\^~>=<]//g' | sed -E 's/^([0-9]+\.[0-9]+).*/\1/') + + # Extract major.minor from our AI version (e.g., 1.2.x → 1.2, 2.0.x → 2.0) + local our_version=$(echo "$ai_version" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/') + + # Simple version comparison: they must match + if [ "$required_version" = "$our_version" ]; then + return 0 # Compatible + else + echo " ⚠️ Incompatible: requires AI ^$required_version, but we have AI $ai_version" >&2 + return 1 # Incompatible + fi +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Main Logic: Hybrid Architecture +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# 1. If DP_TEST_MODULE set: Clone test module first, use its AI requirement +# 2. Otherwise: Use auto-detected AI version from compatibility matrix +# 3. Clone additional modules from DP_AI_MODULES with compatibility filtering +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +# Determine final AI version to use +FINAL_AI_VERSION="$DP_AI_MODULE_VERSION" + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Step 1: Clone test module first (if specified) to determine AI requirements +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +if [ -n "${DP_TEST_MODULE:-}" ]; then + echo + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Step 1: Clone Test Module (determines AI version requirement)" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + test_version="$DP_TEST_MODULE_VERSION" + clone_module "$DP_TEST_MODULE" "$test_version" "$DP_TEST_MODULE_ISSUE_FORK" "$DP_TEST_MODULE_ISSUE_BRANCH" + + # Get AI requirement from test module + test_module_ai_requirement=$(get_compatible_version "repos/$DP_TEST_MODULE" "$DP_AI_MODULE") + + if [ -n "$test_module_ai_requirement" ]; then + # Check if user explicitly set AI version + if [ "${DP_AI_MODULE_VERSION_EXPLICIT:-no}" = "yes" ]; then + # User explicitly set AI version - validate compatibility + if [ "$test_module_ai_requirement" != "$FINAL_AI_VERSION" ]; then + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "❌ ERROR: Version Conflict" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + echo "Test module '$DP_TEST_MODULE' requires AI $test_module_ai_requirement" + echo "But you explicitly configured DP_AI_MODULE_VERSION=$FINAL_AI_VERSION" + echo "" + echo "Fix options:" + echo " 1. Remove DP_AI_MODULE_VERSION from config (auto-detect from test module)" + echo " 2. Change DP_AI_MODULE_VERSION to $test_module_ai_requirement" + echo " 3. Test a different module compatible with AI $FINAL_AI_VERSION" + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + exit 1 + else + echo " ✓ Test module requires AI $test_module_ai_requirement (matches your configuration)" + fi + else + # User didn't set AI version - auto-detect from test module + FINAL_AI_VERSION="$test_module_ai_requirement" + echo " → Test module requires AI $FINAL_AI_VERSION (auto-detected)" + fi + else + # Couldn't determine requirement from test module + if [ "${DP_AI_MODULE_VERSION_EXPLICIT:-no}" = "no" ]; then + echo " ⚠️ Could not determine AI version from test module" + echo " → Using compatibility matrix default: $FINAL_AI_VERSION" + else + echo " ⚠️ Could not determine AI version from test module" + echo " → Using your configured version: $FINAL_AI_VERSION" + fi + fi + + # Mark test module as compatible (it drove the AI version choice) + if [ -z "$COMPATIBLE_AI_MODULES" ]; then + export COMPATIBLE_AI_MODULES="$DP_TEST_MODULE" + else + export COMPATIBLE_AI_MODULES="$COMPATIBLE_AI_MODULES,$DP_TEST_MODULE" + fi +else + echo + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "Step 1: No Test Module" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo " → Using AI version from compatibility matrix: $FINAL_AI_VERSION" +fi + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Step 2: Clone AI base module at determined version +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +echo +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "Step 2: Clone AI Base Module @ $FINAL_AI_VERSION" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + +clone_module "$DP_AI_MODULE" "$FINAL_AI_VERSION" "$DP_AI_ISSUE_FORK" "$DP_AI_ISSUE_BRANCH" + +# AI base is always compatible +if [ -z "$COMPATIBLE_AI_MODULES" ]; then + export COMPATIBLE_AI_MODULES="$DP_AI_MODULE" +else + export COMPATIBLE_AI_MODULES="$COMPATIBLE_AI_MODULES,$DP_AI_MODULE" +fi + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Step 3: Clone additional AI modules (with compatibility filtering) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +echo +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "Step 3: Clone Additional AI Modules (compatibility filtering)" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + +# Parse DP_AI_MODULES (comma-separated list) +if [ -n "${DP_AI_MODULES:-}" ]; then + IFS=',' read -ra MODULES <<< "$DP_AI_MODULES" + for module in "${MODULES[@]}"; do + module=$(echo "$module" | xargs) # Trim whitespace + + if [ -z "$module" ]; then + continue + fi + + # Skip if already cloned (e.g., as test module) + if echo ",$CLONED_AI_MODULES," | grep -q ",$module,"; then + echo " ✓ $module already cloned" + continue + fi + + # Clone at dev branch + echo " → Cloning $module..." + clone_module "$module" "" + + # Check compatibility with AI version + if is_compatible_with_ai "repos/$module" "$FINAL_AI_VERSION"; then + echo " ✓ $module is compatible with AI $FINAL_AI_VERSION" + if [ -z "$COMPATIBLE_AI_MODULES" ]; then + export COMPATIBLE_AI_MODULES="$module" + else + export COMPATIBLE_AI_MODULES="$COMPATIBLE_AI_MODULES,$module" + fi + else + echo " ✗ Skipping $module from composer (incompatible, but cloned for inspection)" + fi + done +else + echo " (No additional modules specified in DP_AI_MODULES)" +fi + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Step 4: Clone default provider +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +echo +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "Step 4: Clone Default Provider" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + +# Always clone ai_provider_litellm unless already cloned +if echo ",$CLONED_AI_MODULES," | grep -q ",ai_provider_litellm,"; then + echo " ✓ Provider already cloned" +else + provider_version=$(get_compatible_version "repos/$DP_AI_MODULE" "ai_provider_litellm") + if [ -z "$provider_version" ]; then + provider_version="$FINAL_AI_VERSION" + fi + echo " → Cloning default provider: ai_provider_litellm @ $provider_version" + clone_module "ai_provider_litellm" "$provider_version" + + # Check compatibility + if is_compatible_with_ai "repos/ai_provider_litellm" "$FINAL_AI_VERSION"; then + echo " ✓ Provider is compatible" + export COMPATIBLE_AI_MODULES="$COMPATIBLE_AI_MODULES,ai_provider_litellm" + else + echo " ✗ Provider incompatible (skipping from composer)" + fi +fi + +echo +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "✓ Summary" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " AI Version: $FINAL_AI_VERSION" +echo " Cloned modules: $CLONED_AI_MODULES" +echo " Compatible (will be added to composer): $COMPATIBLE_AI_MODULES" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo diff --git a/.devpanel/composer_setup.sh b/.devpanel/composer_setup.sh index d75dd5a5..e08fe265 100755 --- a/.devpanel/composer_setup.sh +++ b/.devpanel/composer_setup.sh @@ -2,11 +2,11 @@ set -eu -o pipefail cd $APP_ROOT -# Determine which starter template to use +# Determine which starter template to use. # Options: "cms" or "core" STARTER_TEMPLATE="${DP_STARTER_TEMPLATE:-cms}" -# Determine the composer package and version +# Determine the composer package and version. if [ "$STARTER_TEMPLATE" = "cms" ]; then COMPOSER_PROJECT="drupal/cms" # For CMS versions: 1.x, 1.0.0, 2.0.0, etc. @@ -33,20 +33,38 @@ else esac fi -# Always regenerate composer.json from the selected template +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Generate composer.json from CMS/Core template using temp directory +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Why do we copy it to temp? +# - `composer create-project` requires an empty/non-existent target directory +# - Our project root may have existing files (git, config, etc.) +# - Solution: Create in temp, copy everything over, then customize composer.json +# - This is safer than deleting project root first (preserves files if script fails) +# +# Clean up temp directory if it exists from previous runs. +rm -rf "$APP_ROOT"/temp-composer-files + +# Create the project template in temp directory. if [ -n "$install_version" ]; then time composer create-project -n --no-install "$COMPOSER_PROJECT":"$install_version" temp-composer-files else time composer create-project -n --no-install "$COMPOSER_PROJECT" temp-composer-files fi -# Copy all files and directories (including hidden files) from temp directory + +# Copy all files (including hidden files) from temp to project root. cp -r "$APP_ROOT"/temp-composer-files/. "$APP_ROOT"/. + +# Clean up temp directory. rm -rf "$APP_ROOT"/temp-composer-files -# Set minimum-stability to dev to allow alpha/beta packages (needed for CMS 2.x) +# Set minimum-stability to dev to allow alpha/beta packages (needed for dev versions). composer config minimum-stability dev -# Programmatically fix Composer 2.2 allow-plugins to avoid errors +# Allow patches to fail without stopping installation. +composer config extra.composer-exit-on-patch-failure false + +# Programmatically fix Composer 2.2 allow-plugins to avoid errors. composer config --no-plugins allow-plugins.composer/installers true composer config --no-plugins allow-plugins.drupal/core-project-message true composer config --no-plugins allow-plugins.drupal/core-vendor-hardening true @@ -67,17 +85,48 @@ composer config -jm extra.drupal-scaffold.file-mapping '{ composer config scripts.post-drupal-scaffold-cmd \ 'cd web/sites/default && test -z "$(grep '\''include \$devpanel_settings;'\'' settings.php)" && patch -Np1 -r /dev/null < $APP_ROOT/.devpanel/drupal-settings.patch || :' +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# AI MODULES FROM GIT (Path Repositories) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Add path repositories ONLY for compatible AI modules +# Incompatible modules are cloned (available in repos/) but not added to composer +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +if [ -n "${COMPATIBLE_AI_MODULES:-}" ]; then + echo "Adding path repositories for compatible AI modules..." + + IFS=',' read -ra MODULES <<< "$COMPATIBLE_AI_MODULES" + for module in "${MODULES[@]}"; do + module=$(echo "$module" | xargs) # Trim whitespace + + if [ -z "$module" ]; then + continue + fi + + if [ -d "repos/$module" ]; then + echo " - Adding path repository for: $module" + composer config --no-plugins repositories."$module"-git \ + "{\"type\": \"path\", \"url\": \"repos/$module\", \"options\": {\"symlink\": true}}" + + # Require from path (use *@dev to accept version from module's composer.json). + composer require -n --no-update "drupal/$module:*@dev" + fi + done + + echo "Path repositories added for compatible AI modules!" +fi + # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # AI DEPENDENCIES # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# Enable Composer Patches plugin (useful for applying patches from drupal.org) +# Enable Composer Patches plugin (needed for applying patches from drupal.org). composer config --no-plugins allow-plugins.cweagans/composer-patches true if [ "$STARTER_TEMPLATE" = "cms" ]; then - echo "Adding CMS AI dependencies (full setup with webform libraries)..." + echo "Adding CMS dependencies (full setup with webform libraries)..." - # Add JavaScript library repositories for Webform support + # Add JavaScript library repositories for Webform support. composer config repositories.tippyjs '{ "type": "package", "package": { @@ -282,10 +331,9 @@ if [ "$STARTER_TEMPLATE" = "cms" ]; then } }' - # Require all CMS dependencies (AI + Webform libraries) + # Require all CMS dependencies (Webform libraries only - AI modules come from git). composer require -n --no-update \ cweagans/composer-patches:^2@beta \ - drupal/ai_provider_litellm:@beta \ drush/drush:^13.6 \ codemirror/codemirror \ jquery/inputmask \ @@ -303,11 +351,11 @@ if [ "$STARTER_TEMPLATE" = "cms" ]; then else echo "Adding Core AI dependencies (lean setup for quick PR/issue testing)..." - # Core variant: AI + Search only, no webform bloat + # Core variant: Search only - AI modules come from git via path repos. composer require -n --no-update \ cweagans/composer-patches:^2@beta \ - drupal/ai_provider_litellm:@beta \ drush/drush:^13.6 \ drupal/search_api \ - drupal/search_api_db + drupal/search_api_db \ + drupal/token fi diff --git a/.devpanel/contrib_modules_setup.sh b/.devpanel/contrib_modules_setup.sh deleted file mode 100755 index 42418adb..00000000 --- a/.devpanel/contrib_modules_setup.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Check if additional modules should be installed -export DEVEL_NAME="devel" -export DEVEL_PACKAGE="drupal/devel" - -export ADMIN_TOOLBAR_NAME="admin_toolbar_tools" -export ADMIN_TOOLBAR_PACKAGE="drupal/admin_toolbar" - -# TODO: once Drupalpod extension supports additional modules - remove these 2 lines -export DP_EXTRA_DEVEL=1 -export DP_EXTRA_ADMIN_TOOLBAR=1 - -# Adding support for composer-drupal-lenient - https://packagist.org/packages/mglaman/composer-drupal-lenient -if [[ "$DP_VERSION" =~ ^10(\..*)?$ ]]; then - if [ "$DP_PROJECT_TYPE" != "project_core" ]; then - export COMPOSER_DRUPAL_LENIENT=mglaman/composer-drupal-lenient - else - export COMPOSER_DRUPAL_LENIENT='' - fi -fi - -# Adding support for composer-drupal-lenient - https://packagist.org/packages/mglaman/composer-drupal-lenient -if [[ "$DP_VERSION" =~ ^11(\..*)?$ ]]; then - # admin_toolbar and devel are not compatible yet with Drupal 11 - export DP_EXTRA_ADMIN_TOOLBAR= - export DP_EXTRA_DEVEL= - if [ "$DP_PROJECT_TYPE" != "project_core" ]; then - export COMPOSER_DRUPAL_LENIENT=mglaman/composer-drupal-lenient - else - export COMPOSER_DRUPAL_LENIENT='' - fi -fi diff --git a/.devpanel/drupal_setup_contrib.sh b/.devpanel/drupal_setup_contrib.sh deleted file mode 100755 index 4d690f8f..00000000 --- a/.devpanel/drupal_setup_contrib.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail -cd "${APP_ROOT}" - -# Drupal projects with no composer.json, bypass the symlink config, symlink has to be created manually. - -if [ "$DP_PROJECT_TYPE" == "project_module" ]; then - PROJECT_TYPE=modules -elif [ "$DP_PROJECT_TYPE" == "project_theme" ]; then - PROJECT_TYPE=themes -fi - -cat <"${APP_ROOT}"/repos/add-project-as-symlink.sh -#!/usr/bin/env bash -# This file was dynamically generated by a script -echo "Replace project with a symlink" -rm -rf web/$PROJECT_TYPE/contrib/$DP_PROJECT_NAME -cd web/$PROJECT_TYPE/contrib && ln -s ../../../repos/$DP_PROJECT_NAME . -PROJECTASYMLINK - -chmod +x "${APP_ROOT}"/repos/add-project-as-symlink.sh - -if [ -n "$COMPOSER_DRUPAL_LENIENT" ]; then - # Add composer_drupal_lenient for modules on Drupal 10 - composer config --no-plugins --merge --json extra.drupal-lenient.allowed-list '["drupal/'"$DP_PROJECT_NAME"'"]' - time composer require "$COMPOSER_DRUPAL_LENIENT" -fi -# Add the project to composer (it will get the version according to the branch under `/repo/name_of_project`) -time composer require drupal/"$DP_PROJECT_NAME" --no-interaction --no-install diff --git a/.devpanel/drupal_setup_core.sh b/.devpanel/drupal_setup_core.sh deleted file mode 100755 index 5a3957d9..00000000 --- a/.devpanel/drupal_setup_core.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail -cd "${APP_ROOT}" - -# Add a special path when working on core contributions -# (Without it, /web/modules/contrib is not found by website) -composer config --no-plugins repositories.drupal-core2 '{"type": "path", "url": "repos/drupal/core"}' -composer config --no-plugins repositories.drupal-core3 '{"type": "path", "url": "repos/drupal/composer/Metapackage/CoreRecommended"}' -composer config --no-plugins repositories.drupal-core4 '{"type": "path", "url": "repos/drupal/composer/Metapackage/DevDependencies"}' -composer config --no-plugins repositories.drupal-core5 '{"type": "path", "url": "repos/drupal/composer/Plugin/ProjectMessage"}' -composer config --no-plugins repositories.drupal-core6 '{"type": "path", "url": "repos/drupal/composer/Plugin/VendorHardening"}' - -# Removing the conflict part of composer -echo "$(cat composer.json | jq 'del(.conflict)' --indent 4)" >composer.json - -# If a core issue branch was chosen, we want the version of Drupal core that is in that issue branch -# This is very helpful for issues that started with previous Drupal core versions, and the issue version automatically got updated to latest current drupal version -if [ "$DP_PROJECT_TYPE" == "project_core" ] && [ -n "$DP_ISSUE_BRANCH" ]; then - time composer require drupal/core-recommended:* drupal/core-project-message:* drupal/core-composer-scaffold:* --no-update -fi - -# Only after composer update, /web/core get symlinked to /repos/drupal/core -# repos/drupal/core -> web/core -time composer update --no-plugins --no-install - -# vendor -> repos/drupal/vendor -if [ ! -L "$APP_ROOT"/repos/drupal/vendor ]; then - cd "$APP_ROOT"/repos/drupal && - ln -s ../../vendor . -fi - -# Create folders for running tests -mkdir -p "$APP_ROOT"/web/sites/simpletest -mkdir -p "$APP_ROOT"/web/sites/simpletest/browser_output - -# Symlink the simpletest folder into the Drupal core git repo. -# repos/drupal/sites/simpletest -> ../../../web/sites/simpletest -if [ ! -L "$APP_ROOT"/repos/drupal/sites/simpletest ]; then - cd "$APP_ROOT"/repos/drupal/sites && - ln -s ../../../web/sites/simpletest . -fi diff --git a/.devpanel/fallback_setup.sh b/.devpanel/fallback_setup.sh index 47e177c5..145677cc 100755 --- a/.devpanel/fallback_setup.sh +++ b/.devpanel/fallback_setup.sh @@ -48,10 +48,97 @@ else fi fi -# Set install profile based on starter template +# Set install profile based on starter template (only if not already set) # For CMS, don't specify a profile - let Drupal auto-detect the distribution +if [ -z "${DP_INSTALL_PROFILE+x}" ]; then + if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then + export DP_INSTALL_PROFILE='' + else + export DP_INSTALL_PROFILE='standard' + fi +fi + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# AI MODULE CONFIGURATION (always use git for AI modules) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +# Auto-detect compatible AI module version based on CMS/Core version if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then - export DP_INSTALL_PROFILE='' + case "$DP_VERSION" in + 2.0.x|2.x|2.0.*) + # CMS 2.x requires AI ^1.2 + DEFAULT_AI_VERSION="1.2.x" + echo "Detected CMS 2.x → Using AI modules 1.2.x" + ;; + 1.x|1.0.x|1.*.*) + # CMS 1.x requires AI ^1.0 + DEFAULT_AI_VERSION="1.0.x" + echo "Detected CMS 1.x → Using AI modules 1.0.x" + ;; + *) + echo "⚠️ WARNING: Unknown CMS version '$DP_VERSION', defaulting to AI 1.2.x" + DEFAULT_AI_VERSION="1.2.x" + ;; + esac +else + # Drupal Core + case "$DP_VERSION" in + 11.*|11.x) + # Drupal 11.x works with AI ^1.2 + DEFAULT_AI_VERSION="1.2.x" + echo "Detected Drupal Core 11.x → Using AI modules 1.2.x" + ;; + 10.*|10.x) + # Drupal 10.x works with AI ^1.0 + DEFAULT_AI_VERSION="1.0.x" + echo "Detected Drupal Core 10.x → Using AI modules 1.0.x" + ;; + *) + echo "⚠️ WARNING: Unknown Core version '$DP_VERSION', defaulting to AI 1.2.x" + DEFAULT_AI_VERSION="1.2.x" + ;; + esac +fi + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# AI Module Configuration (Dependency-Driven Architecture) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +# AI base module (ALWAYS cloned from git) +export DP_AI_MODULE=${DP_AI_MODULE:-'ai'} + +# Track if user explicitly set AI version (for validation when testing modules) +if [ -z "${DP_AI_MODULE_VERSION:-}" ]; then + # User didn't set it - use default and mark as auto-detected + export DP_AI_MODULE_VERSION="$DEFAULT_AI_VERSION" + export DP_AI_MODULE_VERSION_EXPLICIT="no" else - export DP_INSTALL_PROFILE='standard' + # User explicitly set it - validate compatibility when testing modules + export DP_AI_MODULE_VERSION_EXPLICIT="yes" +fi + +export DP_AI_ISSUE_FORK=${DP_AI_ISSUE_FORK:-''} +export DP_AI_ISSUE_BRANCH=${DP_AI_ISSUE_BRANCH:-''} + +# Generic test module (optional - any module you're testing) +export DP_TEST_MODULE=${DP_TEST_MODULE:-''} # e.g., 'ai_search', 'ai_provider_litellm', 'ai_agents' +export DP_TEST_MODULE_VERSION=${DP_TEST_MODULE_VERSION:-''} # Optional: specific version/branch +export DP_TEST_MODULE_ISSUE_FORK=${DP_TEST_MODULE_ISSUE_FORK:-''} +export DP_TEST_MODULE_ISSUE_BRANCH=${DP_TEST_MODULE_ISSUE_BRANCH:-''} + +# Show final AI module configuration +echo "📦 AI Module Configuration:" +echo " - AI Base: $DP_AI_MODULE @ $DP_AI_MODULE_VERSION" +if [ -n "${DP_AI_ISSUE_BRANCH:-}" ]; then + echo " └─ Testing PR: $DP_AI_ISSUE_FORK/$DP_AI_ISSUE_BRANCH" +fi +if [ -n "${DP_TEST_MODULE:-}" ]; then + echo " - Test Module: $DP_TEST_MODULE" + if [ -n "${DP_TEST_MODULE_VERSION:-}" ]; then + echo " └─ Version: $DP_TEST_MODULE_VERSION" + fi + if [ -n "${DP_TEST_MODULE_ISSUE_BRANCH:-}" ]; then + echo " └─ Testing PR: $DP_TEST_MODULE_ISSUE_FORK/$DP_TEST_MODULE_ISSUE_BRANCH" + fi fi +echo " - Dependencies: Auto-resolved from composer.json" diff --git a/.devpanel/git_setup.sh b/.devpanel/git_setup.sh deleted file mode 100755 index 35cd09ed..00000000 --- a/.devpanel/git_setup.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Add git.drupal.org to known_hosts -mkdir -p ~/.ssh -host=git.drupal.org -SSHKey=$(ssh-keyscan $host 2>/dev/null) -echo "$SSHKey" >>~/.ssh/known_hosts - -# Ignore specific directories during Drupal core development -cp "${APP_ROOT}"/.gitpod/drupal/templates/git-exclude.template "${APP_ROOT}"/.git/info/exclude - -# Get the required repo ready -if [ "$DP_STARTER_TEMPLATE" = "cms" ] && [ "$DP_PROJECT_TYPE" == "project_core" ]; then - # Clone Drupal CMS repo - if git submodule status repos/cms > /dev/null 2>&1; then - time git submodule update --init --recursive - else - time git submodule add -f https://git.drupalcode.org/project/cms.git repos/cms - time git config -f .gitmodules submodule."repos/cms".ignore dirty - fi - - # For CMS, check out the version branch/tag - d="$DP_VERSION" - case $d in - *.x) - checkout_type=origin - ;; - *) - checkout_type=tags - ;; - esac - - cd "${APP_ROOT}"/repos/cms && - git fetch origin && - git fetch --all --tags && - git checkout "$checkout_type"/"$DP_VERSION" - -elif [ "$DP_PROJECT_TYPE" == "project_core" ]; then - # Find if requested core version is dev or stable - d="$DP_VERSION" - case $d in - *.x) - # If dev - use git checkout origin/* - checkout_type=origin - ;; - *) - # stable - use git checkout tags/* - checkout_type=tags - ;; - esac - - # Clone Drupal core repo - if git submodule status repos/drupal > /dev/null 2>&1; then - time git submodule update --init --recursive - else - time git submodule add -f https://git.drupalcode.org/project/drupal.git repos/drupal - time git config -f .gitmodules submodule."repos/drupal".ignore dirty - fi - - # Use origin or tags in git checkout command - cd "${APP_ROOT}"/repos/drupal && - git fetch origin && - git fetch --all --tags && - git checkout "$checkout_type"/"$DP_VERSION" - - # Ignore specific directories during Drupal core development - cp "${APP_ROOT}"/.gitpod/drupal/templates/git-exclude.template "${APP_ROOT}"/.git/modules/repos/drupal/info/exclude -else - # If not core - clone selected project into /repos and remove existing repos. - if git submodule status repos/"$DP_PROJECT_NAME" > /dev/null 2>&1; then - time git submodule update --init --recursive - else - git rm -r repos/*/ - time git submodule add -f https://git.drupalcode.org/project/"$DP_PROJECT_NAME".git repos/"$DP_PROJECT_NAME" - time git config -f .gitmodules submodule."repos/$DP_PROJECT_NAME".ignore dirty - fi -fi - -# Set WORK_DIR -export WORK_DIR="${APP_ROOT}"/repos/$DP_PROJECT_NAME - -# Checkout specific branch only if there's issue_branch -if [ -n "$DP_ISSUE_BRANCH" ]; then - # If branch already exist only run checkout, - if cd "${WORK_DIR}" && git show-ref -q --heads "$DP_ISSUE_BRANCH"; then - cd "${WORK_DIR}" && git checkout "$DP_ISSUE_BRANCH" - else - cd "${WORK_DIR}" && git remote add "$DP_ISSUE_FORK" https://git.drupalcode.org/issue/"$DP_ISSUE_FORK".git - cd "${WORK_DIR}" && git fetch "$DP_ISSUE_FORK" - cd "${WORK_DIR}" && git checkout -b "$DP_ISSUE_BRANCH" --track "$DP_ISSUE_FORK"/"$DP_ISSUE_BRANCH" - fi -elif [ -n "$DP_MODULE_VERSION" ] && [ "$DP_PROJECT_TYPE" != "project_core" ]; then - cd "${WORK_DIR}" && git checkout "$DP_MODULE_VERSION" -fi - -git add . diff --git a/.devpanel/init.sh b/.devpanel/init.sh index b28052ea..41b1df3d 100755 --- a/.devpanel/init.sh +++ b/.devpanel/init.sh @@ -1,28 +1,40 @@ #!/usr/bin/env bash + +# Optional debug mode; strict error handling for safety. if [ -n "${DEBUG_SCRIPT:-}" ]; then set -x fi set -eu -o pipefail -cd $APP_ROOT +# Move into the application root and prepare logging. +cd "$APP_ROOT" mkdir -p logs LOG_FILE="logs/init-$(date +%F-%T).log" -exec > >(tee $LOG_FILE) 2>&1 +exec > >(tee "$LOG_FILE") 2>&1 +# Configure timing format for any timed operations below. TIMEFORMAT=%lR + # For faster performance, don't audit dependencies automatically. export COMPOSER_NO_AUDIT=1 + # For faster performance, don't install dev dependencies. +# @todo Should we keep it like this? export COMPOSER_NO_DEV=1 -# Assuming .sh files are in the same directory as this script +# The other bash files are in the same dir. DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# Always source fallback_setup to set all defaults -# This ensures DP_INSTALL_PROFILE and other variables are initialized +# Always source fallback_setup to set all defaults. +# This ensures DP_INSTALL_PROFILE and other variables are initialized. source "$DIR/fallback_setup.sh" -# Install VSCode Extensions +# Clone AI modules from git (always - base + provider + optional test module) +echo +echo 'Cloning AI modules from git...' +time source "$DIR/clone_ai_modules.sh" + +# Install VSCode Extensions. if [ -n "${DP_VSCODE_EXTENSIONS:-}" ]; then IFS=',' for value in $DP_VSCODE_EXTENSIONS; do @@ -30,17 +42,22 @@ if [ -n "${DP_VSCODE_EXTENSIONS:-}" ]; then done fi -#== Clean rebuild if requested. +#== Clean rebuild vs incremental install. +# DP_REBUILD=1: Clean rebuild - delete vendor, web, composer files (fresh start). +# DP_REBUILD=0: Incremental install - preserve existing files (useful for resuming failed installs). if [ "${DP_REBUILD:-0}" = "1" ]; then echo echo 'Performing clean rebuild...' - echo 'Removing vendor and web directories...' - time rm -rf vendor web/core web/modules/contrib web/themes/contrib web/profiles/contrib composer.lock + echo 'Removing vendor, web, and composer files...' + time rm -rf vendor web/core web/modules/contrib web/themes/contrib web/profiles/contrib composer.json composer.lock echo 'Rebuild mode enabled.' echo fi -#== Remove root-owned files. +#== Remove root-owned filesystem artifacts. +# Docker/DDEV volumes sometimes create root-owned 'lost+found' directories (filesystem recovery artifacts). +# These aren't needed for the application and can cause confusion, permission errors, or block operations. +# Requires sudo because they're owned by root. echo echo Remove root-owned files. time sudo rm -rf lost+found @@ -58,8 +75,35 @@ elif [ -f composer.json ]; then echo fi fi + echo 'Running composer update...' -time composer -n update --no-dev --no-progress || { echo "Composer update failed!"; exit 1; } +# Note: May show patch warnings, but packages are still installed successfully +time composer -n update --no-dev --no-progress || { + echo "Composer update encountered errors (likely patch failures), but continuing..." + echo "Regenerating autoload files..." + composer dump-autoload +} + +# Validate module compatibility. If users try to get versions +# that conflict, we need to warn them. +echo +echo 'Validating AI module compatibility...' +if composer validate --no-check-all --no-check-publish 2>&1 | grep -q "is valid"; then + echo "✓ Composer validation passed" +else + echo "⚠️ Composer validation found warnings (this may be OK)" +fi + +# Check if AI modules are properly symlinked. +if [ -L web/modules/contrib/ai ] && [ -L web/modules/contrib/ai_provider_litellm ]; then + echo "✓ AI modules symlinked from git:" + echo " - $(readlink web/modules/contrib/ai)" + echo " - $(readlink web/modules/contrib/ai_provider_litellm)" +else + echo "⚠️ AI modules not symlinked - may be using Composer versions" +fi + +echo 'Composer dependencies installed.' #== Create the private files directory. if [ ! -d private ]; then diff --git a/.devpanel/repos/.gitkeep b/.devpanel/repos/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.gitignore b/.gitignore index 6b896c57..dd798b80 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,60 @@ -/.devpanel/dumps/ +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Drupal / Composer +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +/recipes +/vendor +/web +/web/core +/web/modules/contrib +/web/themes/contrib +/web/profiles/contrib +/web/libraries +composer.lock +patches.lock.json +.gitattributes +.editorconfig + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Runtime / Generated +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +/logs /.devpanel/salt.txt -/.editorconfig -/.gitattributes -/.vscode/ -/composer.json -/composer.lock -/config/ -/logs/* -/patches.lock.json -/private/ -/README.md -/recipes/ -/vendor/ -/web/ +/private +/config/sync +composer.json +LICENSE.txt + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# AI Modules (git submodules - managed by .gitmodules) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +/repos/* +!/repos/.gitkeep + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Node / Testing +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +/node_modules +package-lock.json + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# User-specific Config (users customize per environment) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +.ddev/config.drupal.yaml + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# macOS +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +.DS_Store +.AppleDouble +.LSOverride +._* +.Spotlight-V100 +.Trashes + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Windows +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ diff --git a/.gitmodules b/.gitmodules index 10908d5e..51477f7a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,19 @@ path = repos/drupal url = https://git.drupalcode.org/project/drupal.git ignore = dirty +[submodule "repos/ai"] + path = repos/ai + url = https://git.drupalcode.org/project/ai.git + ignore = dirty +[submodule "repos/ai_provider_litellm"] + path = repos/ai_provider_litellm + url = https://git.drupalcode.org/project/ai_provider_litellm.git + ignore = dirty +[submodule "repos/ai_search"] + path = repos/ai_search + url = https://git.drupalcode.org/project/ai_search.git + ignore = dirty +[submodule "repos/ai_agents"] + path = repos/ai_agents + url = https://git.drupalcode.org/project/ai_agents.git + ignore = dirty diff --git a/package.json b/package.json new file mode 100644 index 00000000..c18d7b92 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "drupalpod-ai-qa", + "version": "1.0.0", + "description": "DrupalPod AI QA Environment with automated testing", + "scripts": { + "test": "bats tests/*.bats", + "test:unit": "bats tests/clone_ai_modules.bats tests/fallback_setup.bats", + "test:integration": "bats tests/integration.bats", + "test:verbose": "bats -t tests/*.bats" + }, + "devDependencies": { + "bats": "^1.11.0" + }, + "keywords": [ + "drupal", + "ai", + "testing", + "ddev" + ] +} diff --git a/repos/drupal b/repos/drupal deleted file mode 160000 index 96512344..00000000 --- a/repos/drupal +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 965123445745f50c7fc001c72a96650518c267d2 diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 00000000..64032a06 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,105 @@ +# DevPanel Shell Script Tests + +Test suite for `.devpanel/*.sh` scripts using [bats](https://github.com/bats-core/bats-core). + +**Tests verify logic and decisions, not actual execution** - no repos are cloned, no composer is run! + +## Installation + +```bash +# Install dependencies +npm install + +# Or install bats manually +brew install bats-core # macOS +sudo apt-get install bats # Ubuntu/Debian +``` + +## Running Tests + +```bash +# Run all tests +npm test + +# Unit tests only (helper functions) +npm run test:unit + +# Integration tests only (decision logic) +npm run test:integration + +# Verbose output +npm run test:verbose + +# Run specific test file +bats tests/integration.bats +``` + +## Test Structure + +### Unit Tests (Helper Functions) + +**`fallback_setup.bats`** - Tests for `.devpanel/fallback_setup.sh` +- ✓ Default value detection +- ✓ AI version auto-detection from CMS/Core version +- ✓ Explicit version tracking (DP_AI_MODULE_VERSION_EXPLICIT flag) +- ✓ Version validation (CMS vs Core) + +**`clone_ai_modules.bats`** - Tests for `.devpanel/clone_ai_modules.sh` +- ✓ Helper function tests (`get_compatible_version`, `is_compatible_with_ai`) +- ✓ Version constraint parsing (^2.0 → 2.0.x, ~1.2.0 → 1.2.x) +- ✓ Compatibility checking +- ✓ Edge cases (missing composer.json, no AI dependency) + +### Integration Tests (Decision Logic) + +**`integration.bats`** - Tests the **decisions** the scripts make (without actually cloning or installing): + +**Use Case: Test Module Specified** +- ✓ ai_search with empty AI version → auto-detect AI 2.0.x +- ✓ ai_search with explicit AI 1.2.x → detect conflict (should fail) + +**Use Case: DP_AI_MODULES with Compatibility Filtering** +- ✓ AI 1.2.x → ai_search incompatible (skip) +- ✓ AI 1.2.x → ai_provider_litellm compatible (include) +- ✓ AI 1.2.x → ai_agents compatible (include) +- ✓ AI 2.0.x → ai_search compatible (include) + +**Use Case: Edge Cases** +- ✓ Module without composer.json → treat as compatible +- ✓ Module without AI dependency → treat as compatible + +## Writing New Tests + +```bash +@test "descriptive test name" { + # Setup + export SOME_VAR="value" + + # Run command + run some_command + + # Assertions + [ "$status" -eq 0 ] # Exit code 0 + [[ "$output" =~ "pattern" ]] # Output matches pattern + [ "$result" = "expected" ] # Exact match +} +``` + +## CI Integration + +Add to `.github/workflows/test.yml`: + +```yaml +name: Tests + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - run: npm ci + - run: npm test +``` diff --git a/tests/clone_ai_modules.bats b/tests/clone_ai_modules.bats new file mode 100644 index 00000000..6fe12baa --- /dev/null +++ b/tests/clone_ai_modules.bats @@ -0,0 +1,178 @@ +#!/usr/bin/env bats + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Test Suite for clone_ai_modules.sh +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +setup() { + # Set up test environment + export APP_ROOT="$(pwd)" + export DP_AI_MODULE="ai" + + # Create test repos directory structure + mkdir -p repos/ai + mkdir -p repos/ai_search + mkdir -p repos/ai_provider_litellm + mkdir -p repos/ai_agents + + # Create mock composer.json files for testing + cat > repos/ai/composer.json <<'EOF' +{ + "name": "drupal/ai", + "require": { + "php": ">=8.1" + } +} +EOF + + cat > repos/ai_search/composer.json <<'EOF' +{ + "name": "drupal/ai_search", + "require": { + "drupal/ai": "^2.0" + } +} +EOF + + cat > repos/ai_provider_litellm/composer.json <<'EOF' +{ + "name": "drupal/ai_provider_litellm", + "require": { + "drupal/ai": "^1.2" + } +} +EOF + + cat > repos/ai_agents/composer.json <<'EOF' +{ + "name": "drupal/ai_agents", + "require": { + "drupal/ai": "^1.2" + } +} +EOF + + # Source ONLY helper functions (not main execution logic) + # Extract function definitions without running the script + eval "$(sed -n '/^get_ai_dependencies()/,/^}/p' .devpanel/clone_ai_modules.sh)" + eval "$(sed -n '/^get_compatible_version()/,/^}/p' .devpanel/clone_ai_modules.sh)" + eval "$(sed -n '/^is_compatible_with_ai()/,/^}/p' .devpanel/clone_ai_modules.sh)" +} + +teardown() { + # Clean up test directories + rm -rf repos/ai repos/ai_search repos/ai_provider_litellm repos/ai_agents +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Helper Function Tests +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "get_compatible_version extracts AI requirement from ai_search" { + result=$(get_compatible_version "repos/ai_search" "ai") + [ "$result" = "2.0.x" ] +} + +@test "get_compatible_version extracts AI requirement from ai_provider_litellm" { + result=$(get_compatible_version "repos/ai_provider_litellm" "ai") + [ "$result" = "1.2.x" ] +} + +@test "get_compatible_version returns empty for missing dependency" { + result=$(get_compatible_version "repos/ai_search" "nonexistent") + [ -z "$result" ] +} + +@test "is_compatible_with_ai: ai_provider_litellm compatible with AI 1.2.x" { + run is_compatible_with_ai "repos/ai_provider_litellm" "1.2.x" + [ "$status" -eq 0 ] +} + +@test "is_compatible_with_ai: ai_search incompatible with AI 1.2.x" { + run is_compatible_with_ai "repos/ai_search" "1.2.x" + [ "$status" -eq 1 ] +} + +@test "is_compatible_with_ai: ai_search compatible with AI 2.0.x" { + run is_compatible_with_ai "repos/ai_search" "2.0.x" + [ "$status" -eq 0 ] +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Version Constraint Parsing Tests +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "parse version constraint: ^2.0 → 2.0.x" { + # Create directory first, then composer.json + mkdir -p repos/test + cat > repos/test/composer.json <<'EOF' +{ + "require": { + "drupal/ai": "^2.0" + } +} +EOF + result=$(get_compatible_version "repos/test" "ai") + [ "$result" = "2.0.x" ] + rm -rf repos/test +} + +@test "parse version constraint: ^1.2.0 → 1.2.x" { + mkdir -p repos/test + cat > repos/test/composer.json <<'EOF' +{ + "require": { + "drupal/ai": "^1.2.0" + } +} +EOF + result=$(get_compatible_version "repos/test" "ai") + [ "$result" = "1.2.x" ] + rm -rf repos/test +} + +@test "parse version constraint: ~1.2.0 → 1.2.x" { + mkdir -p repos/test + cat > repos/test/composer.json <<'EOF' +{ + "require": { + "drupal/ai": "~1.2.0" + } +} +EOF + result=$(get_compatible_version "repos/test" "ai") + [ "$result" = "1.2.x" ] + rm -rf repos/test +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Edge Cases +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "is_compatible_with_ai: module without composer.json is compatible" { + mkdir -p repos/test_no_composer + run is_compatible_with_ai "repos/test_no_composer" "1.2.x" + [ "$status" -eq 0 ] + rm -rf repos/test_no_composer +} + +@test "is_compatible_with_ai: module without AI dependency is compatible" { + mkdir -p repos/test_no_ai_dep + cat > repos/test_no_ai_dep/composer.json <<'EOF' +{ + "require": { + "php": ">=8.1" + } +} +EOF + run is_compatible_with_ai "repos/test_no_ai_dep" "1.2.x" + [ "$status" -eq 0 ] + rm -rf repos/test_no_ai_dep +} + +@test "get_compatible_version: handles missing composer.json gracefully" { + mkdir -p repos/test_missing + result=$(get_compatible_version "repos/test_missing" "ai") + [ -z "$result" ] + rm -rf repos/test_missing +} diff --git a/tests/fallback_setup.bats b/tests/fallback_setup.bats new file mode 100644 index 00000000..5ebdd98c --- /dev/null +++ b/tests/fallback_setup.bats @@ -0,0 +1,143 @@ +#!/usr/bin/env bats + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Test Suite for fallback_setup.sh +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +setup() { + export APP_ROOT="$(pwd)" + + # Unset all variables to test defaults + unset DP_STARTER_TEMPLATE + unset DP_VERSION + unset DP_AI_MODULE + unset DP_AI_MODULE_VERSION + unset DP_AI_MODULE_VERSION_EXPLICIT + unset DP_TEST_MODULE +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Default Value Tests +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "DP_STARTER_TEMPLATE defaults to 'cms'" { + source .devpanel/fallback_setup.sh + [ "$DP_STARTER_TEMPLATE" = "cms" ] +} + +@test "DP_VERSION defaults to '1.x' for CMS" { + export DP_STARTER_TEMPLATE="cms" + source .devpanel/fallback_setup.sh + [ "$DP_VERSION" = "1.x" ] +} + +@test "DP_VERSION defaults to '11.2.8' for core" { + export DP_STARTER_TEMPLATE="core" + source .devpanel/fallback_setup.sh + [ "$DP_VERSION" = "11.2.8" ] +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# AI Version Auto-Detection Tests +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "CMS 2.x → AI 1.2.x" { + export DP_STARTER_TEMPLATE="cms" + export DP_VERSION="2.0.x" + source .devpanel/fallback_setup.sh + [ "$DP_AI_MODULE_VERSION" = "1.2.x" ] +} + +@test "CMS 1.x → AI 1.0.x" { + export DP_STARTER_TEMPLATE="cms" + export DP_VERSION="1.x" + source .devpanel/fallback_setup.sh + [ "$DP_AI_MODULE_VERSION" = "1.0.x" ] +} + +@test "Core 11.x → AI 1.2.x" { + export DP_STARTER_TEMPLATE="core" + export DP_VERSION="11.x" + source .devpanel/fallback_setup.sh + [ "$DP_AI_MODULE_VERSION" = "1.2.x" ] +} + +@test "Core 10.x → AI 1.0.x" { + export DP_STARTER_TEMPLATE="core" + export DP_VERSION="10.x" + source .devpanel/fallback_setup.sh + [ "$DP_AI_MODULE_VERSION" = "1.0.x" ] +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Explicit Version Tracking Tests +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "DP_AI_MODULE_VERSION_EXPLICIT=no when version is auto-detected" { + export DP_STARTER_TEMPLATE="core" + export DP_VERSION="11.x" + # Don't set DP_AI_MODULE_VERSION - let it auto-detect + source .devpanel/fallback_setup.sh + [ "$DP_AI_MODULE_VERSION_EXPLICIT" = "no" ] +} + +@test "DP_AI_MODULE_VERSION_EXPLICIT=yes when version is explicitly set" { + export DP_STARTER_TEMPLATE="core" + export DP_VERSION="11.x" + export DP_AI_MODULE_VERSION="2.0.x" # Explicitly set + source .devpanel/fallback_setup.sh + [ "$DP_AI_MODULE_VERSION_EXPLICIT" = "yes" ] + [ "$DP_AI_MODULE_VERSION" = "2.0.x" ] +} + +@test "Empty DP_AI_MODULE_VERSION is treated as unset (auto-detect)" { + export DP_STARTER_TEMPLATE="core" + export DP_VERSION="11.x" + export DP_AI_MODULE_VERSION="" # Empty string + source .devpanel/fallback_setup.sh + [ "$DP_AI_MODULE_VERSION_EXPLICIT" = "no" ] + [ "$DP_AI_MODULE_VERSION" = "1.2.x" ] # Auto-detected +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Version Validation Tests +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "Error: CMS template with core version (9.x)" { + export DP_STARTER_TEMPLATE="cms" + export DP_VERSION="9.x" + run source .devpanel/fallback_setup.sh + [ "$status" -eq 1 ] + [[ "$output" =~ "looks like a Drupal core version" ]] +} + +@test "Error: Core template with CMS version (1.x)" { + export DP_STARTER_TEMPLATE="core" + export DP_VERSION="1.x" + run source .devpanel/fallback_setup.sh + [ "$status" -eq 1 ] + [[ "$output" =~ "looks like a CMS version" ]] +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Install Profile Tests +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "CMS uses empty install profile (auto-detect drupal_cms_installer)" { + export DP_STARTER_TEMPLATE="cms" + source .devpanel/fallback_setup.sh + [ -z "$DP_INSTALL_PROFILE" ] +} + +@test "Core uses 'standard' install profile" { + export DP_STARTER_TEMPLATE="core" + source .devpanel/fallback_setup.sh + [ "$DP_INSTALL_PROFILE" = "standard" ] +} + +@test "Custom install profile can be overridden" { + export DP_STARTER_TEMPLATE="cms" + export DP_INSTALL_PROFILE="minimal" + source .devpanel/fallback_setup.sh + [ "$DP_INSTALL_PROFILE" = "minimal" ] +} diff --git a/tests/integration.bats b/tests/integration.bats new file mode 100644 index 00000000..7043f937 --- /dev/null +++ b/tests/integration.bats @@ -0,0 +1,215 @@ +#!/usr/bin/env bats + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Integration Tests - Verify Script Decisions (Not Actual Execution) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Tests verify the script makes correct decisions about: +# - Which modules to clone +# - What versions to use +# - When to fail vs continue +# - Compatibility filtering +# +# We DON'T actually clone repos or run composer - just verify logic! +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +setup() { + export APP_ROOT="$(pwd)" + + # Create mock repo structure with composer.json files + mkdir -p repos/{ai,ai_search,ai_provider_litellm,ai_agents} + + # ai_search requires AI ^2.0 + cat > repos/ai_search/composer.json <<'EOF' +{"require": {"drupal/ai": "^2.0"}} +EOF + + # ai_provider_litellm requires AI ^1.2 + cat > repos/ai_provider_litellm/composer.json <<'EOF' +{"require": {"drupal/ai": "^1.2"}} +EOF + + # ai_agents requires AI ^1.2 + cat > repos/ai_agents/composer.json <<'EOF' +{"require": {"drupal/ai": "^1.2"}} +EOF + + # Stub the clone_module function to just track what would be cloned + clone_module() { + local module_name=$1 + echo "WOULD_CLONE: $module_name" >&2 + + # Track in CLONED_AI_MODULES + if [ -z "$CLONED_AI_MODULES" ]; then + export CLONED_AI_MODULES="$module_name" + else + export CLONED_AI_MODULES="$CLONED_AI_MODULES,$module_name" + fi + } + export -f clone_module +} + +teardown() { + rm -rf repos +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Use Case: Test Module Specified (Auto-Detect AI Version) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "Test module ai_search → auto-detect AI 2.0.x" { + export DP_AI_MODULE="ai" + export DP_AI_MODULE_VERSION="" # Empty = auto-detect + export DP_AI_MODULE_VERSION_EXPLICIT="no" + export DP_TEST_MODULE="ai_search" + export DP_AI_MODULES="" + + # Load helper functions without executing main script + eval "$(sed -n '/^get_compatible_version()/,/^}/p' .devpanel/clone_ai_modules.sh)" + + # Get AI requirement from test module + ai_requirement=$(get_compatible_version "repos/ai_search" "ai") + + # Verify decision + [ "$ai_requirement" = "2.0.x" ] +} + +@test "Test module set + explicit AI version mismatch → should fail" { + export DP_AI_MODULE="ai" + export DP_AI_MODULE_VERSION="1.2.x" # Explicitly set + export DP_AI_MODULE_VERSION_EXPLICIT="yes" + export DP_TEST_MODULE="ai_search" # Needs 2.0.x + + eval "$(sed -n '/^get_compatible_version()/,/^}/p' .devpanel/clone_ai_modules.sh)" + + test_module_ai_requirement=$(get_compatible_version "repos/ai_search" "ai") + + # Verify we detected the conflict + [ "$test_module_ai_requirement" = "2.0.x" ] + [ "$DP_AI_MODULE_VERSION" = "1.2.x" ] + [ "$test_module_ai_requirement" != "$DP_AI_MODULE_VERSION" ] + # Script should fail in this case (verified separately) +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Use Case: No Test Module (Use DP_AI_MODULES with Compatibility Filtering) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "DP_AI_MODULES: ai_search incompatible with AI 1.2.x → should skip" { + export DP_AI_MODULE_VERSION="1.2.x" + + eval "$(sed -n '/^is_compatible_with_ai()/,/^}/p' .devpanel/clone_ai_modules.sh)" + eval "$(sed -n '/^get_compatible_version()/,/^}/p' .devpanel/clone_ai_modules.sh)" + + # Check if ai_search is compatible with AI 1.2.x + run is_compatible_with_ai "repos/ai_search" "1.2.x" + + # Should be incompatible (exit 1) + [ "$status" -eq 1 ] + [[ "$output" =~ "Incompatible" ]] +} + +@test "DP_AI_MODULES: ai_provider_litellm compatible with AI 1.2.x → should include" { + export DP_AI_MODULE_VERSION="1.2.x" + + eval "$(sed -n '/^is_compatible_with_ai()/,/^}/p' .devpanel/clone_ai_modules.sh)" + eval "$(sed -n '/^get_compatible_version()/,/^}/p' .devpanel/clone_ai_modules.sh)" + + # Check if ai_provider_litellm is compatible with AI 1.2.x + run is_compatible_with_ai "repos/ai_provider_litellm" "1.2.x" + + # Should be compatible (exit 0) + [ "$status" -eq 0 ] +} + +@test "DP_AI_MODULES: ai_agents compatible with AI 1.2.x → should include" { + export DP_AI_MODULE_VERSION="1.2.x" + + eval "$(sed -n '/^is_compatible_with_ai()/,/^}/p' .devpanel/clone_ai_modules.sh)" + eval "$(sed -n '/^get_compatible_version()/,/^}/p' .devpanel/clone_ai_modules.sh)" + + # Check if ai_agents is compatible with AI 1.2.x + run is_compatible_with_ai "repos/ai_agents" "1.2.x" + + # Should be compatible (exit 0) + [ "$status" -eq 0 ] +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Use Case: Verify Correct Modules Get Added to COMPATIBLE_AI_MODULES +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "Compatibility filtering: AI 1.2.x should only include compatible modules" { + export DP_AI_MODULE_VERSION="1.2.x" + export COMPATIBLE_AI_MODULES="" + + eval "$(sed -n '/^is_compatible_with_ai()/,/^}/p' .devpanel/clone_ai_modules.sh)" + eval "$(sed -n '/^get_compatible_version()/,/^}/p' .devpanel/clone_ai_modules.sh)" + + # Simulate checking each module + modules="ai_provider_litellm ai_search ai_agents" + + for module in $modules; do + if is_compatible_with_ai "repos/$module" "1.2.x" 2>/dev/null; then + if [ -z "$COMPATIBLE_AI_MODULES" ]; then + COMPATIBLE_AI_MODULES="$module" + else + COMPATIBLE_AI_MODULES="$COMPATIBLE_AI_MODULES,$module" + fi + fi + done + + # Verify: should include ai_provider_litellm and ai_agents, but NOT ai_search + [[ "$COMPATIBLE_AI_MODULES" =~ "ai_provider_litellm" ]] + [[ "$COMPATIBLE_AI_MODULES" =~ "ai_agents" ]] + [[ ! "$COMPATIBLE_AI_MODULES" =~ "ai_search" ]] +} + +@test "Compatibility filtering: AI 2.0.x should include ai_search" { + export DP_AI_MODULE_VERSION="2.0.x" + export COMPATIBLE_AI_MODULES="" + + eval "$(sed -n '/^is_compatible_with_ai()/,/^}/p' .devpanel/clone_ai_modules.sh)" + eval "$(sed -n '/^get_compatible_version()/,/^}/p' .devpanel/clone_ai_modules.sh)" + + # Check if ai_search is compatible with AI 2.0.x + if is_compatible_with_ai "repos/ai_search" "2.0.x" 2>/dev/null; then + COMPATIBLE_AI_MODULES="ai_search" + fi + + # Verify: should include ai_search + [ "$COMPATIBLE_AI_MODULES" = "ai_search" ] +} + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Use Case: Module Without composer.json or AI Dependency +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +@test "Module without composer.json is treated as compatible" { + mkdir -p repos/custom_module + # No composer.json + + eval "$(sed -n '/^is_compatible_with_ai()/,/^}/p' .devpanel/clone_ai_modules.sh)" + + run is_compatible_with_ai "repos/custom_module" "1.2.x" + + # Should be compatible (exit 0) + [ "$status" -eq 0 ] + + rm -rf repos/custom_module +} + +@test "Module without AI dependency is treated as compatible" { + mkdir -p repos/standalone_module + cat > repos/standalone_module/composer.json <<'EOF' +{"require": {"php": ">=8.1"}} +EOF + + eval "$(sed -n '/^is_compatible_with_ai()/,/^}/p' .devpanel/clone_ai_modules.sh)" + + run is_compatible_with_ai "repos/standalone_module" "1.2.x" + + # Should be compatible (exit 0) + [ "$status" -eq 0 ] + + rm -rf repos/standalone_module +} From 22cde1498ddbdfc6108123f77a041bd387d679ef Mon Sep 17 00:00:00 2001 From: LittlePixieZ Date: Fri, 28 Nov 2025 14:24:53 +0000 Subject: [PATCH 6/9] Capturing latest place, latest stable tag not good enough for when getting a dev branch of AI --- .ddev/config.yaml | 47 ++- .devpanel/clone_ai_modules.sh | 104 ++++- .devpanel/fallback_setup.sh | 54 +-- .devpanel/init.sh | 4 +- .gitignore | 2 + Drupal Core Development Composer Project.md | 211 ---------- README.md | 100 ----- TESTING.md | 430 ++++++++++++++++++++ repos/ai | 1 + repos/ai_agents | 1 + repos/ai_provider_litellm | 1 + repos/ai_search | 1 + tests/fallback_setup.bats | 22 +- 13 files changed, 593 insertions(+), 385 deletions(-) delete mode 100644 Drupal Core Development Composer Project.md delete mode 100644 README.md create mode 100644 TESTING.md create mode 160000 repos/ai create mode 160000 repos/ai_agents create mode 160000 repos/ai_provider_litellm create mode 160000 repos/ai_search diff --git a/.ddev/config.yaml b/.ddev/config.yaml index 74864580..8b1702d1 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -17,7 +17,7 @@ hooks: use_dns_when_possible: true composer_version: "2" web_environment: - # Set up DevPanel variables. + # Set up DevPanel variables. DO NOT CHANGE - APP_ROOT=$DDEV_COMPOSER_ROOT - WEB_ROOT=$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT - DB_HOST=db @@ -27,8 +27,51 @@ web_environment: - DB_NAME=db - DP_APP_ID=drupalpod_ai_qa - DB_DRIVER=mysql - # AI ecosystem modules to always try to clone (compatibility filtered) - DP_AI_MODULES=ai_provider_litellm,ai_search,ai_agents + + - # ============================================================================ + - # DevPanel / Drupal defaults - customisable + - # ============================================================================ + + - # --------------------------------------------------------------------------- + - # Direct mappings to your DDEV environment variables (keep names identical) + - # --------------------------------------------------------------------------- + - DP_STARTER_TEMPLATE=cms # Starter template (e.g., core, demo, etc.) + - DP_VERSION=2.0.x # Drupal version + + - # --------------------------------------------------------------------------- + - # AI module / PR testing defaults + - # - DP_AI_MODULE_VERSION behavior: + - # * Empty = Auto-detect from test module (recommended) + - # * Set explicitly = Validate compatibility (fails if test module incompatible) + - # - DP_AI_ISSUE_FORK / DP_AI_ISSUE_BRANCH: test a PR for the base module + - # --------------------------------------------------------------------------- + - DP_AI_MODULE=ai # Base AI module name + - DP_AI_MODULE_VERSION= # Empty = auto-detect (or set explicitly to validate) + - DP_AI_ISSUE_FORK= + - DP_AI_ISSUE_BRANCH= + + - # --------------------------------------------------------------------------- + - # Test any AI sub-module (ai_search, ai_agents, providers, etc.) + - # - Setting DP_TEST_MODULE will auto-detect required AI version! + - # - The script clones test module first, reads its AI requirement, then clones AI + - # - Use DP_TEST_MODULE_VERSION to pin a release-style version (optional) + - # - Use DP_TEST_MODULE_ISSUE_FORK / DP_TEST_MODULE_ISSUE_BRANCH to test PRs + - # --------------------------------------------------------------------------- + - DP_TEST_MODULE= # Empty = use auto-detected AI version + - DP_TEST_MODULE_VERSION= # Empty = use dev branch + - DP_TEST_MODULE_ISSUE_FORK= + - DP_TEST_MODULE_ISSUE_BRANCH= + + - # --------------------------------------------------------------------------- + - # Optional: local or cloud API key for LiteLLM / provider testing (empty by default) + - # --------------------------------------------------------------------------- + - DP_AI_VIRTUAL_KEY= + + - # --------------------------------------------------------------------------- + - # Set to 1 if you wish to rebuild the whole project from scratch + - # --------------------------------------------------------------------------- + - DP_REBUILD=1 corepack_enable: false ddev_version_constraint: '>=1.24.0' diff --git a/.devpanel/clone_ai_modules.sh b/.devpanel/clone_ai_modules.sh index 886d0e18..e0f238ff 100755 --- a/.devpanel/clone_ai_modules.sh +++ b/.devpanel/clone_ai_modules.sh @@ -56,8 +56,11 @@ clone_module() { if git show-ref --verify --quiet refs/remotes/origin/"$module_version"; then git checkout -B "$module_version" origin/"$module_version" else - echo " ⚠️ Branch $module_version not found, using default" - git checkout $(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5) + echo " ⚠️ Branch $module_version not found, using latest stable" + latest_tag=$(git describe --tags --abbrev=0 $(git rev-list --tags --max-count=1) 2>/dev/null || true) + if [ -n "$latest_tag" ]; then + git checkout tags/"$latest_tag" + fi fi else # Try as tag, then branch @@ -66,10 +69,23 @@ clone_module() { elif git show-ref --verify --quiet refs/remotes/origin/"$module_version"; then git checkout -B "$module_version" origin/"$module_version" else - echo " ⚠️ Version $module_version not found, using default" - git checkout $(git remote show origin | grep 'HEAD branch' | cut -d' ' -f5) + echo " ⚠️ Version $module_version not found, using latest stable" + latest_tag=$(git describe --tags --abbrev=0 $(git rev-list --tags --max-count=1) 2>/dev/null || true) + if [ -n "$latest_tag" ]; then + git checkout tags/"$latest_tag" + fi fi fi + else + # No version specified - checkout latest stable tag + echo " → No version specified, checking out latest stable release" + latest_tag=$(git describe --tags --abbrev=0 $(git rev-list --tags --max-count=1) 2>/dev/null || true) + if [ -n "$latest_tag" ]; then + echo " → Found latest stable: $latest_tag" + git checkout tags/"$latest_tag" + else + echo " ⚠️ No tags found, using default branch" + fi fi cd "${APP_ROOT}" @@ -139,6 +155,13 @@ get_compatible_version() { is_compatible_with_ai() { local module_path=$1 local ai_version=$2 + + # If AI version is empty (using git default branch), we can't check compatibility + # Assume compatible - the actual version will be determined by git + if [ -z "$ai_version" ]; then + return 0 # Can't check compatibility without knowing AI version + fi + local composer_json="${module_path}/composer.json" if [ ! -f "$composer_json" ]; then @@ -171,15 +194,16 @@ is_compatible_with_ai() { } # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# Main Logic: Hybrid Architecture +# Main Logic: Hybrid Architecture (Dependency-Driven) # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# 1. If DP_TEST_MODULE set: Clone test module first, use its AI requirement -# 2. Otherwise: Use auto-detected AI version from compatibility matrix -# 3. Clone additional modules from DP_AI_MODULES with compatibility filtering +# 1. If DP_TEST_MODULE set: Clone test module first, read AI requirement from composer.json +# 2. If DP_AI_MODULE_VERSION set: Use that specific version (dev branch or tag) +# 3. Otherwise: Use latest stable tag (e.g., 1.2.1, not 1.2.x-dev) +# 4. Clone additional modules from DP_AI_MODULES with compatibility filtering # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# Determine final AI version to use -FINAL_AI_VERSION="$DP_AI_MODULE_VERSION" +# Determine final AI version to use (empty = latest stable tag) +FINAL_AI_VERSION="${DP_AI_MODULE_VERSION}" # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Step 1: Clone test module first (if specified) to determine AI requirements @@ -227,10 +251,14 @@ if [ -n "${DP_TEST_MODULE:-}" ]; then else # Couldn't determine requirement from test module if [ "${DP_AI_MODULE_VERSION_EXPLICIT:-no}" = "no" ]; then - echo " ⚠️ Could not determine AI version from test module" - echo " → Using compatibility matrix default: $FINAL_AI_VERSION" + echo " ⚠️ Could not determine AI version from test module's composer.json" + if [ -z "$FINAL_AI_VERSION" ]; then + echo " → Using git repo's default branch (future-proof)" + else + echo " → Using default: $FINAL_AI_VERSION" + fi else - echo " ⚠️ Could not determine AI version from test module" + echo " ⚠️ Could not determine AI version from test module's composer.json" echo " → Using your configured version: $FINAL_AI_VERSION" fi fi @@ -246,7 +274,11 @@ else echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "Step 1: No Test Module" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo " → Using AI version from compatibility matrix: $FINAL_AI_VERSION" + if [ -z "$FINAL_AI_VERSION" ]; then + echo " → Will use latest stable release tag" + else + echo " → Using explicitly configured AI version: $FINAL_AI_VERSION" + fi fi # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ @@ -254,11 +286,53 @@ fi # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ echo echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -echo "Step 2: Clone AI Base Module @ $FINAL_AI_VERSION" +if [ -z "$FINAL_AI_VERSION" ]; then + echo "Step 2: Clone AI Base Module @ latest stable" +else + echo "Step 2: Clone AI Base Module @ $FINAL_AI_VERSION" +fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" clone_module "$DP_AI_MODULE" "$FINAL_AI_VERSION" "$DP_AI_ISSUE_FORK" "$DP_AI_ISSUE_BRANCH" +# If AI version was empty (latest stable tag), detect the actual version for compatibility filtering +if [ -z "$FINAL_AI_VERSION" ]; then + cd "${APP_ROOT}"/repos/"$DP_AI_MODULE" + + # Try multiple methods to detect version + # Method 1: Current branch name (works if checked out to a branch) + actual_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true) + + if [[ "$actual_branch" =~ ^[0-9]+\.[0-9x]+$ ]] || [[ "$actual_branch" =~ ^[0-9]+\.x$ ]]; then + FINAL_AI_VERSION="$actual_branch" + echo " → Detected AI version from branch: $FINAL_AI_VERSION" + else + # Method 2: Check which remote branch this commit belongs to (handles detached HEAD) + remote_branch=$(git branch -r --contains HEAD 2>/dev/null | grep -E 'origin/[0-9]+\.(x|[0-9]+\.x)$' | head -1 | xargs | sed 's|.*origin/||' || true) + + if [ -n "$remote_branch" ] && [[ "$remote_branch" =~ ^[0-9]+\.[0-9x]+$ ]]; then + FINAL_AI_VERSION="$remote_branch" + echo " → Detected AI version from remote branch: $FINAL_AI_VERSION" + else + # Method 3: Try git describe to find nearest tag + nearest_tag=$(git describe --tags --abbrev=0 2>/dev/null || true) + if [ -n "$nearest_tag" ]; then + # Convert tag to branch format (e.g., 1.2.0 → 1.2.x, 2.0.0-alpha1 → 2.0.x) + FINAL_AI_VERSION=$(echo "$nearest_tag" | sed -E 's/^([0-9]+\.[0-9]+).*/\1.x/') + echo " → Detected AI version from tag: $FINAL_AI_VERSION (from $nearest_tag)" + fi + fi + fi + + cd "${APP_ROOT}" + + if [ -n "$FINAL_AI_VERSION" ]; then + echo " ✓ Using detected version for compatibility filtering: $FINAL_AI_VERSION" + else + echo " ⚠️ Could not detect AI version - skipping compatibility filtering" + fi +fi + # AI base is always compatible if [ -z "$COMPATIBLE_AI_MODULES" ]; then export COMPATIBLE_AI_MODULES="$DP_AI_MODULE" diff --git a/.devpanel/fallback_setup.sh b/.devpanel/fallback_setup.sh index 145677cc..8b653c1f 100755 --- a/.devpanel/fallback_setup.sh +++ b/.devpanel/fallback_setup.sh @@ -59,49 +59,12 @@ if [ -z "${DP_INSTALL_PROFILE+x}" ]; then fi # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# AI MODULE CONFIGURATION (always use git for AI modules) +# AI MODULE CONFIGURATION (Dependency-Driven Architecture) # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -# Auto-detect compatible AI module version based on CMS/Core version -if [ "$DP_STARTER_TEMPLATE" = "cms" ]; then - case "$DP_VERSION" in - 2.0.x|2.x|2.0.*) - # CMS 2.x requires AI ^1.2 - DEFAULT_AI_VERSION="1.2.x" - echo "Detected CMS 2.x → Using AI modules 1.2.x" - ;; - 1.x|1.0.x|1.*.*) - # CMS 1.x requires AI ^1.0 - DEFAULT_AI_VERSION="1.0.x" - echo "Detected CMS 1.x → Using AI modules 1.0.x" - ;; - *) - echo "⚠️ WARNING: Unknown CMS version '$DP_VERSION', defaulting to AI 1.2.x" - DEFAULT_AI_VERSION="1.2.x" - ;; - esac -else - # Drupal Core - case "$DP_VERSION" in - 11.*|11.x) - # Drupal 11.x works with AI ^1.2 - DEFAULT_AI_VERSION="1.2.x" - echo "Detected Drupal Core 11.x → Using AI modules 1.2.x" - ;; - 10.*|10.x) - # Drupal 10.x works with AI ^1.0 - DEFAULT_AI_VERSION="1.0.x" - echo "Detected Drupal Core 10.x → Using AI modules 1.0.x" - ;; - *) - echo "⚠️ WARNING: Unknown Core version '$DP_VERSION', defaulting to AI 1.2.x" - DEFAULT_AI_VERSION="1.2.x" - ;; - esac -fi - -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# AI Module Configuration (Dependency-Driven Architecture) +# AI version is dynamically determined from: +# 1. Test module's composer.json (if DP_TEST_MODULE set) +# 2. Latest dev branch (if not set) +# No hardcoded version mappings - let dependencies drive the version! # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # AI base module (ALWAYS cloned from git) @@ -109,12 +72,15 @@ export DP_AI_MODULE=${DP_AI_MODULE:-'ai'} # Track if user explicitly set AI version (for validation when testing modules) if [ -z "${DP_AI_MODULE_VERSION:-}" ]; then - # User didn't set it - use default and mark as auto-detected - export DP_AI_MODULE_VERSION="$DEFAULT_AI_VERSION" + # User didn't set it - leave empty for auto-detection from test module + # If no test module, clone_ai_modules.sh will use latest dev branch + export DP_AI_MODULE_VERSION="" export DP_AI_MODULE_VERSION_EXPLICIT="no" + echo "📦 AI version will be auto-detected from test module dependencies" else # User explicitly set it - validate compatibility when testing modules export DP_AI_MODULE_VERSION_EXPLICIT="yes" + echo "📦 AI version explicitly set to: $DP_AI_MODULE_VERSION" fi export DP_AI_ISSUE_FORK=${DP_AI_ISSUE_FORK:-''} diff --git a/.devpanel/init.sh b/.devpanel/init.sh index 41b1df3d..dcb52b86 100755 --- a/.devpanel/init.sh +++ b/.devpanel/init.sh @@ -131,10 +131,10 @@ echo if [ "${DP_REBUILD:-0}" = "1" ] || ! drush status --field=bootstrap | grep -q "Drupal bootstrap"; then if [ -z "$DP_INSTALL_PROFILE" ]; then echo 'Install Drupal.' - time drush -n si + time drush -n si --account-name=admin --account-pass=admin else echo 'Install Drupal with profile: '"$DP_INSTALL_PROFILE" - time drush -n si "$DP_INSTALL_PROFILE" + time drush -n si "$DP_INSTALL_PROFILE" --account-name=admin --account-pass=admin fi #== Apply the AI recipe. diff --git a/.gitignore b/.gitignore index dd798b80..d5f9d285 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ composer.lock patches.lock.json .gitattributes .editorconfig +"Drupal Core Development Composer Project.md" +README.md # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Runtime / Generated diff --git a/Drupal Core Development Composer Project.md b/Drupal Core Development Composer Project.md deleted file mode 100644 index 608ae7de..00000000 --- a/Drupal Core Development Composer Project.md +++ /dev/null @@ -1,211 +0,0 @@ -# Drupal Core Development Composer Project - -This is a Composer project template for developing Drupal core. - -It allows: - -- a clean git clone of Drupal core. -- Composer dependencies of Drupal core are installed, so Drupal can be installed - and run as normal. -- other Composer packages you might want, such as Drush, Devel module, and Admin - Toolbar module, can be installed too, but don't affect the composer files - that are part of Drupal core. - -## Installation - -To install a Drupal project for working on Drupal core: - -``` -$ composer create-project joachim-n/drupal-core-development-project -``` - -Composer will clone Drupal core into a 'repos/drupal' directory within the -project, and then symlink that into the project when it installs Drupal core. - -Once the installation is complete, you can install Drupal as normal, either with -`drush si` or with the web UI. - -## Limitations - -During some Composer commands you may see multiple copies of this error message: - -> Could not scan for classes inside [Drupal class filename]. - -These are harmless and can be ignored. - -## Developing Drupal core - -You can use the Drupal core git clone at 'repos/drupal/' in any way you like: -create feature branches, clone from drupal.org issue forks, and so on. Changes -you make to files in the git clone affect the project, since the git clone is -symlinked into it. - -### Managing the Composer project - -You can install any Composer packages you like, including Drupal contrib -modules, without affecting the git clone of Drupal core. To work with Composer, -you need to be in the root directory of the project. - -Changes to the git clone's composer.json will be taken into account by Composer. -So for example, if pulling from the main branch of Drupal core changes Composer -dependencies, and in particular if you change to a different core major or minor -branch, you should run `composer update` on the project to install these. - -### Running tests - -The following are required to run tests. - -#### PHPUnit configuration - -The simplest way to run tests with this setup is to put the phpunit.xml file in -the project root and then run tests from there: - -$ vendor/bin/phpunit web/core/PATH-TO-TEST-FILE/TestFile.php - -To set this up, copy Drupal core's sample phpunit.xml file to the project root: - -$ cp web/core/phpunit.xml.dist phpunit.xml - -Then change the `bootstrap` attribute so the path is correct: - -``` - Date: Thu, 4 Dec 2025 23:25:43 +0000 Subject: [PATCH 7/9] Moved Drupal into docroot, got CMS/core working, created images for cms & core - need to fix patches --- .ddev/config.yaml | 11 +- .devpanel/cleanup.sh | 5 - .devpanel/clone_ai_modules.sh | 20 +- .devpanel/composer_setup.sh | 36 +- .devpanel/create_quickstart.sh | 18 +- .devpanel/fallback_setup.sh | 40 +- .devpanel/init-container.sh | 23 +- .devpanel/init.sh | 180 ++---- .devpanel/logs/init-2025-12-04-21:55:09.log | 631 ++++++++++++++++++++ .devpanel/logs/init-2025-12-04-21:55:58.log | 631 ++++++++++++++++++++ .devpanel/re-config.sh | 20 +- .devpanel/salt.txt | 1 + .devpanel/setup_ai.sh | 31 + .devpanel/warm | 17 - .github/workflows/docker-publish-image.yml | 36 +- .github/workflows/docker-publish-images.yml | 26 +- .gitignore | 54 +- .gitmodules | 12 + docroot/repos/ai | 1 + docroot/repos/ai_agents | 1 + docroot/repos/ai_provider_litellm | 1 + docroot/repos/ai_search | 1 + recipes/.gitignore | 1 - 23 files changed, 1552 insertions(+), 245 deletions(-) delete mode 100755 .devpanel/cleanup.sh create mode 100644 .devpanel/logs/init-2025-12-04-21:55:09.log create mode 100644 .devpanel/logs/init-2025-12-04-21:55:58.log create mode 100644 .devpanel/salt.txt create mode 100755 .devpanel/setup_ai.sh delete mode 100755 .devpanel/warm create mode 160000 docroot/repos/ai create mode 160000 docroot/repos/ai_agents create mode 160000 docroot/repos/ai_provider_litellm create mode 160000 docroot/repos/ai_search delete mode 100644 recipes/.gitignore diff --git a/.ddev/config.yaml b/.ddev/config.yaml index 8b1702d1..4e1b8a86 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -1,6 +1,7 @@ type: drupal11 -docroot: web +docroot: docroot/web php_version: "8.3" +composer_root: docroot webserver_type: apache-fpm xdebug_enabled: false additional_hostnames: [] @@ -13,13 +14,13 @@ hooks: # Set up debugging. - exec: test -f .vscode/launch.json || mkdir -p .vscode && cp .ddev/launch.json .vscode/ # Run initial setup tasks only when needed (DP_REBUILD=1 or Drupal not installed). - - exec: 'if [ "${DP_REBUILD:-0}" = "1" ] || ! drush status --field=bootstrap 2>/dev/null | grep -q "Successful"; then .devpanel/init.sh; fi' + - exec: 'if [ "${DP_REBUILD:-0}" = "1" ] || ! drush status --field=bootstrap 2>/dev/null | grep -q "Successful"; then bash "$(pwd)/.devpanel/init.sh"; fi' use_dns_when_possible: true composer_version: "2" web_environment: # Set up DevPanel variables. DO NOT CHANGE - APP_ROOT=$DDEV_COMPOSER_ROOT - - WEB_ROOT=$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT + - WEB_ROOT=$DDEV_APPROOT/$DDEV_DOCROOT - DB_HOST=db - DB_PORT=3306 - DB_USER=db @@ -36,8 +37,8 @@ web_environment: - # --------------------------------------------------------------------------- - # Direct mappings to your DDEV environment variables (keep names identical) - # --------------------------------------------------------------------------- - - DP_STARTER_TEMPLATE=cms # Starter template (e.g., core, demo, etc.) - - DP_VERSION=2.0.x # Drupal version + - DP_STARTER_TEMPLATE=core # Starter template (e.g., core, demo, etc.) + - DP_VERSION=11.x # Drupal version - # --------------------------------------------------------------------------- - # AI module / PR testing defaults diff --git a/.devpanel/cleanup.sh b/.devpanel/cleanup.sh deleted file mode 100755 index 3ffcd95e..00000000 --- a/.devpanel/cleanup.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -eu -o pipefail - -# Remove composer.json. A fresh one will be generated. -rm -f "${APP_ROOT}"/composer.json diff --git a/.devpanel/clone_ai_modules.sh b/.devpanel/clone_ai_modules.sh index e0f238ff..31dcf7e7 100755 --- a/.devpanel/clone_ai_modules.sh +++ b/.devpanel/clone_ai_modules.sh @@ -1,6 +1,15 @@ #!/usr/bin/env bash set -eu -o pipefail -cd "${APP_ROOT}" + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Directory Setup (works in both DDEV and GitHub Actions environments) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Find the .devpanel directory (where this script lives) +DEVPANEL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Project root is one level up from .devpanel +PROJECT_ROOT="$(dirname "$DEVPANEL_DIR")" + +cd "$PROJECT_ROOT" # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Clone AI Modules from Git (Dependency-Driven Architecture) @@ -57,7 +66,7 @@ clone_module() { git checkout -B "$module_version" origin/"$module_version" else echo " ⚠️ Branch $module_version not found, using latest stable" - latest_tag=$(git describe --tags --abbrev=0 $(git rev-list --tags --max-count=1) 2>/dev/null || true) + latest_tag=$(git tag --sort=-version:refname | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true) if [ -n "$latest_tag" ]; then git checkout tags/"$latest_tag" fi @@ -70,16 +79,17 @@ clone_module() { git checkout -B "$module_version" origin/"$module_version" else echo " ⚠️ Version $module_version not found, using latest stable" - latest_tag=$(git describe --tags --abbrev=0 $(git rev-list --tags --max-count=1) 2>/dev/null || true) + latest_tag=$(git tag --sort=-version:refname | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true) if [ -n "$latest_tag" ]; then git checkout tags/"$latest_tag" fi fi fi else - # No version specified - checkout latest stable tag + # No version specified - checkout latest stable tag (by semantic version, not date) echo " → No version specified, checking out latest stable release" - latest_tag=$(git describe --tags --abbrev=0 $(git rev-list --tags --max-count=1) 2>/dev/null || true) + # Sort tags by semantic version (descending) and pick the highest + latest_tag=$(git tag --sort=-version:refname | grep -E '^[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true) if [ -n "$latest_tag" ]; then echo " → Found latest stable: $latest_tag" git checkout tags/"$latest_tag" diff --git a/.devpanel/composer_setup.sh b/.devpanel/composer_setup.sh index e08fe265..2e6ff51a 100755 --- a/.devpanel/composer_setup.sh +++ b/.devpanel/composer_setup.sh @@ -1,6 +1,17 @@ #!/usr/bin/env bash set -eu -o pipefail -cd $APP_ROOT + +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Directory Setup (works in both DDEV and GitHub Actions environments) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Find the .devpanel directory (where this script lives) +DEVPANEL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Project root is one level up from .devpanel +PROJECT_ROOT="$(dirname "$DEVPANEL_DIR")" +# APP_ROOT is the composer root (from environment or default to PROJECT_ROOT) +APP_ROOT="${APP_ROOT:-$PROJECT_ROOT}" + +cd "$APP_ROOT" # Determine which starter template to use. # Options: "cms" or "core" @@ -43,7 +54,7 @@ fi # - This is safer than deleting project root first (preserves files if script fails) # # Clean up temp directory if it exists from previous runs. -rm -rf "$APP_ROOT"/temp-composer-files +rm -rf temp-composer-files # Create the project template in temp directory. if [ -n "$install_version" ]; then @@ -52,11 +63,11 @@ else time composer create-project -n --no-install "$COMPOSER_PROJECT" temp-composer-files fi -# Copy all files (including hidden files) from temp to project root. -cp -r "$APP_ROOT"/temp-composer-files/. "$APP_ROOT"/. +# Copy all files (including hidden files) from temp to docroot. +cp -r temp-composer-files/. . # Clean up temp directory. -rm -rf "$APP_ROOT"/temp-composer-files +rm -rf temp-composer-files # Set minimum-stability to dev to allow alpha/beta packages (needed for dev versions). composer config minimum-stability dev @@ -76,14 +87,9 @@ composer config --no-plugins allow-plugins.php-http/discovery true composer config --no-plugins allow-plugins.tbachert/spi false # Scaffold settings.php. -composer config -jm extra.drupal-scaffold.file-mapping '{ - "[web-root]/sites/default/settings.php": { - "path": "web/core/assets/scaffold/files/default.settings.php", - "overwrite": false - } -}' +composer config extra.drupal-scaffold.file-mapping '{"[web-root]/sites/default/settings.php":{"path":"web/core/assets/scaffold/files/default.settings.php","overwrite":false}}' composer config scripts.post-drupal-scaffold-cmd \ - 'cd web/sites/default && test -z "$(grep '\''include \$devpanel_settings;'\'' settings.php)" && patch -Np1 -r /dev/null < $APP_ROOT/.devpanel/drupal-settings.patch || :' + 'cd web/sites/default && test -z "$(grep '\''include \$devpanel_settings;'\'' settings.php)" && patch -Np1 -r /dev/null < $DIR/drupal-settings.patch || :' # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # AI MODULES FROM GIT (Path Repositories) @@ -103,10 +109,10 @@ if [ -n "${COMPATIBLE_AI_MODULES:-}" ]; then continue fi - if [ -d "repos/$module" ]; then + if [ -d "$APP_ROOT/repos/$module" ]; then echo " - Adding path repository for: $module" composer config --no-plugins repositories."$module"-git \ - "{\"type\": \"path\", \"url\": \"repos/$module\", \"options\": {\"symlink\": true}}" + "{\"type\": \"path\", \"url\": \"$APP_ROOT/repos/$module\", \"options\": {\"symlink\": true}}" # Require from path (use *@dev to accept version from module's composer.json). composer require -n --no-update "drupal/$module:*@dev" @@ -332,7 +338,7 @@ if [ "$STARTER_TEMPLATE" = "cms" ]; then }' # Require all CMS dependencies (Webform libraries only - AI modules come from git). - composer require -n --no-update \ + composer require -n --no-update --dev \ cweagans/composer-patches:^2@beta \ drush/drush:^13.6 \ codemirror/codemirror \ diff --git a/.devpanel/create_quickstart.sh b/.devpanel/create_quickstart.sh index cf39db09..31fb9656 100755 --- a/.devpanel/create_quickstart.sh +++ b/.devpanel/create_quickstart.sh @@ -19,6 +19,20 @@ echo -e "-------------------------------" echo -e "| DevPanel Quickstart Creator |" echo -e "-------------------------------\n" +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Directory Setup (works in both DDEV and GitHub Actions environments) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Find the .devpanel directory (where this script lives) +DEVPANEL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Project root is one level up from .devpanel +PROJECT_ROOT="$(dirname "$DEVPANEL_DIR")" +# APP_ROOT is the composer root (from environment or default to PROJECT_ROOT) +APP_ROOT="${APP_ROOT:-$PROJECT_ROOT}" +# WEB_ROOT from environment (with fallback) +WEB_ROOT="${WEB_ROOT:-$APP_ROOT/web}" + +# Define drush command +DRUSH="$APP_ROOT/vendor/bin/drush" # Preparing WORK_DIR=$APP_ROOT @@ -32,8 +46,8 @@ mkdir -p $DUMPS_DIR cd $WORK_DIR echo -e "> Export database to $APP_ROOT/.devpanel/dumps" mkdir -p $APP_ROOT/.devpanel/dumps -drush cr --quiet -drush sql-dump --result-file=../.devpanel/dumps/db.sql --gzip --extra-dump=--no-tablespaces +$DRUSH cr --quiet +$DRUSH sql-dump --result-file=../.devpanel/dumps/db.sql --gzip --extra-dump=--no-tablespaces # Step 2 - Compress static files cd $WORK_DIR diff --git a/.devpanel/fallback_setup.sh b/.devpanel/fallback_setup.sh index 8b653c1f..6c4bf969 100755 --- a/.devpanel/fallback_setup.sh +++ b/.devpanel/fallback_setup.sh @@ -1,7 +1,45 @@ #!/usr/bin/env bash set -eu -o pipefail -# Set defaults for DrupalPod AI QA +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# DevPanel/GitHub Actions: Auto-detect starter template from Docker image tag +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# This ensures image tag is authoritative over env vars to prevent conflicts +# DDEV: DP_IMAGE not set, skips this section and uses defaults below +if [ -n "${DP_IMAGE:-}" ]; then + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "🐳 DevPanel Mode: Image-based configuration" + echo " Using Docker image: $DP_IMAGE" + + # Extract tag from image (after the colon) + IMAGE_TAG="${DP_IMAGE##*:}" + + # Detect starter template from tag + if [[ "$IMAGE_TAG" == *"core"* ]]; then + DETECTED_TEMPLATE="core" + elif [[ "$IMAGE_TAG" == *"cms"* ]]; then + DETECTED_TEMPLATE="cms" + elif [[ "$IMAGE_TAG" == "latest" ]]; then + DETECTED_TEMPLATE="cms" # latest = cms by convention + else + DETECTED_TEMPLATE="" # Unknown tag, use defaults below + fi + + # Make image tag authoritative + if [ -n "$DETECTED_TEMPLATE" ]; then + if [ -n "${DP_STARTER_TEMPLATE:-}" ] && [ "$DP_STARTER_TEMPLATE" != "$DETECTED_TEMPLATE" ]; then + echo " ⚠️ Conflict detected: Image='$DETECTED_TEMPLATE', Env='$DP_STARTER_TEMPLATE'" + echo " ✓ Using image value (image is authoritative)" + else + echo " ✓ Detected: $DETECTED_TEMPLATE" + fi + export DP_STARTER_TEMPLATE="$DETECTED_TEMPLATE" + fi + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo +fi + +# Set defaults for DrupalPod AI QA (DDEV and fallback for DevPanel) export DP_STARTER_TEMPLATE=${DP_STARTER_TEMPLATE:='cms'} # Set default version based on starter template diff --git a/.devpanel/init-container.sh b/.devpanel/init-container.sh index 568fefa7..26178e4b 100755 --- a/.devpanel/init-container.sh +++ b/.devpanel/init-container.sh @@ -15,11 +15,24 @@ # For GNU Affero General Public License see . # ---------------------------------------------------------------------- +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Directory Setup (works in both DDEV and GitHub Actions environments) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Find the .devpanel directory (where this script lives) +DEVPANEL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Project root is one level up from .devpanel +PROJECT_ROOT="$(dirname "$DEVPANEL_DIR")" +# APP_ROOT is the composer root (from environment or default to PROJECT_ROOT) +APP_ROOT="${APP_ROOT:-$PROJECT_ROOT}" + +# Define drush command +DRUSH="$APP_ROOT/vendor/bin/drush" + #== Import database if [[ $(mysql -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD $DB_NAME -e "show tables;") == '' ]]; then if [[ -f "$APP_ROOT/.devpanel/dumps/db.sql.gz" ]]; then echo 'Import mysql file ...' - drush sqlq --file="$APP_ROOT/.devpanel/dumps/db.sql.gz" --file-delete + $DRUSH sqlq --file="$APP_ROOT/.devpanel/dumps/db.sql.gz" --file-delete fi fi @@ -31,11 +44,7 @@ if [[ -n "$DB_SYNC_VOL" ]]; then fi fi -drush -n updb +$DRUSH -n updb echo echo 'Run cron.' -drush cron -echo -echo 'Populate caches.' -drush cache:warm -$APP_ROOT/.devpanel/warm +$DRUSH cron diff --git a/.devpanel/init.sh b/.devpanel/init.sh index dcb52b86..7fcece85 100755 --- a/.devpanel/init.sh +++ b/.devpanel/init.sh @@ -6,188 +6,114 @@ if [ -n "${DEBUG_SCRIPT:-}" ]; then fi set -eu -o pipefail -# Move into the application root and prepare logging. +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Directory Setup (works in both DDEV and GitHub Actions environments) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +DEVPANEL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$DEVPANEL_DIR")" +APP_ROOT="${APP_ROOT:-$PROJECT_ROOT}" +DIR="$DEVPANEL_DIR" + cd "$APP_ROOT" mkdir -p logs LOG_FILE="logs/init-$(date +%F-%T).log" exec > >(tee "$LOG_FILE") 2>&1 -# Configure timing format for any timed operations below. TIMEFORMAT=%lR - -# For faster performance, don't audit dependencies automatically. export COMPOSER_NO_AUDIT=1 - -# For faster performance, don't install dev dependencies. -# @todo Should we keep it like this? export COMPOSER_NO_DEV=1 -# The other bash files are in the same dir. -DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Drush path (after composer install) +DRUSH="$APP_ROOT/vendor/bin/drush" -# Always source fallback_setup to set all defaults. -# This ensures DP_INSTALL_PROFILE and other variables are initialized. +# Source fallback setup source "$DIR/fallback_setup.sh" -# Clone AI modules from git (always - base + provider + optional test module) +# Clone AI modules echo echo 'Cloning AI modules from git...' time source "$DIR/clone_ai_modules.sh" -# Install VSCode Extensions. +# Install VSCode extensions if [ -n "${DP_VSCODE_EXTENSIONS:-}" ]; then IFS=',' for value in $DP_VSCODE_EXTENSIONS; do - time code-server --install-extension $value + time code-server --install-extension "$value" done fi -#== Clean rebuild vs incremental install. -# DP_REBUILD=1: Clean rebuild - delete vendor, web, composer files (fresh start). -# DP_REBUILD=0: Incremental install - preserve existing files (useful for resuming failed installs). +# Clean rebuild vs incremental install if [ "${DP_REBUILD:-0}" = "1" ]; then echo echo 'Performing clean rebuild...' - echo 'Removing vendor, web, and composer files...' - time rm -rf vendor web/core web/modules/contrib web/themes/contrib web/profiles/contrib composer.json composer.lock + echo 'Removing docroot directory...' + time rm -rf docroot echo 'Rebuild mode enabled.' echo fi -#== Remove root-owned filesystem artifacts. -# Docker/DDEV volumes sometimes create root-owned 'lost+found' directories (filesystem recovery artifacts). -# These aren't needed for the application and can cause confusion, permission errors, or block operations. -# Requires sudo because they're owned by root. +# Remove root-owned artifacts echo -echo Remove root-owned files. +echo "Remove root-owned files." time sudo rm -rf lost+found -#== Composer install. -echo -if [ "${DP_REBUILD:-0}" = "1" ] || [ ! -f composer.json ]; then - echo 'Generate composer.json.' - time source .devpanel/composer_setup.sh - echo -elif [ -f composer.json ]; then - if composer show --locked cweagans/composer-patches ^2 &> /dev/null; then - echo 'Update patches.lock.json.' - time composer prl - echo - fi +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Composer setup +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +if [ "${DP_REBUILD:-0}" = "1" ] || [ ! -f docroot/composer.json ]; then + source "$DIR/composer_setup.sh" +else + composer show --locked cweagans/composer-patches ^2 &>/dev/null && composer prl fi +# Ensure dependencies are installed +composer -n update --no-dev --no-progress || composer dump-autoload + echo 'Running composer update...' -# Note: May show patch warnings, but packages are still installed successfully time composer -n update --no-dev --no-progress || { echo "Composer update encountered errors (likely patch failures), but continuing..." echo "Regenerating autoload files..." composer dump-autoload } -# Validate module compatibility. If users try to get versions -# that conflict, we need to warn them. -echo -echo 'Validating AI module compatibility...' -if composer validate --no-check-all --no-check-publish 2>&1 | grep -q "is valid"; then - echo "✓ Composer validation passed" -else - echo "⚠️ Composer validation found warnings (this may be OK)" -fi - -# Check if AI modules are properly symlinked. -if [ -L web/modules/contrib/ai ] && [ -L web/modules/contrib/ai_provider_litellm ]; then - echo "✓ AI modules symlinked from git:" - echo " - $(readlink web/modules/contrib/ai)" - echo " - $(readlink web/modules/contrib/ai_provider_litellm)" -else - echo "⚠️ AI modules not symlinked - may be using Composer versions" -fi - -echo 'Composer dependencies installed.' +echo 'All modules installed and ready!' -#== Create the private files directory. -if [ ! -d private ]; then - echo - echo 'Create the private files directory.' - time mkdir private -fi +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Private files & config +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +[ ! -d private ] && { echo; echo 'Create the private files directory.'; time mkdir private; } +[ ! -d config/sync ] && { echo; echo 'Create the config sync directory.'; time mkdir -p config/sync; } -#== Create the config sync directory. -if [ ! -d config/sync ]; then - echo - echo 'Create the config sync directory.' - time mkdir -p config/sync -fi +# Generate hash salt if missing +[ ! -f "$DIR/salt.txt" ] && { echo; echo 'Generate hash salt.'; time openssl rand -hex 32 > "$DIR/salt.txt"; } -#== Generate hash salt. -if [ ! -f .devpanel/salt.txt ]; then - echo - echo 'Generate hash salt.' - time openssl rand -hex 32 > .devpanel/salt.txt -fi - -#== Install Drupal. +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Install Drupal +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ echo -if [ "${DP_REBUILD:-0}" = "1" ] || ! drush status --field=bootstrap | grep -q "Drupal bootstrap"; then - if [ -z "$DP_INSTALL_PROFILE" ]; then - echo 'Install Drupal.' - time drush -n si --account-name=admin --account-pass=admin - else - echo 'Install Drupal with profile: '"$DP_INSTALL_PROFILE" - time drush -n si "$DP_INSTALL_PROFILE" --account-name=admin --account-pass=admin - fi +if [ "${DP_REBUILD:-0}" = "1" ] || ! $DRUSH status --field=bootstrap | grep -q "Drupal bootstrap"; then + PROFILE="${DP_INSTALL_PROFILE:-standard}" + echo "Installing Drupal with profile: $PROFILE" + time $DRUSH -n si "$PROFILE" --account-name=admin --account-pass=admin - #== Apply the AI recipe. + # AI setup if available if [ -n "${DP_AI_VIRTUAL_KEY:-}" ]; then - echo - time drush -n en ai_provider_litellm - drush -n key-save litellm_api_key --label="LiteLLM API key" --key-provider=env --key-provider-settings='{ - "env_variable": "DP_AI_VIRTUAL_KEY", - "base64_encoded": false, - "strip_line_breaks": true - }' - drush -n cset ai_provider_litellm.settings api_key litellm_api_key - drush -n cset ai_provider_litellm.settings moderation false --input-format yaml - drush -n cset ai_provider_litellm.settings host "${DP_AI_HOST:="https://ai.drupalforge.org"}" - drush -q recipe ../recipes/drupal_cms_ai --input=drupal_cms_ai.provider=litellm - drush -n cset ai.settings default_providers.chat.provider_id litellm - drush -n cset ai.settings default_providers.chat.model_id openai/gpt-4o-mini - drush -n cset ai.settings default_providers.chat_with_complex_json.provider_id litellm - drush -n cset ai.settings default_providers.chat_with_complex_json.model_id openai/gpt-4o-mini - drush -n cset ai.settings default_providers.chat_with_image_vision.provider_id litellm - drush -n cset ai.settings default_providers.chat_with_image_vision.model_id openai/gpt-4o-mini - drush -n cset ai.settings default_providers.chat_with_structured_response.provider_id litellm - drush -n cset ai.settings default_providers.chat_with_structured_response.model_id openai/gpt-4o-mini - drush -n cset ai.settings default_providers.chat_with_tools.provider_id litellm - drush -n cset ai.settings default_providers.chat_with_tools.model_id openai/gpt-4o-mini - drush -n cset ai.settings default_providers.embeddings.provider_id litellm - drush -n cset ai.settings default_providers.embeddings.model_id openai/text-embedding-3-small - drush -n cset ai.settings default_providers.text_to_speech.provider_id litellm - drush -n cset ai.settings default_providers.text_to_speech.model_id openai/gpt-4o-mini-realtime-preview - drush -n cset ai_assistant_api.ai_assistant.drupal_cms_assistant llm_provider __default__ - drush -n cset klaro.klaro_app.deepchat status 0 + source "$DIR/setup_ai.sh" fi echo echo 'Tell Automatic Updates about patches.' - drush -n cset --input-format=yaml package_manager.settings additional_trusted_composer_plugins '["cweagans/composer-patches"]' - drush -n cset --input-format=yaml package_manager.settings additional_known_files_in_project_root '["patches.json", "patches.lock.json"]' - time drush ev '\Drupal::moduleHandler()->invoke("automatic_updates", "modules_installed", [[], FALSE])' + $DRUSH -n cset --input-format=yaml package_manager.settings additional_trusted_composer_plugins '["cweagans/composer-patches"]' + $DRUSH -n cset --input-format=yaml package_manager.settings additional_known_files_in_project_root '["patches.json", "patches.lock.json"]' + time $DRUSH ev '\Drupal::moduleHandler()->invoke("automatic_updates", "modules_installed", [[], FALSE])' else echo 'Update database.' - time drush -n updb + time $DRUSH -n updb fi -#== Warm up caches. -echo -echo 'Run cron.' -time drush cron -echo -echo 'Populate caches.' -time drush cache:warm -time .devpanel/warm - -#== Finish measuring script time. +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Finish measuring script time +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ INIT_DURATION=$SECONDS INIT_HOURS=$(($INIT_DURATION / 3600)) INIT_MINUTES=$(($INIT_DURATION % 3600 / 60)) diff --git a/.devpanel/logs/init-2025-12-04-21:55:09.log b/.devpanel/logs/init-2025-12-04-21:55:09.log new file mode 100644 index 00000000..9953a774 --- /dev/null +++ b/.devpanel/logs/init-2025-12-04-21:55:09.log @@ -0,0 +1,631 @@ +📦 AI version will be auto-detected from test module dependencies +📦 AI Module Configuration: + - AI Base: ai @ + - Dependencies: Auto-resolved from composer.json + +Cloning AI modules from git... + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Step 1: No Test Module +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + → Will use latest stable release tag + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Step 2: Clone AI Base Module @ latest stable +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Cloning: ai +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✓ Submodule exists, updating... +Submodule path 'repos/ai': checked out '6c704d8f04e7cb222164897f786fa87bee0f7c95' +0m0.054s + → No version specified, checking out latest stable release + → Found latest stable: 1.2.4 +Previous HEAD position was 6c704d8f Issues/3540486: Translate CKEditor plugin ignores language_source = lang +HEAD is now at b1194e65 Chatbot + → Detected AI version from tag: 1.2.x (from 1.2.4) + ✓ Using detected version for compatibility filtering: 1.2.x + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Step 3: Clone Additional AI Modules (compatibility filtering) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + → Cloning ai_provider_litellm... +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Cloning: ai_provider_litellm +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✓ Submodule exists, updating... +Submodule path 'repos/ai_provider_litellm': checked out '7523d5cac87cd831a480b411bc0eb7aca03f82f1' +0m0.032s + → No version specified, checking out latest stable release + → Found latest stable: 1.2.0-rc1 +Previous HEAD position was 7523d5c 3558458: add extra check on handleApiException +HEAD is now at 2abcc2e Resolve #3550655 "Override handleapiexception to" + ✓ ai_provider_litellm is compatible with AI 1.2.x + → Cloning ai_search... +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Cloning: ai_search +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✓ Submodule exists, updating... +0m0.021s + → No version specified, checking out latest stable release + → Found latest stable: 2.0.0-alpha1 +HEAD is now at 43a6627 fix: #3557904 Vector DB Explorer fails with TypeError when search results contain array values in extra data + ⚠️ Incompatible: requires AI ^2.0, but we have AI 1.2.x + ✗ Skipping ai_search from composer (incompatible, but cloned for inspection) + → Cloning ai_agents... +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Cloning: ai_agents +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✓ Submodule exists, updating... +Submodule path 'repos/ai_agents': checked out '9502f73f218999de66050463f1182fa51c6c0714' +0m0.030s + → No version specified, checking out latest stable release + → Found latest stable: 1.2.1 +Previous HEAD position was 9502f73 Cherry pick code from #3536318 +HEAD is now at 2fe31d6 Cherry pick code from #3536318 + ✓ ai_agents is compatible with AI 1.2.x + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Step 4: Clone Default Provider +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✓ Provider already cloned + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +✓ Summary +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + AI Version: 1.2.x + Cloned modules: ai,ai_provider_litellm,ai_search,ai_agents + Compatible (will be added to composer): ai,ai_provider_litellm,ai_agents +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +0m6.817s + +Performing clean rebuild... +Removing docroot directory... +0m0.993s +Rebuild mode enabled. + + +Remove root-owned files. +0m0.007s + +Generate composer.json. +Creating a "drupal/cms:2.0.x-dev" project at "./temp-composer-files" +Installing drupal/cms (2.0.x-dev 58e1bbb0d3740edf197985aaae25c6569714fa87) + - Installing drupal/cms (2.0.x-dev 58e1bbb): Extracting archive +Created project in /var/www/html/docroot/docroot/temp-composer-files +0m0.453s +Adding path repositories for compatible AI modules... +Path repositories added for compatible AI modules! +Adding CMS dependencies (full setup with webform libraries)... +Using version ^5.65 for codemirror/codemirror +Using version ^5.0 for jquery/inputmask +Using version ^17.0 for jquery/intl-tel-input +Using version ^1.1 for jquery/rateit +Using version ^4.0 for jquery/select2 +Using version ^0.9.1 for jquery/textcounter +Using version ^1.14 for jquery/timepicker +Using version ^2.11 for popperjs/popperjs +Using version ^2.0 for progress-tracker/progress-tracker +Using version ^2.3 for signature_pad/signature_pad +Using version ^12.0 for tabby/tabby +Using version ^6.3 for tippyjs/tippyjs +drush/drush is currently present in the require-dev key and you ran the command without the --dev flag, which will move it to the require key. +./composer.json has been updated +0m4.359s + +Running composer update... +Loading composer repositories with package information +Updating dependencies +Lock file operations: 225 installs, 0 updates, 0 removals + - Locking asm89/stack-cors (v2.3.0) + - Locking chi-teck/drupal-code-generator (4.2.0) + - Locking codemirror/codemirror (5.65.12) + - Locking composer/ca-bundle (1.5.9) + - Locking composer/class-map-generator (1.7.0) + - Locking composer/composer (2.9.2) + - Locking composer/installers (v2.3.0) + - Locking composer/metadata-minifier (1.0.0) + - Locking composer/pcre (3.3.2) + - Locking composer/semver (3.4.4) + - Locking composer/spdx-licenses (1.5.9) + - Locking composer/xdebug-handler (3.0.5) + - Locking consolidation/annotated-command (4.10.4) + - Locking consolidation/config (3.2.0) + - Locking consolidation/filter-via-dot-access-data (2.0.3) + - Locking consolidation/log (3.1.1) + - Locking consolidation/output-formatters (4.7.0) + - Locking consolidation/robo (5.1.1) + - Locking consolidation/site-alias (4.1.2) + - Locking consolidation/site-process (5.4.2) + - Locking cweagans/composer-configurable-plugin (2.0.0) + - Locking cweagans/composer-patches (2.0.0) + - Locking dflydev/dot-access-data (v3.0.3) + - Locking doctrine/annotations (2.0.2) + - Locking doctrine/deprecations (1.1.5) + - Locking doctrine/lexer (2.1.1) + - Locking dragonmantank/cron-expression (v3.6.0) + - Locking drupal/ai (1.2.4) + - Locking drupal/ai_agents (1.2.1) + - Locking drupal/ai_image_alt_text (1.0.1) + - Locking drupal/ai_provider_anthropic (1.2.0) + - Locking drupal/ai_provider_openai (1.2.0) + - Locking drupal/automatic_updates (4.0.0) + - Locking drupal/autosave_form (1.10.0) + - Locking drupal/better_exposed_filters (7.1.1) + - Locking drupal/bpmn_io (3.0.2) + - Locking drupal/byte (1.0.0-alpha5) + - Locking drupal/canvas (1.0.0) + - Locking drupal/captcha (2.0.9) + - Locking drupal/checklistapi (2.1.7) + - Locking drupal/coffee (2.0.1) + - Locking drupal/core (11.2.9) + - Locking drupal/core-composer-scaffold (11.2.9) + - Locking drupal/core-project-message (11.2.9) + - Locking drupal/core-recipe-unpack (11.2.9) + - Locking drupal/core-recommended (11.2.9) + - Locking drupal/core-vendor-hardening (11.2.9) + - Locking drupal/crop (2.5.0) + - Locking drupal/ctools (4.1.0) + - Locking drupal/cva (1.0.0-beta1) + - Locking drupal/dashboard (2.1.1) + - Locking drupal/drupal_cms_accessibility_tools (2.0.0-alpha2) + - Locking drupal/drupal_cms_admin_ui (2.0.0-alpha2) + - Locking drupal/drupal_cms_ai (2.0.0-alpha2) + - Locking drupal/drupal_cms_anti_spam (2.0.0-alpha2) + - Locking drupal/drupal_cms_authentication (2.0.0-alpha2) + - Locking drupal/drupal_cms_blog (2.0.0-alpha2) + - Locking drupal/drupal_cms_content_type_base (2.0.0-alpha2) + - Locking drupal/drupal_cms_forms (2.0.0-alpha2) + - Locking drupal/drupal_cms_google_analytics (2.0.0-alpha2) + - Locking drupal/drupal_cms_helper (2.0.0-alpha2) + - Locking drupal/drupal_cms_image (2.0.0-alpha2) + - Locking drupal/drupal_cms_page (2.0.0-alpha2) + - Locking drupal/drupal_cms_privacy_basic (2.0.0-alpha2) + - Locking drupal/drupal_cms_remote_video (2.0.0-alpha2) + - Locking drupal/drupal_cms_search (2.0.0-alpha2) + - Locking drupal/drupal_cms_seo_basic (2.0.0-alpha2) + - Locking drupal/drupal_cms_seo_tools (2.0.0-alpha2) + - Locking drupal/drupal_cms_starter (2.0.0-alpha2) + - Locking drupal/easy_breadcrumb (2.0.9) + - Locking drupal/easy_email (3.0.7) + - Locking drupal/easy_email_express (1.0.4) + - Locking drupal/easy_email_standard (1.0.3) + - Locking drupal/easy_email_text_format (1.0.3) + - Locking drupal/easy_email_theme (1.1.0) + - Locking drupal/easy_email_types_core (1.0.4) + - Locking drupal/easy_email_types_default (1.0.2) + - Locking drupal/eca (3.0.8) + - Locking drupal/editoria11y (2.2.18) + - Locking drupal/field_group (4.0.0) + - Locking drupal/focal_point (2.1.2) + - Locking drupal/friendly_captcha_challenge (0.9.18) + - Locking drupal/friendlycaptcha (1.1.4) + - Locking drupal/gin (5.0.9) + - Locking drupal/gin_login (2.1.3) + - Locking drupal/gin_toolbar (3.0.2) + - Locking drupal/google_tag (2.0.9) + - Locking drupal/honeypot (2.2.2) + - Locking drupal/jquery_ui (1.8.0) + - Locking drupal/jquery_ui_resizable (2.1.0) + - Locking drupal/key (1.20.0) + - Locking drupal/klaro (3.0.7) + - Locking drupal/klaro_js (3.0.1) + - Locking drupal/linkit (7.0.11) + - Locking drupal/login_emailusername (3.0.1) + - Locking drupal/mailsystem (4.5.0) + - Locking drupal/menu_link_attributes (1.5.0) + - Locking drupal/mercury (1.0.0-alpha2) + - Locking drupal/metatag (2.2.0) + - Locking drupal/modeler_api (1.0.6) + - Locking drupal/nouislider_js (15.8.1) + - Locking drupal/pathauto (1.14.0) + - Locking drupal/project_browser (2.1.2) + - Locking drupal/recipe_installer_kit (1.0.0) + - Locking drupal/redirect (1.12.0) + - Locking drupal/robotstxt (1.6.0) + - Locking drupal/sam (1.3.2) + - Locking drupal/scheduler (2.2.2) + - Locking drupal/scheduler_content_moderation_integration (3.0.4) + - Locking drupal/search_api (1.40.0) + - Locking drupal/search_api_autocomplete (1.11.0) + - Locking drupal/search_api_exclude (2.0.3) + - Locking drupal/selective_better_exposed_filters (3.0.3) + - Locking drupal/seo_checklist (5.2.4) + - Locking drupal/simple_search_form (1.8.0) + - Locking drupal/simple_sitemap (4.2.3) + - Locking drupal/sitemap (2.5.0) + - Locking drupal/svg_image (3.2.2) + - Locking drupal/symfony_mailer_lite (2.0.4) + - Locking drupal/tagify (1.2.44) + - Locking drupal/token (1.16.0) + - Locking drupal/token_or (2.3.2) + - Locking drupal/trash (3.0.22) + - Locking drupal/ui_icons (1.1.0-beta6) + - Locking drupal/webform (6.3.0-beta6) + - Locking drupal/yoast_seo (2.2.0) + - Locking drush/drush (13.7.0) + - Locking egulias/email-validator (4.0.4) + - Locking enshrined/svg-sanitize (0.22.0) + - Locking goalgorilla/rtseo.js (2.1.0) + - Locking grasmash/expander (3.0.1) + - Locking grasmash/yaml-cli (3.2.1) + - Locking guzzlehttp/guzzle (7.9.3) + - Locking guzzlehttp/promises (2.2.0) + - Locking guzzlehttp/psr7 (2.7.1) + - Locking html2text/html2text (4.3.2) + - Locking jquery/inputmask (5.0.9) + - Locking jquery/intl-tel-input (17.0.19) + - Locking jquery/rateit (1.1.5) + - Locking jquery/select2 (4.0.13) + - Locking jquery/textcounter (0.9.1) + - Locking jquery/timepicker (1.14.0) + - Locking justinrainbow/json-schema (6.6.3) + - Locking laravel/prompts (v0.3.8) + - Locking league/commonmark (2.8.0) + - Locking league/config (v1.2.0) + - Locking league/container (4.2.5) + - Locking league/html-to-markdown (5.1.1) + - Locking marc-mabe/php-enum (v4.7.2) + - Locking masterminds/html5 (2.9.0) + - Locking mck89/peast (v1.17.4) + - Locking mtownsend/xml-to-array (2.0.0) + - Locking nette/schema (v1.3.3) + - Locking nette/utils (v4.1.0) + - Locking nikic/php-parser (v5.6.2) + - Locking openai-php/client (v0.18.0) + - Locking pear/archive_tar (1.5.0) + - Locking pear/console_getopt (v1.4.3) + - Locking pear/pear-core-minimal (v1.10.16) + - Locking pear/pear_exception (v1.0.2) + - Locking phootwork/collection (v3.2.3) + - Locking phootwork/lang (v3.2.3) + - Locking php-http/discovery (1.20.0) + - Locking php-http/multipart-stream-builder (1.4.2) + - Locking php-tuf/composer-stager (v2.0.2) + - Locking phpowermove/docblock (v4.0) + - Locking popperjs/popperjs (2.11.6) + - Locking progress-tracker/progress-tracker (2.0.7) + - Locking psr/cache (3.0.0) + - Locking psr/container (2.0.2) + - Locking psr/event-dispatcher (1.0.0) + - Locking psr/http-client (1.0.3) + - Locking psr/http-factory (1.1.0) + - Locking psr/http-message (2.0) + - Locking psr/log (3.0.2) + - Locking psy/psysh (v0.12.15) + - Locking ralouphie/getallheaders (3.0.3) + - Locking react/promise (v3.3.0) + - Locking revolt/event-loop (v1.0.8) + - Locking sebastian/diff (7.0.0) + - Locking seld/jsonlint (1.11.0) + - Locking seld/phar-utils (1.2.1) + - Locking seld/signal-handler (2.0.2) + - Locking signature_pad/signature_pad (2.3.0) + - Locking symfony/console (v7.3.6) + - Locking symfony/css-selector (v7.4.0) + - Locking symfony/dependency-injection (v7.3.6) + - Locking symfony/deprecation-contracts (v3.6.0) + - Locking symfony/error-handler (v7.3.6) + - Locking symfony/event-dispatcher (v7.3.3) + - Locking symfony/event-dispatcher-contracts (v3.6.0) + - Locking symfony/filesystem (v7.3.6) + - Locking symfony/finder (v7.3.5) + - Locking symfony/http-foundation (v7.3.7) + - Locking symfony/http-kernel (v7.3.7) + - Locking symfony/mailer (v7.3.5) + - Locking symfony/mime (v7.3.4) + - Locking symfony/polyfill-ctype (v1.32.0) + - Locking symfony/polyfill-iconv (v1.32.0) + - Locking symfony/polyfill-intl-grapheme (v1.32.0) + - Locking symfony/polyfill-intl-idn (v1.32.0) + - Locking symfony/polyfill-intl-normalizer (v1.32.0) + - Locking symfony/polyfill-mbstring (v1.32.0) + - Locking symfony/polyfill-php73 (v1.33.0) + - Locking symfony/polyfill-php80 (v1.33.0) + - Locking symfony/polyfill-php81 (v1.33.0) + - Locking symfony/polyfill-php83 (v1.33.0) + - Locking symfony/polyfill-php84 (v1.32.0) + - Locking symfony/process (v7.3.4) + - Locking symfony/psr-http-message-bridge (v7.3.0) + - Locking symfony/routing (v7.3.6) + - Locking symfony/serializer (v7.3.5) + - Locking symfony/service-contracts (v3.6.1) + - Locking symfony/string (v7.3.4) + - Locking symfony/translation-contracts (v3.6.1) + - Locking symfony/validator (v7.3.7) + - Locking symfony/var-dumper (v7.3.5) + - Locking symfony/var-exporter (v7.3.4) + - Locking symfony/yaml (v7.3.5) + - Locking tabby/tabby (12.0.3) + - Locking tijsverkoyen/css-to-inline-styles (v2.3.0) + - Locking tippyjs/tippyjs (6.3.7) + - Locking twig/html-extra (v3.22.1) + - Locking twig/twig (v3.21.1) + - Locking yethee/tiktoken (0.5.1) +Writing lock file +Installing dependencies from lock file +Package operations: 225 installs, 0 updates, 0 removals + - Installing cweagans/composer-configurable-plugin (2.0.0): Extracting archive + - Installing cweagans/composer-patches (2.0.0): Extracting archive +patches.lock.json does not exist. Creating a new patches.lock.json. + - Resolving patches from dependencies. + - Installing composer/installers (v2.3.0): Extracting archive + - Installing drupal/core-composer-scaffold (11.2.9): Extracting archive + - Installing drupal/core-project-message (11.2.9): Extracting archive + - Installing drupal/core-recipe-unpack (11.2.9): Extracting archive + - Installing drupal/core-vendor-hardening (11.2.9): Extracting archive + - Installing php-http/discovery (1.20.0): Extracting archive + - Installing codemirror/codemirror (5.65.12): Extracting archive + - Installing symfony/process (v7.3.4): Extracting archive + - Installing symfony/polyfill-php84 (v1.32.0): Extracting archive + - Installing symfony/polyfill-php81 (v1.33.0): Extracting archive + - Installing symfony/polyfill-php80 (v1.33.0): Extracting archive + - Installing symfony/polyfill-php73 (v1.33.0): Extracting archive + - Installing symfony/finder (v7.3.5): Extracting archive + - Installing symfony/polyfill-iconv (v1.32.0): Extracting archive + - Installing symfony/polyfill-mbstring (v1.32.0): Extracting archive + - Installing symfony/polyfill-ctype (v1.32.0): Extracting archive + - Installing symfony/filesystem (v7.3.6): Extracting archive + - Installing symfony/polyfill-intl-normalizer (v1.32.0): Extracting archive + - Installing symfony/polyfill-intl-grapheme (v1.32.0): Extracting archive + - Installing symfony/string (v7.3.4): Extracting archive + - Installing symfony/deprecation-contracts (v3.6.0): Extracting archive + - Installing psr/container (2.0.2): Extracting archive + - Installing symfony/service-contracts (v3.6.1): Extracting archive + - Installing symfony/console (v7.3.6): Extracting archive + - Installing seld/signal-handler (2.0.2): Extracting archive + - Installing seld/phar-utils (1.2.1): Extracting archive + - Installing seld/jsonlint (1.11.0): Extracting archive + - Installing react/promise (v3.3.0): Extracting archive + - Installing psr/log (3.0.2): Extracting archive + - Installing marc-mabe/php-enum (v4.7.2): Extracting archive + - Installing justinrainbow/json-schema (6.6.3): Extracting archive + - Installing composer/pcre (3.3.2): Extracting archive + - Installing composer/xdebug-handler (3.0.5): Extracting archive + - Installing composer/spdx-licenses (1.5.9): Extracting archive + - Installing composer/semver (3.4.4): Extracting archive + - Installing composer/metadata-minifier (1.0.0): Extracting archive + - Installing composer/class-map-generator (1.7.0): Extracting archive + - Installing composer/ca-bundle (1.5.9): Extracting archive + - Installing composer/composer (2.9.2): Extracting archive + - Installing consolidation/log (3.1.1): Extracting archive + - Installing twig/twig (v3.21.1): Extracting archive + - Installing symfony/yaml (v7.3.5): Extracting archive + - Installing symfony/translation-contracts (v3.6.1): Extracting archive + - Installing symfony/polyfill-php83 (v1.33.0): Extracting archive + - Installing symfony/validator (v7.3.7): Extracting archive + - Installing symfony/serializer (v7.3.5): Extracting archive + - Installing symfony/routing (v7.3.6): Extracting archive + - Installing symfony/http-foundation (v7.3.7): Extracting archive + - Installing psr/http-message (2.0): Extracting archive + - Installing symfony/psr-http-message-bridge (v7.3.0): Extracting archive + - Installing symfony/polyfill-intl-idn (v1.32.0): Extracting archive + - Installing symfony/mime (v7.3.4): Extracting archive + - Installing psr/event-dispatcher (1.0.0): Extracting archive + - Installing symfony/event-dispatcher-contracts (v3.6.0): Extracting archive + - Installing symfony/event-dispatcher (v7.3.3): Extracting archive + - Installing doctrine/deprecations (1.1.5): Extracting archive + - Installing doctrine/lexer (2.1.1): Extracting archive + - Installing egulias/email-validator (4.0.4): Extracting archive + - Installing symfony/mailer (v7.3.5): Extracting archive + - Installing symfony/var-dumper (v7.3.5): Extracting archive + - Installing symfony/error-handler (v7.3.6): Extracting archive + - Installing symfony/http-kernel (v7.3.7): Extracting archive + - Installing symfony/var-exporter (v7.3.4): Extracting archive + - Installing symfony/dependency-injection (v7.3.6): Extracting archive + - Installing sebastian/diff (7.0.0): Extracting archive + - Installing revolt/event-loop (v1.0.8): Extracting archive + - Installing php-tuf/composer-stager (v2.0.2): Extracting archive + - Installing pear/pear_exception (v1.0.2): Extracting archive + - Installing pear/console_getopt (v1.4.3): Extracting archive + - Installing pear/pear-core-minimal (v1.10.16): Extracting archive + - Installing pear/archive_tar (1.5.0): Extracting archive + - Installing mck89/peast (v1.17.4): Extracting archive + - Installing masterminds/html5 (2.9.0): Extracting archive + - Installing ralouphie/getallheaders (3.0.3): Extracting archive + - Installing psr/http-factory (1.1.0): Extracting archive + - Installing guzzlehttp/psr7 (2.7.1): Extracting archive + - Installing psr/http-client (1.0.3): Extracting archive + - Installing guzzlehttp/promises (2.2.0): Extracting archive + - Installing guzzlehttp/guzzle (7.9.3): Extracting archive + - Installing psr/cache (3.0.0): Extracting archive + - Installing doctrine/annotations (2.0.2): Extracting archive + - Installing asm89/stack-cors (v2.3.0): Extracting archive + - Installing drupal/core (11.2.9): Extracting archive + - Installing drupal/ui_icons (1.1.0-beta6): Extracting archive + - Installing drupal/mercury (1.0.0-alpha2): Extracting archive + - Installing drupal/easy_email_text_format (1.0.3): Extracting archive + - Installing drupal/token (1.16.0): Extracting archive + - Installing drupal/jquery_ui (1.8.0): Extracting archive + - Installing drupal/jquery_ui_resizable (2.1.0): Extracting archive + - Installing drupal/easy_email (3.0.7): Extracting archive + - Installing drupal/easy_email_types_default (1.0.2): Extracting archive + - Installing drupal/easy_email_types_core (1.0.4): Extracting archive + - Installing symfony/css-selector (v7.4.0): Extracting archive + - Installing tijsverkoyen/css-to-inline-styles (v2.3.0): Extracting archive + - Installing html2text/html2text (4.3.2): Extracting archive + - Installing drupal/mailsystem (4.5.0): Extracting archive + - Installing drupal/symfony_mailer_lite (2.0.4): Extracting archive + - Installing drupal/easy_email_theme (1.1.0): Extracting archive + - Installing drupal/easy_email_standard (1.0.3): Extracting archive + - Installing drupal/easy_email_express (1.0.4): Extracting archive + - Installing goalgorilla/rtseo.js (2.1.0): Extracting archive + - Installing drupal/metatag (2.2.0): Extracting archive + - Installing drupal/yoast_seo (2.2.0): Extracting archive + - Installing drupal/token_or (2.3.2): Extracting archive + - Installing drupal/sitemap (2.5.0): Extracting archive + - Installing drupal/simple_sitemap (4.2.3): Extracting archive + - Installing drupal/checklistapi (2.1.7): Extracting archive + - Installing drupal/seo_checklist (5.2.4): Extracting archive + - Installing drupal/robotstxt (1.6.0): Extracting archive + - Installing drupal/modeler_api (1.0.6): Extracting archive + - Installing drupal/crop (2.5.0): Extracting archive + - Installing drupal/focal_point (2.1.2): Extracting archive + - Installing drupal/field_group (4.0.0): Extracting archive + - Installing dragonmantank/cron-expression (v3.6.0): Extracting archive + - Installing drupal/eca (3.0.8): Extracting archive + - Installing mtownsend/xml-to-array (2.0.0): Extracting archive + - Installing drupal/bpmn_io (3.0.2): Extracting archive + - Installing drupal/drupal_cms_seo_tools (2.0.0-alpha2): Extracting archive + - Installing drupal/menu_link_attributes (1.5.0): Extracting archive + - Installing drupal/klaro_js (3.0.1): Extracting archive + - Installing drupal/klaro (3.0.7): Extracting archive + - Installing drupal/trash (3.0.22): Extracting archive + - Installing drupal/tagify (1.2.44): Extracting archive + - Installing drupal/scheduler (2.2.2): Extracting archive + - Installing drupal/scheduler_content_moderation_integration (3.0.4): Extracting archive + - Installing drupal/ctools (4.1.0): Extracting archive + - Installing drupal/pathauto (1.14.0): Extracting archive + - Installing drupal/linkit (7.0.11): Extracting archive + - Installing enshrined/svg-sanitize (0.22.0): Extracting archive + - Installing drupal/svg_image (3.2.2): Extracting archive + - Installing drupal/drupal_cms_image (2.0.0-alpha2): Extracting archive + - Installing drupal/drupal_cms_helper (2.0.0-alpha2): Extracting archive + - Installing drupal/canvas (1.0.0): Extracting archive + - Installing drupal/autosave_form (1.10.0): Extracting archive + - Installing drupal/drupal_cms_content_type_base (2.0.0-alpha2): Extracting archive + - Installing drupal/drupal_cms_page (2.0.0-alpha2): Extracting archive + - Installing drupal/drupal_cms_privacy_basic (2.0.0-alpha2): Extracting archive + - Installing drupal/drupal_cms_remote_video (2.0.0-alpha2): Extracting archive + - Installing drupal/webform (6.3.0-beta6): Extracting archive + - Installing drupal/honeypot (2.2.2): Extracting archive + - Installing drupal/captcha (2.0.9): Extracting archive + - Installing drupal/friendlycaptcha (1.1.4): Extracting archive + - Installing drupal/friendly_captcha_challenge (0.9.18): Extracting archive + - Installing drupal/drupal_cms_anti_spam (2.0.0-alpha2): Extracting archive + - Installing drupal/drupal_cms_forms (2.0.0-alpha2): Extracting archive + - Installing drupal/nouislider_js (15.8.1): Extracting archive + - Installing drupal/better_exposed_filters (7.1.1): Extracting archive + - Installing drupal/selective_better_exposed_filters (3.0.3): Extracting archive + - Installing drupal/drupal_cms_blog (2.0.0-alpha2): Extracting archive + - Installing drupal/login_emailusername (3.0.1): Extracting archive + - Installing drupal/drupal_cms_authentication (2.0.0-alpha2): Extracting archive + - Installing drupal/sam (1.3.2): Extracting archive + - Installing drupal/project_browser (2.1.2): Extracting archive + - Installing drupal/gin_login (2.1.3): Extracting archive + - Installing drupal/gin_toolbar (3.0.2): Extracting archive + - Installing drupal/gin (5.0.9): Extracting archive + - Installing drupal/dashboard (2.1.1): Extracting archive + - Installing drupal/coffee (2.0.1): Extracting archive + - Installing drupal/drupal_cms_admin_ui (2.0.0-alpha2): Extracting archive + - Installing drupal/byte (1.0.0-alpha5): Extracting archive + - Installing drupal/core-recommended (11.2.9) + - Installing twig/html-extra (v3.22.1): Extracting archive + - Installing drupal/cva (1.0.0-beta1): Extracting archive + - Installing drupal/editoria11y (2.2.18): Extracting archive + - Installing drupal/drupal_cms_accessibility_tools (2.0.0-alpha2): Extracting archive + - Installing nette/utils (v4.1.0): Extracting archive + - Installing nette/schema (v1.3.3): Extracting archive + - Installing dflydev/dot-access-data (v3.0.3): Extracting archive + - Installing league/config (v1.2.0): Extracting archive + - Installing league/commonmark (2.8.0): Extracting archive + - Installing drupal/key (1.20.0): Extracting archive + - Installing yethee/tiktoken (0.5.1): Extracting archive + - Installing php-http/multipart-stream-builder (1.4.2): Extracting archive + - Installing openai-php/client (v0.18.0): Extracting archive + - Installing league/html-to-markdown (5.1.1): Extracting archive + - Installing drupal/ai (1.2.4): Extracting archive + - Installing drupal/ai_provider_openai (1.2.0): Extracting archive + - Installing drupal/ai_provider_anthropic (1.2.0): Extracting archive + - Installing drupal/ai_image_alt_text (1.0.1): Extracting archive + - Installing drupal/ai_agents (1.2.1): Extracting archive + - Installing drupal/drupal_cms_ai (2.0.0-alpha2): Extracting archive + - Installing drupal/google_tag (2.0.9): Extracting archive + - Installing drupal/drupal_cms_google_analytics (2.0.0-alpha2): Extracting archive + - Installing drupal/redirect (1.12.0): Extracting archive + - Installing drupal/easy_breadcrumb (2.0.9): Extracting archive + - Installing drupal/drupal_cms_seo_basic (2.0.0-alpha2): Extracting archive + - Installing drupal/simple_search_form (1.8.0): Extracting archive + - Installing drupal/search_api (1.40.0): Extracting archive + - Installing drupal/search_api_exclude (2.0.3): Extracting archive + - Installing drupal/search_api_autocomplete (1.11.0): Extracting archive + - Installing drupal/drupal_cms_search (2.0.0-alpha2): Extracting archive + - Installing drupal/automatic_updates (4.0.0): Extracting archive + - Installing drupal/drupal_cms_starter (2.0.0-alpha2): Extracting archive + - Installing nikic/php-parser (v5.6.2): Extracting archive + - Installing psy/psysh (v0.12.15): Extracting archive + - Installing league/container (4.2.5): Extracting archive + - Installing laravel/prompts (v0.3.8): Extracting archive + - Installing grasmash/yaml-cli (3.2.1): Extracting archive + - Installing grasmash/expander (3.0.1): Extracting archive + - Installing consolidation/config (3.2.0): Extracting archive + - Installing consolidation/site-alias (4.1.2): Extracting archive + - Installing consolidation/site-process (5.4.2): Extracting archive + - Installing phootwork/lang (v3.2.3): Extracting archive + - Installing phootwork/collection (v3.2.3): Extracting archive + - Installing phpowermove/docblock (v4.0): Extracting archive + - Installing consolidation/output-formatters (4.7.0): Extracting archive + - Installing consolidation/annotated-command (4.10.4): Extracting archive + - Installing consolidation/robo (5.1.1): Extracting archive + - Installing consolidation/filter-via-dot-access-data (2.0.3): Extracting archive + - Installing chi-teck/drupal-code-generator (4.2.0): Extracting archive + - Installing drush/drush (13.7.0): Extracting archive + - Installing drupal/recipe_installer_kit (1.0.0): Extracting archive + - Installing jquery/inputmask (5.0.9): Extracting archive + - Installing jquery/intl-tel-input (17.0.19): Extracting archive + - Installing jquery/rateit (1.1.5): Extracting archive + - Installing jquery/select2 (4.0.13): Extracting archive + - Installing jquery/textcounter (0.9.1): Extracting archive + - Installing jquery/timepicker (1.14.0): Extracting archive + - Installing popperjs/popperjs (2.11.6): Extracting archive + - Installing progress-tracker/progress-tracker (2.0.7): Extracting archive + - Installing signature_pad/signature_pad (2.3.0): Extracting archive + - Installing tabby/tabby (12.0.3): Extracting archive + - Installing tippyjs/tippyjs (6.3.7): Extracting archive + Cleaning: symfony/process + Cleaning: symfony/finder + Cleaning: symfony/filesystem + Cleaning: symfony/console + Cleaning: seld/jsonlint + Cleaning: justinrainbow/json-schema + Cleaning: twig/twig + Cleaning: symfony/yaml + Cleaning: symfony/validator + Cleaning: symfony/serializer + Cleaning: symfony/routing + Cleaning: symfony/http-foundation + Cleaning: symfony/psr-http-message-bridge + Cleaning: symfony/event-dispatcher + Cleaning: egulias/email-validator + Cleaning: symfony/var-dumper + Cleaning: symfony/http-kernel + Cleaning: symfony/dependency-injection + Cleaning: sebastian/diff + Cleaning: pear/pear_exception + Cleaning: pear/console_getopt + Cleaning: pear/pear-core-minimal + Cleaning: pear/archive_tar + Cleaning: mck89/peast + Cleaning: masterminds/html5 + Cleaning: guzzlehttp/psr7 + Cleaning: guzzlehttp/promises + Cleaning: symfony/css-selector + - Patching drupal/canvas + - Found cached patch at /mnt/ddev-global-cache/composer/patches/dd1ee073adaa9b96b834661b2aa6781620cbbf87ae95be5f58bc2e568b92f9bd.patch + +In Patches.php line 288: + + No available patcher was able to apply patch https://git.drupalcode.org/project/canvas/-/merge_requests/187.diff to dr + upal/canvas + + +update [--with WITH] [--prefer-source] [--prefer-dist] [--prefer-install PREFER-INSTALL] [--dry-run] [--dev] [--no-dev] [--lock] [--no-install] [--no-audit] [--audit-format AUDIT-FORMAT] [--no-security-blocking] [--no-autoloader] [--no-suggest] [--no-progress] [-w|--with-dependencies] [-W|--with-all-dependencies] [-v|vv|vvv|--verbose] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--apcu-autoloader-prefix APCU-AUTOLOADER-PREFIX] [--ignore-platform-req IGNORE-PLATFORM-REQ] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [-m|--minimal-changes] [--patch-only] [-i|--interactive] [--root-reqs] [--bump-after-update [BUMP-AFTER-UPDATE]] [--] [...] + +0m17.587s +Composer update encountered errors (likely patch failures), but continuing... +Regenerating autoload files... +Generating optimized autoload files +Hardening vendor directory with .htaccess file. +Generated optimized autoload files containing 7393 classes +All modules installed and ready! + +Create the private files directory. +0m0.003s + +Create the config sync directory. +0m0.001s + +Install Drupal. +drush is not available. You may need to 'ddev composer require drush/drush' +0m0.038s diff --git a/.devpanel/logs/init-2025-12-04-21:55:58.log b/.devpanel/logs/init-2025-12-04-21:55:58.log new file mode 100644 index 00000000..79589bb0 --- /dev/null +++ b/.devpanel/logs/init-2025-12-04-21:55:58.log @@ -0,0 +1,631 @@ +📦 AI version will be auto-detected from test module dependencies +📦 AI Module Configuration: + - AI Base: ai @ + - Dependencies: Auto-resolved from composer.json + +Cloning AI modules from git... + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Step 1: No Test Module +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + → Will use latest stable release tag + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Step 2: Clone AI Base Module @ latest stable +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Cloning: ai +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✓ Submodule exists, updating... +Submodule path 'repos/ai': checked out '6c704d8f04e7cb222164897f786fa87bee0f7c95' +0m0.059s + → No version specified, checking out latest stable release + → Found latest stable: 1.2.4 +Previous HEAD position was 6c704d8f Issues/3540486: Translate CKEditor plugin ignores language_source = lang +HEAD is now at b1194e65 Chatbot + → Detected AI version from tag: 1.2.x (from 1.2.4) + ✓ Using detected version for compatibility filtering: 1.2.x + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Step 3: Clone Additional AI Modules (compatibility filtering) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + → Cloning ai_provider_litellm... +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Cloning: ai_provider_litellm +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✓ Submodule exists, updating... +Submodule path 'repos/ai_provider_litellm': checked out '7523d5cac87cd831a480b411bc0eb7aca03f82f1' +0m0.029s + → No version specified, checking out latest stable release + → Found latest stable: 1.2.0-rc1 +Previous HEAD position was 7523d5c 3558458: add extra check on handleApiException +HEAD is now at 2abcc2e Resolve #3550655 "Override handleapiexception to" + ✓ ai_provider_litellm is compatible with AI 1.2.x + → Cloning ai_search... +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Cloning: ai_search +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✓ Submodule exists, updating... +0m0.021s + → No version specified, checking out latest stable release + → Found latest stable: 2.0.0-alpha1 +HEAD is now at 43a6627 fix: #3557904 Vector DB Explorer fails with TypeError when search results contain array values in extra data + ⚠️ Incompatible: requires AI ^2.0, but we have AI 1.2.x + ✗ Skipping ai_search from composer (incompatible, but cloned for inspection) + → Cloning ai_agents... +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Cloning: ai_agents +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✓ Submodule exists, updating... +Submodule path 'repos/ai_agents': checked out '9502f73f218999de66050463f1182fa51c6c0714' +0m0.027s + → No version specified, checking out latest stable release + → Found latest stable: 1.2.1 +Previous HEAD position was 9502f73 Cherry pick code from #3536318 +HEAD is now at 2fe31d6 Cherry pick code from #3536318 + ✓ ai_agents is compatible with AI 1.2.x + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +Step 4: Clone Default Provider +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ✓ Provider already cloned + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +✓ Summary +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + AI Version: 1.2.x + Cloned modules: ai,ai_provider_litellm,ai_search,ai_agents + Compatible (will be added to composer): ai,ai_provider_litellm,ai_agents +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +0m6.081s + +Performing clean rebuild... +Removing docroot directory... +0m0.786s +Rebuild mode enabled. + + +Remove root-owned files. +0m0.006s + +Generate composer.json. +Creating a "drupal/cms:2.0.x-dev" project at "./temp-composer-files" +Installing drupal/cms (2.0.x-dev 58e1bbb0d3740edf197985aaae25c6569714fa87) + - Installing drupal/cms (2.0.x-dev 58e1bbb): Extracting archive +Created project in /var/www/html/docroot/docroot/temp-composer-files +0m0.475s +Adding path repositories for compatible AI modules... +Path repositories added for compatible AI modules! +Adding CMS dependencies (full setup with webform libraries)... +Using version ^5.65 for codemirror/codemirror +Using version ^5.0 for jquery/inputmask +Using version ^17.0 for jquery/intl-tel-input +Using version ^1.1 for jquery/rateit +Using version ^4.0 for jquery/select2 +Using version ^0.9.1 for jquery/textcounter +Using version ^1.14 for jquery/timepicker +Using version ^2.11 for popperjs/popperjs +Using version ^2.0 for progress-tracker/progress-tracker +Using version ^2.3 for signature_pad/signature_pad +Using version ^12.0 for tabby/tabby +Using version ^6.3 for tippyjs/tippyjs +drush/drush is currently present in the require-dev key and you ran the command without the --dev flag, which will move it to the require key. +./composer.json has been updated +0m4.688s + +Running composer update... +Loading composer repositories with package information +Updating dependencies +Lock file operations: 225 installs, 0 updates, 0 removals + - Locking asm89/stack-cors (v2.3.0) + - Locking chi-teck/drupal-code-generator (4.2.0) + - Locking codemirror/codemirror (5.65.12) + - Locking composer/ca-bundle (1.5.9) + - Locking composer/class-map-generator (1.7.0) + - Locking composer/composer (2.9.2) + - Locking composer/installers (v2.3.0) + - Locking composer/metadata-minifier (1.0.0) + - Locking composer/pcre (3.3.2) + - Locking composer/semver (3.4.4) + - Locking composer/spdx-licenses (1.5.9) + - Locking composer/xdebug-handler (3.0.5) + - Locking consolidation/annotated-command (4.10.4) + - Locking consolidation/config (3.2.0) + - Locking consolidation/filter-via-dot-access-data (2.0.3) + - Locking consolidation/log (3.1.1) + - Locking consolidation/output-formatters (4.7.0) + - Locking consolidation/robo (5.1.1) + - Locking consolidation/site-alias (4.1.2) + - Locking consolidation/site-process (5.4.2) + - Locking cweagans/composer-configurable-plugin (2.0.0) + - Locking cweagans/composer-patches (2.0.0) + - Locking dflydev/dot-access-data (v3.0.3) + - Locking doctrine/annotations (2.0.2) + - Locking doctrine/deprecations (1.1.5) + - Locking doctrine/lexer (2.1.1) + - Locking dragonmantank/cron-expression (v3.6.0) + - Locking drupal/ai (1.2.4) + - Locking drupal/ai_agents (1.2.1) + - Locking drupal/ai_image_alt_text (1.0.1) + - Locking drupal/ai_provider_anthropic (1.2.0) + - Locking drupal/ai_provider_openai (1.2.0) + - Locking drupal/automatic_updates (4.0.0) + - Locking drupal/autosave_form (1.10.0) + - Locking drupal/better_exposed_filters (7.1.1) + - Locking drupal/bpmn_io (3.0.2) + - Locking drupal/byte (1.0.0-alpha5) + - Locking drupal/canvas (1.0.0) + - Locking drupal/captcha (2.0.9) + - Locking drupal/checklistapi (2.1.7) + - Locking drupal/coffee (2.0.1) + - Locking drupal/core (11.2.9) + - Locking drupal/core-composer-scaffold (11.2.9) + - Locking drupal/core-project-message (11.2.9) + - Locking drupal/core-recipe-unpack (11.2.9) + - Locking drupal/core-recommended (11.2.9) + - Locking drupal/core-vendor-hardening (11.2.9) + - Locking drupal/crop (2.5.0) + - Locking drupal/ctools (4.1.0) + - Locking drupal/cva (1.0.0-beta1) + - Locking drupal/dashboard (2.1.1) + - Locking drupal/drupal_cms_accessibility_tools (2.0.0-alpha2) + - Locking drupal/drupal_cms_admin_ui (2.0.0-alpha2) + - Locking drupal/drupal_cms_ai (2.0.0-alpha2) + - Locking drupal/drupal_cms_anti_spam (2.0.0-alpha2) + - Locking drupal/drupal_cms_authentication (2.0.0-alpha2) + - Locking drupal/drupal_cms_blog (2.0.0-alpha2) + - Locking drupal/drupal_cms_content_type_base (2.0.0-alpha2) + - Locking drupal/drupal_cms_forms (2.0.0-alpha2) + - Locking drupal/drupal_cms_google_analytics (2.0.0-alpha2) + - Locking drupal/drupal_cms_helper (2.0.0-alpha2) + - Locking drupal/drupal_cms_image (2.0.0-alpha2) + - Locking drupal/drupal_cms_page (2.0.0-alpha2) + - Locking drupal/drupal_cms_privacy_basic (2.0.0-alpha2) + - Locking drupal/drupal_cms_remote_video (2.0.0-alpha2) + - Locking drupal/drupal_cms_search (2.0.0-alpha2) + - Locking drupal/drupal_cms_seo_basic (2.0.0-alpha2) + - Locking drupal/drupal_cms_seo_tools (2.0.0-alpha2) + - Locking drupal/drupal_cms_starter (2.0.0-alpha2) + - Locking drupal/easy_breadcrumb (2.0.9) + - Locking drupal/easy_email (3.0.7) + - Locking drupal/easy_email_express (1.0.4) + - Locking drupal/easy_email_standard (1.0.3) + - Locking drupal/easy_email_text_format (1.0.3) + - Locking drupal/easy_email_theme (1.1.0) + - Locking drupal/easy_email_types_core (1.0.4) + - Locking drupal/easy_email_types_default (1.0.2) + - Locking drupal/eca (3.0.8) + - Locking drupal/editoria11y (2.2.18) + - Locking drupal/field_group (4.0.0) + - Locking drupal/focal_point (2.1.2) + - Locking drupal/friendly_captcha_challenge (0.9.18) + - Locking drupal/friendlycaptcha (1.1.4) + - Locking drupal/gin (5.0.9) + - Locking drupal/gin_login (2.1.3) + - Locking drupal/gin_toolbar (3.0.2) + - Locking drupal/google_tag (2.0.9) + - Locking drupal/honeypot (2.2.2) + - Locking drupal/jquery_ui (1.8.0) + - Locking drupal/jquery_ui_resizable (2.1.0) + - Locking drupal/key (1.20.0) + - Locking drupal/klaro (3.0.7) + - Locking drupal/klaro_js (3.0.1) + - Locking drupal/linkit (7.0.11) + - Locking drupal/login_emailusername (3.0.1) + - Locking drupal/mailsystem (4.5.0) + - Locking drupal/menu_link_attributes (1.5.0) + - Locking drupal/mercury (1.0.0-alpha2) + - Locking drupal/metatag (2.2.0) + - Locking drupal/modeler_api (1.0.6) + - Locking drupal/nouislider_js (15.8.1) + - Locking drupal/pathauto (1.14.0) + - Locking drupal/project_browser (2.1.2) + - Locking drupal/recipe_installer_kit (1.0.0) + - Locking drupal/redirect (1.12.0) + - Locking drupal/robotstxt (1.6.0) + - Locking drupal/sam (1.3.2) + - Locking drupal/scheduler (2.2.2) + - Locking drupal/scheduler_content_moderation_integration (3.0.4) + - Locking drupal/search_api (1.40.0) + - Locking drupal/search_api_autocomplete (1.11.0) + - Locking drupal/search_api_exclude (2.0.3) + - Locking drupal/selective_better_exposed_filters (3.0.3) + - Locking drupal/seo_checklist (5.2.4) + - Locking drupal/simple_search_form (1.8.0) + - Locking drupal/simple_sitemap (4.2.3) + - Locking drupal/sitemap (2.5.0) + - Locking drupal/svg_image (3.2.2) + - Locking drupal/symfony_mailer_lite (2.0.4) + - Locking drupal/tagify (1.2.44) + - Locking drupal/token (1.16.0) + - Locking drupal/token_or (2.3.2) + - Locking drupal/trash (3.0.22) + - Locking drupal/ui_icons (1.1.0-beta6) + - Locking drupal/webform (6.3.0-beta6) + - Locking drupal/yoast_seo (2.2.0) + - Locking drush/drush (13.7.0) + - Locking egulias/email-validator (4.0.4) + - Locking enshrined/svg-sanitize (0.22.0) + - Locking goalgorilla/rtseo.js (2.1.0) + - Locking grasmash/expander (3.0.1) + - Locking grasmash/yaml-cli (3.2.1) + - Locking guzzlehttp/guzzle (7.9.3) + - Locking guzzlehttp/promises (2.2.0) + - Locking guzzlehttp/psr7 (2.7.1) + - Locking html2text/html2text (4.3.2) + - Locking jquery/inputmask (5.0.9) + - Locking jquery/intl-tel-input (17.0.19) + - Locking jquery/rateit (1.1.5) + - Locking jquery/select2 (4.0.13) + - Locking jquery/textcounter (0.9.1) + - Locking jquery/timepicker (1.14.0) + - Locking justinrainbow/json-schema (6.6.3) + - Locking laravel/prompts (v0.3.8) + - Locking league/commonmark (2.8.0) + - Locking league/config (v1.2.0) + - Locking league/container (4.2.5) + - Locking league/html-to-markdown (5.1.1) + - Locking marc-mabe/php-enum (v4.7.2) + - Locking masterminds/html5 (2.9.0) + - Locking mck89/peast (v1.17.4) + - Locking mtownsend/xml-to-array (2.0.0) + - Locking nette/schema (v1.3.3) + - Locking nette/utils (v4.1.0) + - Locking nikic/php-parser (v5.6.2) + - Locking openai-php/client (v0.18.0) + - Locking pear/archive_tar (1.5.0) + - Locking pear/console_getopt (v1.4.3) + - Locking pear/pear-core-minimal (v1.10.16) + - Locking pear/pear_exception (v1.0.2) + - Locking phootwork/collection (v3.2.3) + - Locking phootwork/lang (v3.2.3) + - Locking php-http/discovery (1.20.0) + - Locking php-http/multipart-stream-builder (1.4.2) + - Locking php-tuf/composer-stager (v2.0.2) + - Locking phpowermove/docblock (v4.0) + - Locking popperjs/popperjs (2.11.6) + - Locking progress-tracker/progress-tracker (2.0.7) + - Locking psr/cache (3.0.0) + - Locking psr/container (2.0.2) + - Locking psr/event-dispatcher (1.0.0) + - Locking psr/http-client (1.0.3) + - Locking psr/http-factory (1.1.0) + - Locking psr/http-message (2.0) + - Locking psr/log (3.0.2) + - Locking psy/psysh (v0.12.15) + - Locking ralouphie/getallheaders (3.0.3) + - Locking react/promise (v3.3.0) + - Locking revolt/event-loop (v1.0.8) + - Locking sebastian/diff (7.0.0) + - Locking seld/jsonlint (1.11.0) + - Locking seld/phar-utils (1.2.1) + - Locking seld/signal-handler (2.0.2) + - Locking signature_pad/signature_pad (2.3.0) + - Locking symfony/console (v7.3.6) + - Locking symfony/css-selector (v7.4.0) + - Locking symfony/dependency-injection (v7.3.6) + - Locking symfony/deprecation-contracts (v3.6.0) + - Locking symfony/error-handler (v7.3.6) + - Locking symfony/event-dispatcher (v7.3.3) + - Locking symfony/event-dispatcher-contracts (v3.6.0) + - Locking symfony/filesystem (v7.3.6) + - Locking symfony/finder (v7.3.5) + - Locking symfony/http-foundation (v7.3.7) + - Locking symfony/http-kernel (v7.3.7) + - Locking symfony/mailer (v7.3.5) + - Locking symfony/mime (v7.3.4) + - Locking symfony/polyfill-ctype (v1.32.0) + - Locking symfony/polyfill-iconv (v1.32.0) + - Locking symfony/polyfill-intl-grapheme (v1.32.0) + - Locking symfony/polyfill-intl-idn (v1.32.0) + - Locking symfony/polyfill-intl-normalizer (v1.32.0) + - Locking symfony/polyfill-mbstring (v1.32.0) + - Locking symfony/polyfill-php73 (v1.33.0) + - Locking symfony/polyfill-php80 (v1.33.0) + - Locking symfony/polyfill-php81 (v1.33.0) + - Locking symfony/polyfill-php83 (v1.33.0) + - Locking symfony/polyfill-php84 (v1.32.0) + - Locking symfony/process (v7.3.4) + - Locking symfony/psr-http-message-bridge (v7.3.0) + - Locking symfony/routing (v7.3.6) + - Locking symfony/serializer (v7.3.5) + - Locking symfony/service-contracts (v3.6.1) + - Locking symfony/string (v7.3.4) + - Locking symfony/translation-contracts (v3.6.1) + - Locking symfony/validator (v7.3.7) + - Locking symfony/var-dumper (v7.3.5) + - Locking symfony/var-exporter (v7.3.4) + - Locking symfony/yaml (v7.3.5) + - Locking tabby/tabby (12.0.3) + - Locking tijsverkoyen/css-to-inline-styles (v2.3.0) + - Locking tippyjs/tippyjs (6.3.7) + - Locking twig/html-extra (v3.22.1) + - Locking twig/twig (v3.21.1) + - Locking yethee/tiktoken (0.5.1) +Writing lock file +Installing dependencies from lock file +Package operations: 225 installs, 0 updates, 0 removals + - Installing cweagans/composer-configurable-plugin (2.0.0): Extracting archive + - Installing cweagans/composer-patches (2.0.0): Extracting archive +patches.lock.json does not exist. Creating a new patches.lock.json. + - Resolving patches from dependencies. + - Installing composer/installers (v2.3.0): Extracting archive + - Installing drupal/core-composer-scaffold (11.2.9): Extracting archive + - Installing drupal/core-project-message (11.2.9): Extracting archive + - Installing drupal/core-recipe-unpack (11.2.9): Extracting archive + - Installing drupal/core-vendor-hardening (11.2.9): Extracting archive + - Installing php-http/discovery (1.20.0): Extracting archive + - Installing codemirror/codemirror (5.65.12): Extracting archive + - Installing symfony/process (v7.3.4): Extracting archive + - Installing symfony/polyfill-php84 (v1.32.0): Extracting archive + - Installing symfony/polyfill-php81 (v1.33.0): Extracting archive + - Installing symfony/polyfill-php80 (v1.33.0): Extracting archive + - Installing symfony/polyfill-php73 (v1.33.0): Extracting archive + - Installing symfony/finder (v7.3.5): Extracting archive + - Installing symfony/polyfill-iconv (v1.32.0): Extracting archive + - Installing symfony/polyfill-mbstring (v1.32.0): Extracting archive + - Installing symfony/polyfill-ctype (v1.32.0): Extracting archive + - Installing symfony/filesystem (v7.3.6): Extracting archive + - Installing symfony/polyfill-intl-normalizer (v1.32.0): Extracting archive + - Installing symfony/polyfill-intl-grapheme (v1.32.0): Extracting archive + - Installing symfony/string (v7.3.4): Extracting archive + - Installing symfony/deprecation-contracts (v3.6.0): Extracting archive + - Installing psr/container (2.0.2): Extracting archive + - Installing symfony/service-contracts (v3.6.1): Extracting archive + - Installing symfony/console (v7.3.6): Extracting archive + - Installing seld/signal-handler (2.0.2): Extracting archive + - Installing seld/phar-utils (1.2.1): Extracting archive + - Installing seld/jsonlint (1.11.0): Extracting archive + - Installing react/promise (v3.3.0): Extracting archive + - Installing psr/log (3.0.2): Extracting archive + - Installing marc-mabe/php-enum (v4.7.2): Extracting archive + - Installing justinrainbow/json-schema (6.6.3): Extracting archive + - Installing composer/pcre (3.3.2): Extracting archive + - Installing composer/xdebug-handler (3.0.5): Extracting archive + - Installing composer/spdx-licenses (1.5.9): Extracting archive + - Installing composer/semver (3.4.4): Extracting archive + - Installing composer/metadata-minifier (1.0.0): Extracting archive + - Installing composer/class-map-generator (1.7.0): Extracting archive + - Installing composer/ca-bundle (1.5.9): Extracting archive + - Installing composer/composer (2.9.2): Extracting archive + - Installing consolidation/log (3.1.1): Extracting archive + - Installing twig/twig (v3.21.1): Extracting archive + - Installing symfony/yaml (v7.3.5): Extracting archive + - Installing symfony/translation-contracts (v3.6.1): Extracting archive + - Installing symfony/polyfill-php83 (v1.33.0): Extracting archive + - Installing symfony/validator (v7.3.7): Extracting archive + - Installing symfony/serializer (v7.3.5): Extracting archive + - Installing symfony/routing (v7.3.6): Extracting archive + - Installing symfony/http-foundation (v7.3.7): Extracting archive + - Installing psr/http-message (2.0): Extracting archive + - Installing symfony/psr-http-message-bridge (v7.3.0): Extracting archive + - Installing symfony/polyfill-intl-idn (v1.32.0): Extracting archive + - Installing symfony/mime (v7.3.4): Extracting archive + - Installing psr/event-dispatcher (1.0.0): Extracting archive + - Installing symfony/event-dispatcher-contracts (v3.6.0): Extracting archive + - Installing symfony/event-dispatcher (v7.3.3): Extracting archive + - Installing doctrine/deprecations (1.1.5): Extracting archive + - Installing doctrine/lexer (2.1.1): Extracting archive + - Installing egulias/email-validator (4.0.4): Extracting archive + - Installing symfony/mailer (v7.3.5): Extracting archive + - Installing symfony/var-dumper (v7.3.5): Extracting archive + - Installing symfony/error-handler (v7.3.6): Extracting archive + - Installing symfony/http-kernel (v7.3.7): Extracting archive + - Installing symfony/var-exporter (v7.3.4): Extracting archive + - Installing symfony/dependency-injection (v7.3.6): Extracting archive + - Installing sebastian/diff (7.0.0): Extracting archive + - Installing revolt/event-loop (v1.0.8): Extracting archive + - Installing php-tuf/composer-stager (v2.0.2): Extracting archive + - Installing pear/pear_exception (v1.0.2): Extracting archive + - Installing pear/console_getopt (v1.4.3): Extracting archive + - Installing pear/pear-core-minimal (v1.10.16): Extracting archive + - Installing pear/archive_tar (1.5.0): Extracting archive + - Installing mck89/peast (v1.17.4): Extracting archive + - Installing masterminds/html5 (2.9.0): Extracting archive + - Installing ralouphie/getallheaders (3.0.3): Extracting archive + - Installing psr/http-factory (1.1.0): Extracting archive + - Installing guzzlehttp/psr7 (2.7.1): Extracting archive + - Installing psr/http-client (1.0.3): Extracting archive + - Installing guzzlehttp/promises (2.2.0): Extracting archive + - Installing guzzlehttp/guzzle (7.9.3): Extracting archive + - Installing psr/cache (3.0.0): Extracting archive + - Installing doctrine/annotations (2.0.2): Extracting archive + - Installing asm89/stack-cors (v2.3.0): Extracting archive + - Installing drupal/core (11.2.9): Extracting archive + - Installing drupal/ui_icons (1.1.0-beta6): Extracting archive + - Installing drupal/mercury (1.0.0-alpha2): Extracting archive + - Installing drupal/easy_email_text_format (1.0.3): Extracting archive + - Installing drupal/token (1.16.0): Extracting archive + - Installing drupal/jquery_ui (1.8.0): Extracting archive + - Installing drupal/jquery_ui_resizable (2.1.0): Extracting archive + - Installing drupal/easy_email (3.0.7): Extracting archive + - Installing drupal/easy_email_types_default (1.0.2): Extracting archive + - Installing drupal/easy_email_types_core (1.0.4): Extracting archive + - Installing symfony/css-selector (v7.4.0): Extracting archive + - Installing tijsverkoyen/css-to-inline-styles (v2.3.0): Extracting archive + - Installing html2text/html2text (4.3.2): Extracting archive + - Installing drupal/mailsystem (4.5.0): Extracting archive + - Installing drupal/symfony_mailer_lite (2.0.4): Extracting archive + - Installing drupal/easy_email_theme (1.1.0): Extracting archive + - Installing drupal/easy_email_standard (1.0.3): Extracting archive + - Installing drupal/easy_email_express (1.0.4): Extracting archive + - Installing goalgorilla/rtseo.js (2.1.0): Extracting archive + - Installing drupal/metatag (2.2.0): Extracting archive + - Installing drupal/yoast_seo (2.2.0): Extracting archive + - Installing drupal/token_or (2.3.2): Extracting archive + - Installing drupal/sitemap (2.5.0): Extracting archive + - Installing drupal/simple_sitemap (4.2.3): Extracting archive + - Installing drupal/checklistapi (2.1.7): Extracting archive + - Installing drupal/seo_checklist (5.2.4): Extracting archive + - Installing drupal/robotstxt (1.6.0): Extracting archive + - Installing drupal/modeler_api (1.0.6): Extracting archive + - Installing drupal/crop (2.5.0): Extracting archive + - Installing drupal/focal_point (2.1.2): Extracting archive + - Installing drupal/field_group (4.0.0): Extracting archive + - Installing dragonmantank/cron-expression (v3.6.0): Extracting archive + - Installing drupal/eca (3.0.8): Extracting archive + - Installing mtownsend/xml-to-array (2.0.0): Extracting archive + - Installing drupal/bpmn_io (3.0.2): Extracting archive + - Installing drupal/drupal_cms_seo_tools (2.0.0-alpha2): Extracting archive + - Installing drupal/menu_link_attributes (1.5.0): Extracting archive + - Installing drupal/klaro_js (3.0.1): Extracting archive + - Installing drupal/klaro (3.0.7): Extracting archive + - Installing drupal/trash (3.0.22): Extracting archive + - Installing drupal/tagify (1.2.44): Extracting archive + - Installing drupal/scheduler (2.2.2): Extracting archive + - Installing drupal/scheduler_content_moderation_integration (3.0.4): Extracting archive + - Installing drupal/ctools (4.1.0): Extracting archive + - Installing drupal/pathauto (1.14.0): Extracting archive + - Installing drupal/linkit (7.0.11): Extracting archive + - Installing enshrined/svg-sanitize (0.22.0): Extracting archive + - Installing drupal/svg_image (3.2.2): Extracting archive + - Installing drupal/drupal_cms_image (2.0.0-alpha2): Extracting archive + - Installing drupal/drupal_cms_helper (2.0.0-alpha2): Extracting archive + - Installing drupal/canvas (1.0.0): Extracting archive + - Installing drupal/autosave_form (1.10.0): Extracting archive + - Installing drupal/drupal_cms_content_type_base (2.0.0-alpha2): Extracting archive + - Installing drupal/drupal_cms_page (2.0.0-alpha2): Extracting archive + - Installing drupal/drupal_cms_privacy_basic (2.0.0-alpha2): Extracting archive + - Installing drupal/drupal_cms_remote_video (2.0.0-alpha2): Extracting archive + - Installing drupal/webform (6.3.0-beta6): Extracting archive + - Installing drupal/honeypot (2.2.2): Extracting archive + - Installing drupal/captcha (2.0.9): Extracting archive + - Installing drupal/friendlycaptcha (1.1.4): Extracting archive + - Installing drupal/friendly_captcha_challenge (0.9.18): Extracting archive + - Installing drupal/drupal_cms_anti_spam (2.0.0-alpha2): Extracting archive + - Installing drupal/drupal_cms_forms (2.0.0-alpha2): Extracting archive + - Installing drupal/nouislider_js (15.8.1): Extracting archive + - Installing drupal/better_exposed_filters (7.1.1): Extracting archive + - Installing drupal/selective_better_exposed_filters (3.0.3): Extracting archive + - Installing drupal/drupal_cms_blog (2.0.0-alpha2): Extracting archive + - Installing drupal/login_emailusername (3.0.1): Extracting archive + - Installing drupal/drupal_cms_authentication (2.0.0-alpha2): Extracting archive + - Installing drupal/sam (1.3.2): Extracting archive + - Installing drupal/project_browser (2.1.2): Extracting archive + - Installing drupal/gin_login (2.1.3): Extracting archive + - Installing drupal/gin_toolbar (3.0.2): Extracting archive + - Installing drupal/gin (5.0.9): Extracting archive + - Installing drupal/dashboard (2.1.1): Extracting archive + - Installing drupal/coffee (2.0.1): Extracting archive + - Installing drupal/drupal_cms_admin_ui (2.0.0-alpha2): Extracting archive + - Installing drupal/byte (1.0.0-alpha5): Extracting archive + - Installing drupal/core-recommended (11.2.9) + - Installing twig/html-extra (v3.22.1): Extracting archive + - Installing drupal/cva (1.0.0-beta1): Extracting archive + - Installing drupal/editoria11y (2.2.18): Extracting archive + - Installing drupal/drupal_cms_accessibility_tools (2.0.0-alpha2): Extracting archive + - Installing nette/utils (v4.1.0): Extracting archive + - Installing nette/schema (v1.3.3): Extracting archive + - Installing dflydev/dot-access-data (v3.0.3): Extracting archive + - Installing league/config (v1.2.0): Extracting archive + - Installing league/commonmark (2.8.0): Extracting archive + - Installing drupal/key (1.20.0): Extracting archive + - Installing yethee/tiktoken (0.5.1): Extracting archive + - Installing php-http/multipart-stream-builder (1.4.2): Extracting archive + - Installing openai-php/client (v0.18.0): Extracting archive + - Installing league/html-to-markdown (5.1.1): Extracting archive + - Installing drupal/ai (1.2.4): Extracting archive + - Installing drupal/ai_provider_openai (1.2.0): Extracting archive + - Installing drupal/ai_provider_anthropic (1.2.0): Extracting archive + - Installing drupal/ai_image_alt_text (1.0.1): Extracting archive + - Installing drupal/ai_agents (1.2.1): Extracting archive + - Installing drupal/drupal_cms_ai (2.0.0-alpha2): Extracting archive + - Installing drupal/google_tag (2.0.9): Extracting archive + - Installing drupal/drupal_cms_google_analytics (2.0.0-alpha2): Extracting archive + - Installing drupal/redirect (1.12.0): Extracting archive + - Installing drupal/easy_breadcrumb (2.0.9): Extracting archive + - Installing drupal/drupal_cms_seo_basic (2.0.0-alpha2): Extracting archive + - Installing drupal/simple_search_form (1.8.0): Extracting archive + - Installing drupal/search_api (1.40.0): Extracting archive + - Installing drupal/search_api_exclude (2.0.3): Extracting archive + - Installing drupal/search_api_autocomplete (1.11.0): Extracting archive + - Installing drupal/drupal_cms_search (2.0.0-alpha2): Extracting archive + - Installing drupal/automatic_updates (4.0.0): Extracting archive + - Installing drupal/drupal_cms_starter (2.0.0-alpha2): Extracting archive + - Installing nikic/php-parser (v5.6.2): Extracting archive + - Installing psy/psysh (v0.12.15): Extracting archive + - Installing league/container (4.2.5): Extracting archive + - Installing laravel/prompts (v0.3.8): Extracting archive + - Installing grasmash/yaml-cli (3.2.1): Extracting archive + - Installing grasmash/expander (3.0.1): Extracting archive + - Installing consolidation/config (3.2.0): Extracting archive + - Installing consolidation/site-alias (4.1.2): Extracting archive + - Installing consolidation/site-process (5.4.2): Extracting archive + - Installing phootwork/lang (v3.2.3): Extracting archive + - Installing phootwork/collection (v3.2.3): Extracting archive + - Installing phpowermove/docblock (v4.0): Extracting archive + - Installing consolidation/output-formatters (4.7.0): Extracting archive + - Installing consolidation/annotated-command (4.10.4): Extracting archive + - Installing consolidation/robo (5.1.1): Extracting archive + - Installing consolidation/filter-via-dot-access-data (2.0.3): Extracting archive + - Installing chi-teck/drupal-code-generator (4.2.0): Extracting archive + - Installing drush/drush (13.7.0): Extracting archive + - Installing drupal/recipe_installer_kit (1.0.0): Extracting archive + - Installing jquery/inputmask (5.0.9): Extracting archive + - Installing jquery/intl-tel-input (17.0.19): Extracting archive + - Installing jquery/rateit (1.1.5): Extracting archive + - Installing jquery/select2 (4.0.13): Extracting archive + - Installing jquery/textcounter (0.9.1): Extracting archive + - Installing jquery/timepicker (1.14.0): Extracting archive + - Installing popperjs/popperjs (2.11.6): Extracting archive + - Installing progress-tracker/progress-tracker (2.0.7): Extracting archive + - Installing signature_pad/signature_pad (2.3.0): Extracting archive + - Installing tabby/tabby (12.0.3): Extracting archive + - Installing tippyjs/tippyjs (6.3.7): Extracting archive + Cleaning: symfony/process + Cleaning: symfony/finder + Cleaning: symfony/filesystem + Cleaning: symfony/console + Cleaning: seld/jsonlint + Cleaning: justinrainbow/json-schema + Cleaning: twig/twig + Cleaning: symfony/yaml + Cleaning: symfony/validator + Cleaning: symfony/serializer + Cleaning: symfony/routing + Cleaning: symfony/http-foundation + Cleaning: symfony/psr-http-message-bridge + Cleaning: symfony/event-dispatcher + Cleaning: egulias/email-validator + Cleaning: symfony/var-dumper + Cleaning: symfony/http-kernel + Cleaning: symfony/dependency-injection + Cleaning: sebastian/diff + Cleaning: pear/pear_exception + Cleaning: pear/console_getopt + Cleaning: pear/pear-core-minimal + Cleaning: pear/archive_tar + Cleaning: mck89/peast + Cleaning: masterminds/html5 + Cleaning: guzzlehttp/psr7 + Cleaning: guzzlehttp/promises + Cleaning: symfony/css-selector + - Patching drupal/canvas + - Found cached patch at /mnt/ddev-global-cache/composer/patches/dd1ee073adaa9b96b834661b2aa6781620cbbf87ae95be5f58bc2e568b92f9bd.patch + +In Patches.php line 288: + + No available patcher was able to apply patch https://git.drupalcode.org/project/canvas/-/merge_requests/187.diff to dr + upal/canvas + + +update [--with WITH] [--prefer-source] [--prefer-dist] [--prefer-install PREFER-INSTALL] [--dry-run] [--dev] [--no-dev] [--lock] [--no-install] [--no-audit] [--audit-format AUDIT-FORMAT] [--no-security-blocking] [--no-autoloader] [--no-suggest] [--no-progress] [-w|--with-dependencies] [-W|--with-all-dependencies] [-v|vv|vvv|--verbose] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--apcu-autoloader-prefix APCU-AUTOLOADER-PREFIX] [--ignore-platform-req IGNORE-PLATFORM-REQ] [--ignore-platform-reqs] [--prefer-stable] [--prefer-lowest] [-m|--minimal-changes] [--patch-only] [-i|--interactive] [--root-reqs] [--bump-after-update [BUMP-AFTER-UPDATE]] [--] [...] + +0m12.372s +Composer update encountered errors (likely patch failures), but continuing... +Regenerating autoload files... +Generating optimized autoload files +Hardening vendor directory with .htaccess file. +Generated optimized autoload files containing 7393 classes +All modules installed and ready! + +Create the private files directory. +0m0.002s + +Create the config sync directory. +0m0.003s + +Install Drupal. +drush is not available. You may need to 'ddev composer require drush/drush' +0m0.047s diff --git a/.devpanel/re-config.sh b/.devpanel/re-config.sh index c7a9f0b3..6c79bcb8 100755 --- a/.devpanel/re-config.sh +++ b/.devpanel/re-config.sh @@ -15,10 +15,20 @@ # For GNU Affero General Public License see . # ---------------------------------------------------------------------- -#== If webRoot has not been difined, we will set appRoot to webRoot -if [[ ! -n "$WEB_ROOT" ]]; then - export WEB_ROOT=$APP_ROOT -fi +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Directory Setup (works in both DDEV and GitHub Actions environments) +# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +# Find the .devpanel directory (where this script lives) +DEVPANEL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Project root is one level up from .devpanel +PROJECT_ROOT="$(dirname "$DEVPANEL_DIR")" +# APP_ROOT is the composer root (from environment or default to PROJECT_ROOT) +APP_ROOT="${APP_ROOT:-$PROJECT_ROOT}" +# WEB_ROOT from environment (with fallback) +WEB_ROOT="${WEB_ROOT:-$APP_ROOT/web}" + +# Define drush command +DRUSH="$APP_ROOT/vendor/bin/drush" STATIC_FILES_PATH="$WEB_ROOT/sites/default/files/" SETTINGS_FILES_PATH="$WEB_ROOT/sites/default/settings.php" @@ -56,6 +66,6 @@ if [[ $(mysql -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD $DB_NAME -e "show #== Import mysql files if [[ -f "$APP_ROOT/.devpanel/dumps/db.sql.gz" ]]; then echo 'Import mysql file ...' - drush sqlq --file="$APP_ROOT/.devpanel/dumps/db.sql.gz" --file-delete + "$DRUSH" sqlq --file="$APP_ROOT/.devpanel/dumps/db.sql.gz" --file-delete fi fi diff --git a/.devpanel/salt.txt b/.devpanel/salt.txt new file mode 100644 index 00000000..5860313c --- /dev/null +++ b/.devpanel/salt.txt @@ -0,0 +1 @@ +d529034bdfcacb2f9d15f178c24ac11c9dcdb1838a94f203b471de3318c07e29 diff --git a/.devpanel/setup_ai.sh b/.devpanel/setup_ai.sh new file mode 100755 index 00000000..1d519791 --- /dev/null +++ b/.devpanel/setup_ai.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -eu -o pipefail + + +echo +time $DRUSH -n en ai_provider_litellm +$DRUSH -n key-save litellm_api_key --label="LiteLLM API key" --key-provider=env --key-provider-settings='{ + "env_variable": "DP_AI_VIRTUAL_KEY", + "base64_encoded": false, + "strip_line_breaks": true +}' +$DRUSH -n cset ai_provider_litellm.settings api_key litellm_api_key +$DRUSH -n cset ai_provider_litellm.settings moderation false --input-format yaml +$DRUSH -n cset ai_provider_litellm.settings host "${DP_AI_HOST:="https://ai.drupalforge.org"}" +$DRUSH -q recipe ../recipes/drupal_cms_ai --input=drupal_cms_ai.provider=litellm +$DRUSH -n cset ai.settings default_providers.chat.provider_id litellm +$DRUSH -n cset ai.settings default_providers.chat.model_id openai/gpt-4o-mini +$DRUSH -n cset ai.settings default_providers.chat_with_complex_json.provider_id litellm +$DRUSH -n cset ai.settings default_providers.chat_with_complex_json.model_id openai/gpt-4o-mini +$DRUSH -n cset ai.settings default_providers.chat_with_image_vision.provider_id litellm +$DRUSH -n cset ai.settings default_providers.chat_with_image_vision.model_id openai/gpt-4o-mini +$DRUSH -n cset ai.settings default_providers.chat_with_structured_response.provider_id litellm +$DRUSH -n cset ai.settings default_providers.chat_with_structured_response.model_id openai/gpt-4o-mini +$DRUSH -n cset ai.settings default_providers.chat_with_tools.provider_id litellm +$DRUSH -n cset ai.settings default_providers.chat_with_tools.model_id openai/gpt-4o-mini +$DRUSH -n cset ai.settings default_providers.embeddings.provider_id litellm +$DRUSH -n cset ai.settings default_providers.embeddings.model_id openai/text-embedding-3-small +$DRUSH -n cset ai.settings default_providers.text_to_speech.provider_id litellm +$DRUSH -n cset ai.settings default_providers.text_to_speech.model_id openai/gpt-4o-mini-realtime-preview +$DRUSH -n cset ai_assistant_api.ai_assistant.drupal_cms_assistant llm_provider __default__ +$DRUSH -n cset klaro.klaro_app.deepchat status 0 \ No newline at end of file diff --git a/.devpanel/warm b/.devpanel/warm deleted file mode 100755 index 78b88de4..00000000 --- a/.devpanel/warm +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env php - TRUE, 1); -require 'index.php'; -ob_end_clean(); -echo "Warmed cache for " . $_SERVER['REQUEST_URI'] . "\n"; diff --git a/.github/workflows/docker-publish-image.yml b/.github/workflows/docker-publish-image.yml index 51583280..0ecb68f3 100644 --- a/.github/workflows/docker-publish-image.yml +++ b/.github/workflows/docker-publish-image.yml @@ -5,9 +5,16 @@ on: drupal_core_version: required: false type: string + description: 'Drupal version to install (e.g., 1.x, 11.x, 11.2.5)' webserver_image: required: true type: string + description: 'Base PHP image (e.g., devpanel/php:8.3-base-ai)' + image_tag_suffix: + required: false + type: string + default: '' + description: 'Tag suffix (cms or core) - auto-detects starter template' secrets: DOCKERHUB_TOKEN: required: true @@ -34,6 +41,7 @@ jobs: DB_PASSWORD: password DB_DRIVER: mysql DP_VERSION: ${{ inputs.drupal_core_version || '' }} + DP_IMAGE: drupalforge/drupalpod-ai-qa:${{ inputs.image_tag_suffix || 'latest' }} ports: - 80:80 volumes: @@ -86,20 +94,36 @@ jobs: - name: Set env to PHP 8.2 environment if: endsWith(inputs.webserver_image, ':8.2-base-ai') run: | - echo "IMAGE_TAG=drupalforge/drupalpod:php-8.2" >> $GITHUB_ENV + SUFFIX="${{ inputs.image_tag_suffix }}" + if [ -n "$SUFFIX" ]; then + echo "IMAGE_TAG=drupalforge/drupalpod-ai-qa:php-8.2-${SUFFIX}" >> $GITHUB_ENV + else + echo "IMAGE_TAG=drupalforge/drupalpod-ai-qa:php-8.2" >> $GITHUB_ENV + fi - name: Set env to PHP 8.3 environment if: endsWith(inputs.webserver_image, ':8.3-base-ai') run: | - echo "IMAGE_TAG=drupalforge/drupalpod:php-8.3" >> $GITHUB_ENV + SUFFIX="${{ inputs.image_tag_suffix }}" + if [ -n "$SUFFIX" ]; then + echo "IMAGE_TAG=drupalforge/drupalpod-ai-qa:php-8.3-${SUFFIX}" >> $GITHUB_ENV + else + echo "IMAGE_TAG=drupalforge/drupalpod-ai-qa:php-8.3" >> $GITHUB_ENV + fi - name: Commit and push the container state to Docker Hub run: | docker commit ${{ job.services.webserver.id }} ${{ env.IMAGE_TAG }} docker push ${{ env.IMAGE_TAG }} - - name: Push to tag latest - if: endsWith(inputs.webserver_image, ':8.3-base-ai') + - name: Push to tag latest (CMS only) + if: endsWith(inputs.webserver_image, ':8.3-base-ai') && inputs.image_tag_suffix == 'cms' + run: | + docker commit ${{ job.services.webserver.id }} drupalforge/drupalpod-ai-qa:latest + docker push drupalforge/drupalpod-ai-qa:latest + + - name: Push to tag core (Core only) + if: endsWith(inputs.webserver_image, ':8.3-base-ai') && inputs.image_tag_suffix == 'core' run: | - docker commit ${{ job.services.webserver.id }} drupalforge/drupalpod:latest - docker push drupalforge/drupalpod:latest + docker commit ${{ job.services.webserver.id }} drupalforge/drupalpod-ai-qa:core + docker push drupalforge/drupalpod-ai-qa:core diff --git a/.github/workflows/docker-publish-images.yml b/.github/workflows/docker-publish-images.yml index 4b1722f1..c6b4d61c 100644 --- a/.github/workflows/docker-publish-images.yml +++ b/.github/workflows/docker-publish-images.yml @@ -10,14 +10,34 @@ concurrency: permissions: actions: write jobs: - build-php-8_2: + build-php-8_2-cms: uses: ./.github/workflows/docker-publish-image.yml with: webserver_image: devpanel/php:8.2-base-ai - drupal_core_version: 10.5.4 + drupal_core_version: '1.x' + image_tag_suffix: cms secrets: inherit - build-php-8_3: + + build-php-8_2-core: + uses: ./.github/workflows/docker-publish-image.yml + with: + webserver_image: devpanel/php:8.2-base-ai + drupal_core_version: '11.x' + image_tag_suffix: core + secrets: inherit + + build-php-8_3-cms: + uses: ./.github/workflows/docker-publish-image.yml + with: + webserver_image: devpanel/php:8.3-base-ai + drupal_core_version: '1.x' + image_tag_suffix: cms + secrets: inherit + + build-php-8_3-core: uses: ./.github/workflows/docker-publish-image.yml with: webserver_image: devpanel/php:8.3-base-ai + drupal_core_version: '11.x' + image_tag_suffix: core secrets: inherit diff --git a/.gitignore b/.gitignore index d5f9d285..713d379c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,51 +1,15 @@ -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# Drupal / Composer -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -/recipes -/vendor -/web -/web/core -/web/modules/contrib -/web/themes/contrib -/web/profiles/contrib -/web/libraries -composer.lock -patches.lock.json -.gitattributes -.editorconfig -"Drupal Core Development Composer Project.md" -README.md - -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# Runtime / Generated -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -/logs -/.devpanel/salt.txt -/private -/config/sync -composer.json -LICENSE.txt +# Drupal installation (everything Drupal-related is in docroot/) +/docroot -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# AI Modules (git submodules - managed by .gitmodules) -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -/repos/* -!/repos/.gitkeep +# Git submodules (dynamically generated - don't commit) +/.gitmodules +/repos -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# Node / Testing -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -/node_modules -package-lock.json - -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# User-specific Config (users customize per environment) -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -.ddev/config.drupal.yaml +# Dependencies managed by Composer (legacy - now in docroot/). +/recipes +/vendor -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # macOS -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ .DS_Store .AppleDouble .LSOverride @@ -53,9 +17,7 @@ package-lock.json .Spotlight-V100 .Trashes -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Windows -# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Thumbs.db ehthumbs.db Desktop.ini diff --git a/.gitmodules b/.gitmodules index 51477f7a..061d8206 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,3 +18,15 @@ path = repos/ai_agents url = https://git.drupalcode.org/project/ai_agents.git ignore = dirty +[submodule "docroot/repos/ai"] + path = docroot/repos/ai + url = https://git.drupalcode.org/project/ai.git +[submodule "docroot/repos/ai_provider_litellm"] + path = docroot/repos/ai_provider_litellm + url = https://git.drupalcode.org/project/ai_provider_litellm.git +[submodule "docroot/repos/ai_search"] + path = docroot/repos/ai_search + url = https://git.drupalcode.org/project/ai_search.git +[submodule "docroot/repos/ai_agents"] + path = docroot/repos/ai_agents + url = https://git.drupalcode.org/project/ai_agents.git diff --git a/docroot/repos/ai b/docroot/repos/ai new file mode 160000 index 00000000..b1194e65 --- /dev/null +++ b/docroot/repos/ai @@ -0,0 +1 @@ +Subproject commit b1194e65648e43ecf724a47ec7aa39dcaeb55aba diff --git a/docroot/repos/ai_agents b/docroot/repos/ai_agents new file mode 160000 index 00000000..2fe31d67 --- /dev/null +++ b/docroot/repos/ai_agents @@ -0,0 +1 @@ +Subproject commit 2fe31d67e1750f91cf152c6ba18d6e527b8843fd diff --git a/docroot/repos/ai_provider_litellm b/docroot/repos/ai_provider_litellm new file mode 160000 index 00000000..2abcc2ee --- /dev/null +++ b/docroot/repos/ai_provider_litellm @@ -0,0 +1 @@ +Subproject commit 2abcc2eee856a25239d23b2a186ed59051af0018 diff --git a/docroot/repos/ai_search b/docroot/repos/ai_search new file mode 160000 index 00000000..43a66277 --- /dev/null +++ b/docroot/repos/ai_search @@ -0,0 +1 @@ +Subproject commit 43a66277d277c4fa601c6ed58b41c8e17e3f4c9a diff --git a/recipes/.gitignore b/recipes/.gitignore deleted file mode 100644 index 739a3394..00000000 --- a/recipes/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/README.txt \ No newline at end of file From fc6f5dfc6cdce75c57ff8dca41f0c4917f34835a Mon Sep 17 00:00:00 2001 From: LittlePixieZ Date: Fri, 5 Dec 2025 08:43:25 +0000 Subject: [PATCH 8/9] Fix patches not being allowed early enough --- .devpanel/composer_setup.sh | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/.devpanel/composer_setup.sh b/.devpanel/composer_setup.sh index 2e6ff51a..b82b13e4 100755 --- a/.devpanel/composer_setup.sh +++ b/.devpanel/composer_setup.sh @@ -69,13 +69,8 @@ cp -r temp-composer-files/. . # Clean up temp directory. rm -rf temp-composer-files -# Set minimum-stability to dev to allow alpha/beta packages (needed for dev versions). -composer config minimum-stability dev - -# Allow patches to fail without stopping installation. -composer config extra.composer-exit-on-patch-failure false - # Programmatically fix Composer 2.2 allow-plugins to avoid errors. +# IMPORTANT: Do this FIRST before any other composer config commands to avoid warnings. composer config --no-plugins allow-plugins.composer/installers true composer config --no-plugins allow-plugins.drupal/core-project-message true composer config --no-plugins allow-plugins.drupal/core-vendor-hardening true @@ -85,9 +80,16 @@ composer config --no-plugins allow-plugins.phpstan/extension-installer true composer config --no-plugins allow-plugins.mglaman/composer-drupal-lenient true composer config --no-plugins allow-plugins.php-http/discovery true composer config --no-plugins allow-plugins.tbachert/spi false +composer config --no-plugins allow-plugins.cweagans/composer-patches true + +# Set minimum-stability to dev to allow alpha/beta packages (needed for dev versions). +composer config minimum-stability dev + +# Allow patches to fail without stopping installation. +composer config extra.composer-exit-on-patch-failure false # Scaffold settings.php. -composer config extra.drupal-scaffold.file-mapping '{"[web-root]/sites/default/settings.php":{"path":"web/core/assets/scaffold/files/default.settings.php","overwrite":false}}' +composer config --json extra.drupal-scaffold.file-mapping '{"[web-root]/sites/default/settings.php":{"path":"web/core/assets/scaffold/files/default.settings.php","overwrite":false}}' composer config scripts.post-drupal-scaffold-cmd \ 'cd web/sites/default && test -z "$(grep '\''include \$devpanel_settings;'\'' settings.php)" && patch -Np1 -r /dev/null < $DIR/drupal-settings.patch || :' @@ -126,9 +128,6 @@ fi # AI DEPENDENCIES # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -# Enable Composer Patches plugin (needed for applying patches from drupal.org). -composer config --no-plugins allow-plugins.cweagans/composer-patches true - if [ "$STARTER_TEMPLATE" = "cms" ]; then echo "Adding CMS dependencies (full setup with webform libraries)..." From 8441014b1b029be513bd544a06b06478718f53f1 Mon Sep 17 00:00:00 2001 From: LittlePixieZ Date: Fri, 5 Dec 2025 08:49:45 +0000 Subject: [PATCH 9/9] Remove unnecessary action --- .github/workflows/docker-publish-tempate.yml | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 .github/workflows/docker-publish-tempate.yml diff --git a/.github/workflows/docker-publish-tempate.yml b/.github/workflows/docker-publish-tempate.yml deleted file mode 100644 index 87448813..00000000 --- a/.github/workflows/docker-publish-tempate.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Docker build and push template -on: - push: - branches: - - "main" - - test/* - workflow_dispatch: -jobs: - build-application: - uses: drupalforge/docker_publish_action/.github/workflows/docker-publish.yml@main - with: - dockerhub_username: ${{ vars.DOCKERHUB_USERNAME }} - secrets: - dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}