diff --git a/.circleci/config.yml b/.circleci/config.yml index 30ac3670f..ef5e31516 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -54,7 +54,7 @@ aliases: # This container has all the necessary tools to run a dockerized environment. # @see https://github.com/drevops/ci-runner # @see https://hub.docker.com/repository/docker/drevops/ci-runner/tags?page=1&ordering=last_updated - - image: drevops/ci-runner:24.4.0 + - image: drevops/ci-runner:24.7.0 auth: username: ${DREVOPS_CONTAINER_REGISTRY_USER} password: ${DREVOPS_CONTAINER_REGISTRY_PASS} @@ -238,6 +238,13 @@ jobs: - v1.21.0-db10-{{ checksum "/tmp/db_cache_branch" }}-{{ checksum "/tmp/db_cache_fallback_yes" }}- #;> !PROVISION_USE_PROFILE + - run: + name: Lint Dockerfiles with Hadolint + command: | + for file in $(find . -name 'Dockerfile' -o -name '*.dockerfile'); do + echo "Linting ${file}" && cat "${file}" | docker run --rm -i hadolint/hadolint || [ "${DREVOPS_CI_HADOLINT_IGNORE_FAILURE:-0}" -eq 1 ] + done + - run: name: Login to container registry command: ./scripts/drevops/login-container-registry.sh @@ -252,6 +259,10 @@ jobs: mkdir -p "${DREVOPS_EXPORT_CODE_DIR}" docker compose cp -L cli:"/app/." "${DREVOPS_EXPORT_CODE_DIR}" + - run: + name: Validate Composer configuration + command: docker compose exec cli composer validate --strict || [ "${DREVOPS_CI_COMPOSER_VALIDATE_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Install development dependencies command: | @@ -259,13 +270,6 @@ jobs: if [ -n \"${GITHUB_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${GITHUB_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" - - run: - name: Lint Dockerfiles with Hadolint - command: | - for file in $(find . -name 'Dockerfile' -o -name '*.dockerfile'); do - echo "Linting ${file}" && cat "${file}" | docker run --rm -i hadolint/hadolint || [ "${DREVOPS_CI_HADOLINT_IGNORE_FAILURE:-0}" -eq 1 ] - done - - run: name: Lint code with PHPCS command: docker compose exec -T cli vendor/bin/phpcs || [ "${DREVOPS_CI_PHPCS_IGNORE_FAILURE:-0}" -eq 1 ] diff --git a/.docker/cli.dockerfile b/.docker/cli.dockerfile index cfd19bdc0..b6822ae5e 100644 --- a/.docker/cli.dockerfile +++ b/.docker/cli.dockerfile @@ -4,9 +4,9 @@ # # hadolint global ignore=DL3018 # -# @see https://hub.docker.com/r/uselagoon/php-8.2-cli-drupal/tags +# @see https://hub.docker.com/r/uselagoon/php-8.3-cli-drupal/tags # @see https://github.com/uselagoon/lagoon-images/tree/main/images/php-cli-drupal -FROM uselagoon/php-8.2-cli-drupal:24.5.0 +FROM uselagoon/php-8.3-cli-drupal:24.7.0 # Add missing variables. # @todo Remove once https://github.com/uselagoon/lagoon/issues/3121 is resolved. @@ -30,6 +30,9 @@ ENV DRUPAL_PRIVATE_FILES=${DRUPAL_PRIVATE_FILES} ARG DRUPAL_TEMPORARY_FILES="${TMP:-/tmp}" ENV DRUPAL_TEMPORARY_FILES=${DRUPAL_TEMPORARY_FILES} +ARG DRUPAL_CONFIG_PATH="/app/config/default" +ENV DRUPAL_CONFIG_PATH=${DRUPAL_CONFIG_PATH} + # Set default values for environment variables. # These values will be overridden if set in docker-compose.yml or .env file # during build stage. @@ -95,8 +98,8 @@ RUN npm --prefix /app/${WEBROOT}/themes/custom/your_site_theme ci --no-audit --n COPY . /app # Create files directories and set correct permissions. -RUN mkdir -p "${DRUPAL_PUBLIC_FILES}" "${DRUPAL_PRIVATE_FILES}" "${DRUPAL_TEMPORARY_FILES}" && \ - chmod 0770 "${DRUPAL_PUBLIC_FILES}" "${DRUPAL_PRIVATE_FILES}" "${DRUPAL_TEMPORARY_FILES}" +RUN mkdir -p "${DRUPAL_PUBLIC_FILES}" "${DRUPAL_PRIVATE_FILES}" "${DRUPAL_TEMPORARY_FILES}" "${DRUPAL_CONFIG_PATH}" && \ + chmod 0770 "${DRUPAL_PUBLIC_FILES}" "${DRUPAL_PRIVATE_FILES}" "${DRUPAL_TEMPORARY_FILES}" "${DRUPAL_CONFIG_PATH}" # Compile front-end assets. Running this after copying all files as we need # sources to compile assets. diff --git a/.docker/mariadb.dockerfile b/.docker/mariadb.dockerfile index 75578497e..eea823a81 100644 --- a/.docker/mariadb.dockerfile +++ b/.docker/mariadb.dockerfile @@ -8,7 +8,7 @@ # @see https://github.com/drevops/mariadb-drupal-data # # The ARG value will be updated with a value passed from docker-compose.yml -ARG IMAGE=uselagoon/mariadb-10.11-drupal:24.5.0 +ARG IMAGE=uselagoon/mariadb-10.11-drupal:24.7.0 # hadolint ignore=DL3006 FROM ${IMAGE} diff --git a/.docker/nginx-drupal.dockerfile b/.docker/nginx-drupal.dockerfile index a28f26edb..df678e460 100644 --- a/.docker/nginx-drupal.dockerfile +++ b/.docker/nginx-drupal.dockerfile @@ -9,7 +9,7 @@ FROM ${CLI_IMAGE:-cli} as cli # @see https://hub.docker.com/r/uselagoon/nginx-drupal/tags?page=1 # @see https://github.com/uselagoon/lagoon-images/tree/main/images/nginx-drupal -FROM uselagoon/nginx-drupal:24.5.0 +FROM uselagoon/nginx-drupal:24.7.0 # Webroot is used for Nginx docroot configuration. ARG WEBROOT=web diff --git a/.docker/php.dockerfile b/.docker/php.dockerfile index 6245659c0..b34316044 100644 --- a/.docker/php.dockerfile +++ b/.docker/php.dockerfile @@ -8,9 +8,9 @@ ARG CLI_IMAGE # hadolint ignore=DL3006 FROM ${CLI_IMAGE:-cli} as cli -# @see https://hub.docker.com/r/uselagoon/php-8.2-fpm/tags +# @see https://hub.docker.com/r/uselagoon/php-8.3-fpm/tags # @see https://github.com/uselagoon/lagoon-images/tree/main/images/php-fpm -FROM uselagoon/php-8.2-fpm:24.5.0 +FROM uselagoon/php-8.3-fpm:24.7.0 RUN apk add --no-cache tzdata diff --git a/.docker/solr.dockerfile b/.docker/solr.dockerfile index 792d6fba4..7b303ed6f 100644 --- a/.docker/solr.dockerfile +++ b/.docker/solr.dockerfile @@ -5,7 +5,7 @@ FROM ${CLI_IMAGE} as cli # @see https://hub.docker.com/r/uselagoon/solr-8/tags # @see https://github.com/uselagoon/lagoon-images/blob/main/images/solr/8.Dockerfile -FROM uselagoon/solr-8:24.5.0 +FROM uselagoon/solr-8:24.7.0 # Solr Jump-start config needs to be manually copied from search_api_solr module # /app/docroot/modules/contrib/search_api_solr/jump-start/solr8/config-set. diff --git a/.github/workflows/assign-author.yml b/.github/workflows/assign-author.yml index 466655fc9..a5e7fe1e0 100644 --- a/.github/workflows/assign-author.yml +++ b/.github/workflows/assign-author.yml @@ -15,4 +15,4 @@ jobs: steps: - name: Assign author - uses: toshimaru/auto-author-assign@v2.1.0 + uses: toshimaru/auto-author-assign@v2.1.1 diff --git a/.github/workflows/close-pull-request.yml b/.github/workflows/close-pull-request.yml index 9a9fccda7..1fcfae00c 100644 --- a/.github/workflows/close-pull-request.yml +++ b/.github/workflows/close-pull-request.yml @@ -21,4 +21,6 @@ jobs: --header "X-GitHub-Delivery: ${RUNNER_TRACKING_ID:7}" \ --header "X-GitHub-Event: pull_request" \ --data-binary @- \ - "${LAGOON_WEBHOOK_ENDPOINT-https://hooks.lagoon.amazeeio.cloud/}" + "${LAGOON_WEBHOOK_ENDPOINT:-https://hooks.lagoon.amazeeio.cloud/}" + env: + LAGOON_WEBHOOK_ENDPOINT: ${{ env.LAGOON_WEBHOOK_ENDPOINT }} diff --git a/.scaffold/docs/.utils/variables/extra/ci.variables.sh b/.scaffold/docs/.utils/variables/extra/ci.variables.sh index 2f9f72173..50156b943 100755 --- a/.scaffold/docs/.utils/variables/extra/ci.variables.sh +++ b/.scaffold/docs/.utils/variables/extra/ci.variables.sh @@ -9,6 +9,12 @@ DREVOPS_EXPORT_DB_CONTAINER_REGISTRY_DEPLOY_PROCEED= # Directory to store exported code. DREVOPS_EXPORT_CODE_DIR= +# Ignore Hadolint failures. +DREVOPS_CI_HADOLINT_IGNORE_FAILURE=0 + +# Ignore `composer validate` failures. +DREVOPS_CI_COMPOSER_VALIDATE_IGNORE_FAILURE=0 + # Ignore PHPCS failures. DREVOPS_CI_PHPCS_IGNORE_FAILURE=0 diff --git a/.scaffold/docs/content/workflows/variables.mdx b/.scaffold/docs/content/workflows/variables.mdx index d8a1472d0..6e257fdce 100644 --- a/.scaffold/docs/content/workflows/variables.mdx +++ b/.scaffold/docs/content/workflows/variables.mdx @@ -88,6 +88,22 @@ Default value: `UNDEFINED` Defined in: `CI config` +### `DREVOPS_CI_COMPOSER_VALIDATE_IGNORE_FAILURE` + +Ignore `composer validate` failures. + +Default value: `UNDEFINED` + +Defined in: `CI config` + +### `DREVOPS_CI_HADOLINT_IGNORE_FAILURE` + +Ignore Hadolint failures. + +Default value: `UNDEFINED` + +Defined in: `CI config` + ### `DREVOPS_CI_NPM_LINT_IGNORE_FAILURE` Ignore NPM linters failures. diff --git a/.scaffold/tests/bats/fixtures/docker-compose.env.json b/.scaffold/tests/bats/fixtures/docker-compose.env.json index 44b66c3bc..f22922e4b 100644 --- a/.scaffold/tests/bats/fixtures/docker-compose.env.json +++ b/.scaffold/tests/bats/fixtures/docker-compose.env.json @@ -24,6 +24,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -70,6 +71,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -118,6 +120,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -173,6 +176,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -209,6 +213,7 @@ "build": { "args": { "CLI_IMAGE": "star_wars", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_TEMPORARY_FILES": "/tmp", @@ -228,6 +233,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -290,6 +296,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -362,6 +369,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", diff --git a/.scaffold/tests/bats/fixtures/docker-compose.env_local.json b/.scaffold/tests/bats/fixtures/docker-compose.env_local.json index 44b66c3bc..f22922e4b 100644 --- a/.scaffold/tests/bats/fixtures/docker-compose.env_local.json +++ b/.scaffold/tests/bats/fixtures/docker-compose.env_local.json @@ -24,6 +24,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -70,6 +71,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -118,6 +120,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -173,6 +176,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -209,6 +213,7 @@ "build": { "args": { "CLI_IMAGE": "star_wars", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_TEMPORARY_FILES": "/tmp", @@ -228,6 +233,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -290,6 +296,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", @@ -362,6 +369,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "0", diff --git a/.scaffold/tests/bats/fixtures/docker-compose.env_mod.json b/.scaffold/tests/bats/fixtures/docker-compose.env_mod.json index f573e045c..b9dd25ee0 100644 --- a/.scaffold/tests/bats/fixtures/docker-compose.env_mod.json +++ b/.scaffold/tests/bats/fixtures/docker-compose.env_mod.json @@ -24,6 +24,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "the_matrix.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "1", @@ -70,6 +71,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "the_matrix.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "1", @@ -118,6 +120,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "the_matrix.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "1", @@ -173,6 +176,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "the_matrix.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "1", @@ -209,8 +213,9 @@ "build": { "args": { "CLI_IMAGE": "the_matrix", - "DRUPAL_PRIVATE_FILES": "/app/docroot/sites/default/files/private", - "DRUPAL_PUBLIC_FILES": "/app/docroot/sites/default/files", + "DRUPAL_CONFIG_PATH": "/app/config/default", + "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", + "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_TEMPORARY_FILES": "/tmp", "WEBROOT": "docroot" }, @@ -228,6 +233,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "the_matrix.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "1", @@ -290,6 +296,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "the_matrix.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "1", @@ -362,6 +369,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "the_matrix.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "1", diff --git a/.scaffold/tests/bats/fixtures/docker-compose.noenv.json b/.scaffold/tests/bats/fixtures/docker-compose.noenv.json index 74016b8f5..f974d07e0 100644 --- a/.scaffold/tests/bats/fixtures/docker-compose.noenv.json +++ b/.scaffold/tests/bats/fixtures/docker-compose.noenv.json @@ -24,6 +24,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "", @@ -70,6 +71,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "", @@ -118,6 +120,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "", @@ -173,6 +176,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "", @@ -209,6 +213,7 @@ "build": { "args": { "CLI_IMAGE": "star_wars", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_TEMPORARY_FILES": "/tmp", @@ -228,6 +233,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "", @@ -290,6 +296,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "", @@ -362,6 +369,7 @@ "environment": { "CI": "true", "DREVOPS_LOCALDEV_URL": "star_wars.docker.amazee.io", + "DRUPAL_CONFIG_PATH": "/app/config/default", "DRUPAL_PRIVATE_FILES": "/app/web/sites/default/files/private", "DRUPAL_PUBLIC_FILES": "/app/web/sites/default/files", "DRUPAL_REDIS_ENABLED": "", diff --git a/.scaffold/tests/bats/notify.bats b/.scaffold/tests/bats/notify.bats index 6b94013f5..4efd6d084 100644 --- a/.scaffold/tests/bats/notify.bats +++ b/.scaffold/tests/bats/notify.bats @@ -148,7 +148,7 @@ load _helper.bash declare -a STEPS=( "Started dispatching notifications." "Started GitHub notification for post_deployment event." - "@curl -X GET -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments?ref=mybranch # [{\"id\": \"${app_id}\", \"othervar\": \"54321\"},{\"id\": \"987654321\", \"othervar\": \"12345\"}]" + "@curl -X GET -H Authorization: token token12345 -H Accept: application/vnd.github.v3+json -s https://api.github.com/repos/myorg/myrepo/deployments?ref=mybranch # [{\"id\": \"${app_id}\", \"othervar\": \"54321\"},{\"id\": \"98765432101\", \"othervar\": \"12345\"}]" "@curl -X POST -H Accept: application/vnd.github.v3+json -H Authorization: token token12345 https://api.github.com/repos/myorg/myrepo/deployments/123456789/statuses -s -d {\"state\":\"success\", \"environment_url\": \"https://develop.testproject.com\"} # {\"state\": \"success\", \"othervar\": \"54321\"}" "Marked deployment as finished." "Finished GitHub notification for post_deployment event." diff --git a/.scaffold/tests/bats/workflow.utilities.bats b/.scaffold/tests/bats/workflow.utilities.bats index c770732c3..ed929e012 100644 --- a/.scaffold/tests/bats/workflow.utilities.bats +++ b/.scaffold/tests/bats/workflow.utilities.bats @@ -59,78 +59,6 @@ load _helper.workflow.bash assert_output_contains "Ahoy" } -@test "GitHub labels" { - prepare_sut "Starting utilities tests in build directory ${BUILD_DIR}" - - step "Run ahoy github-labels" - - export GITHUB_TOKEN="${TEST_GITHUB_TOKEN}" - - # Use "drevops/scaffold-destination" as an example GitHub project. - run ahoy github-labels drevops/scaffold-destination - assert_success - assert_output_not_contains "ERROR" - - run curl https://github.com/drevops/scaffold-destination/labels - assert_success - - assert_output_contains ">BLOCKED<" - assert_output_contains "Issue or pull request is blocked" - assert_output_contains ">PR: AUTOMERGE<" - assert_output_contains "Pull request has been approved and set to automerge" - assert_output_contains ">PR: CONFLICT<" - assert_output_contains "Pull request has a conflict that needs to be resolved before it can be merged" - assert_output_contains ">PR: Dependencies<" - assert_output_contains "Pull request was raised automatically by a dependency bot" - assert_output_contains ">PR: DO NOT MERGE<" - assert_output_contains "Do not merge this pull request" - assert_output_contains ">PR: Do not review<" - assert_output_contains "Do not review this pull request" - assert_output_contains ">PR: Needs review<" - assert_output_contains "Pull request needs a review from assigned developers" - assert_output_contains ">PR: Ready for test<" - assert_output_contains "Pull request is ready for manual testing" - assert_output_contains ">PR: Ready to be merged<" - assert_output_contains "Pull request is ready to be merged (assigned after testing is complete)" - assert_output_contains ">PR: Requires more work<" - assert_output_contains "Pull request was reviewed and reviver(s) asked to work further on the pull request" - assert_output_contains ">PR: URGENT<" - assert_output_contains "Pull request needs to be urgently reviewed" - assert_output_contains ">State: Confirmed<" - assert_output_contains "The issue was triaged and confirmed for development" - assert_output_contains ">State: Done<" - assert_output_contains "The issue is complete and waiting for a release" - assert_output_contains ">State: In progress<" - assert_output_contains "The issue is being worked on" - assert_output_contains ">State: Needs more info<" - assert_output_contains "The issue requires more information" - assert_output_contains ">State: Needs more work<" - assert_output_contains "The issue requires more work" - assert_output_contains ">State: Needs triage<" - assert_output_contains "An issue or PR has not been assessed and requires a triage" - assert_output_contains ">State: QA<" - assert_output_contains "The issue is in QA" - assert_output_contains ">Type: Chore<" - assert_output_contains "Issue is a related to a maintenance" - assert_output_contains ">Type: Defect<" - assert_output_contains "Issue is a defect" - assert_output_contains ">Type: Feature<" - assert_output_contains "Issue is a new feature request" - assert_output_contains ">Type: Question<" - assert_output_contains "Issue is a question" - assert_output_contains ">UPSTREAM<" - assert_output_contains "Issue or pull request is related to an upstream project" - - assert_output_not_contains ">bug<" - assert_output_not_contains ">duplicate<" - assert_output_not_contains ">enhancement<" - assert_output_not_contains ">help wanted<" - assert_output_not_contains ">good first issue<" - assert_output_not_contains ">invalid<" - assert_output_not_contains ">question<" - assert_output_not_contains ">wontfix<" -} - @test "Renovate - Check config" { prepare_sut "Starting utilities tests in build directory ${BUILD_DIR}" diff --git a/composer.json b/composer.json index 75daae8de..6f756c0f2 100644 --- a/composer.json +++ b/composer.json @@ -1,20 +1,10 @@ { "name": "your_org/your_site", "description": "Drupal 10 implementation of YOURSITE for YOURORG", - "type": "project", "license": "proprietary", - "repositories": [ - { - "type": "composer", - "url": "https://packages.drupal.org/8" - }, - { - "type": "composer", - "url": "https://asset-packagist.org" - } - ], + "type": "project", "require": { - "php": ">=8.2", + "php": ">=8.3", "composer/installers": "^2.2", "cweagans/composer-patches": "^1.7", "drupal/admin_toolbar": "^3.4", @@ -22,17 +12,17 @@ "drupal/coffee": "^1.4", "drupal/config_split": "^1.9", "drupal/config_update": "^2@alpha", - "drupal/core-composer-scaffold": "^10.2", - "drupal/core-recommended": "^10.2", + "drupal/core-composer-scaffold": "~10.3.0", + "drupal/core-recommended": "~10.3.0", "drupal/environment_indicator": "^4.0", "drupal/pathauto": "^1.12", "drupal/redirect": "^1.9", "drupal/redis": "^1.7", - "drupal/search_api": "^1.34", + "drupal/search_api": "^1.35", "drupal/search_api_solr": "^4.3", "drupal/shield": "^1.7", "drupal/stage_file_proxy": "^2.1", - "drush/drush": "^12.5", + "drush/drush": "~13.0", "oomphinc/composer-installers-extender": "^2.0", "vlucas/phpdotenv": "^5.6", "webflo/drupal-finder": "^1.2" @@ -43,8 +33,9 @@ "drevops/behat-format-progress-fail": "^1.2", "drevops/behat-screenshot": "^1.5", "drevops/behat-steps": "^2.3", - "drupal/core-dev": "^10.2", + "drupal/core-dev": "~10.3.0", "drupal/drupal-extension": "^5", + "ergebnis/composer-normalize": "^2.42", "mglaman/phpstan-drupal": "^1.2", "palantirnet/drupal-rector": "^0.20", "phpcompatibility/php-compatibility": "^9.3", @@ -57,65 +48,63 @@ "conflict": { "drupal/drupal": "*" }, - "minimum-stability": "stable", + "repositories": [ + { + "type": "composer", + "url": "https://packages.drupal.org/8" + }, + { + "type": "composer", + "url": "https://asset-packagist.org" + } + ], + "minimum-stability": "beta", "prefer-stable": true, + "autoload": { + "classmap": [ + "scripts/composer/ScriptHandler.php" + ] + }, + "autoload-dev": { + "classmap": [ + "tests/phpunit/" + ] + }, "config": { - "discard-changes": true, - "sort-packages": true, "allow-plugins": { "composer/installers": true, "cweagans/composer-patches": true, "dealerdirect/phpcodesniffer-composer-installer": true, "drupal/core-composer-scaffold": true, + "ergebnis/composer-normalize": true, "oomphinc/composer-installers-extender": true, "php-http/discovery": true, "phpstan/extension-installer": true, "pyrech/composer-changelogs": true }, + "discard-changes": true, "platform": { - "php": "8.2.18" - } - }, - "autoload": { - "classmap": [ - "scripts/composer/ScriptHandler.php" - ] - }, - "autoload-dev": { - "classmap": [ - "tests/phpunit/" - ] - }, - "scripts": { - "pre-install-cmd": [ - "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" - ], - "pre-update-cmd": [ - "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" - ], - "post-install-cmd": [ - "DrupalProject\\composer\\ScriptHandler::createRequiredFiles" - ], - "post-update-cmd": [ - "DrupalProject\\composer\\ScriptHandler::createRequiredFiles" - ] + "php": "8.3.9" + }, + "sort-packages": true }, "extra": { + "composer-exit-on-patch-failure": true, "drupal-scaffold": { - "locations": { - "web-root": "web/" - }, "file-mapping": { "[project-root]/.editorconfig": false, "[project-root]/.gitattributes": false, - "[web-root]/.htaccess": false, "[web-root]/.ht.router.php": false, - "[web-root]/example.gitignore": false, + "[web-root]/.htaccess": false, "[web-root]/INSTALL.txt": false, "[web-root]/README.txt": false, + "[web-root]/example.gitignore": false, "[web-root]/sites/example.settings.local.php": false, "[web-root]/sites/example.sites.php": false, "[web-root]/web.config": false + }, + "locations": { + "web-root": "web/" } }, "installer-paths": { @@ -123,8 +112,8 @@ "type:drupal-core" ], "web/libraries/{$name}": [ - "type:drupal-library", "type:bower-asset", + "type:drupal-library", "type:npm-asset" ], "web/modules/contrib/{$name}": [ @@ -140,9 +129,14 @@ "type:drupal-drush" ], "web/modules/custom/{$name}": [ + "type:drupal-custom-module", "type:drupal-custom-module" ], + "web/profiles/custom/{$name}": [ + "type:drupal-custom-profile" + ], "web/themes/custom/{$name}": [ + "type:drupal-custom-theme", "type:drupal-custom-theme" ] }, @@ -151,10 +145,23 @@ "npm-asset", "drupal-library" ], - "composer-exit-on-patch-failure": true, "patchLevel": { "drupal/core": "-p2" }, "patches": {} + }, + "scripts": { + "pre-install-cmd": [ + "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" + ], + "post-install-cmd": [ + "DrupalProject\\composer\\ScriptHandler::createRequiredFiles" + ], + "pre-update-cmd": [ + "DrupalProject\\composer\\ScriptHandler::checkComposerVersion" + ], + "post-update-cmd": [ + "DrupalProject\\composer\\ScriptHandler::createRequiredFiles" + ] } } diff --git a/docker-compose.yml b/docker-compose.yml index f6e9ab825..fe6d3ea6f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -62,6 +62,8 @@ x-environment: &default-environment CI: ${CI:-} # Forward emails to Mailhog locally. SSMTP_MAILHUB: ${SSMTP_MAILHUB:-host.docker.internal:1025} + # Path to configuration files. + DRUPAL_CONFIG_PATH: ${DRUPAL_CONFIG_PATH:-/app/config/default} # Drupal file paths. DRUPAL_PUBLIC_FILES: ${DRUPAL_PUBLIC_FILES:-/app/web/sites/default/files} DRUPAL_PRIVATE_FILES: ${DRUPAL_PRIVATE_FILES:-/app/web/sites/default/files/private} @@ -114,8 +116,9 @@ services: args: CLI_IMAGE: *cli-image WEBROOT: "${DREVOPS_WEBROOT:-web}" - DRUPAL_PUBLIC_FILES: ${DRUPAL_PUBLIC_FILES:-/app/${DREVOPS_WEBROOT:-web}/sites/default/files} - DRUPAL_PRIVATE_FILES: ${DRUPAL_PRIVATE_FILES:-/app/${DREVOPS_WEBROOT:-web}/sites/default/files/private} + DRUPAL_CONFIG_PATH: ${DRUPAL_CONFIG_PATH:-/app/config/default} + DRUPAL_PUBLIC_FILES: ${DRUPAL_PUBLIC_FILES:-/app/web/sites/default/files} + DRUPAL_PRIVATE_FILES: ${DRUPAL_PRIVATE_FILES:-/app/web/sites/default/files/private} DRUPAL_TEMPORARY_FILES: ${DRUPAL_TEMPORARY_FILES:-/tmp} <<: [*default-volumes, *default-user] environment: @@ -158,7 +161,7 @@ services: context: . dockerfile: .docker/mariadb.dockerfile args: - IMAGE: "${DREVOPS_DB_IMAGE:-uselagoon/mariadb-10.11-drupal:24.5.0}" # Use custom database image (if defined) or fallback to standard database image. + IMAGE: "${DREVOPS_DB_IMAGE:-uselagoon/mariadb-10.11-drupal:24.7.0}" # Use custom database image (if defined) or fallback to standard database image. <<: *default-user environment: <<: *default-environment @@ -171,7 +174,7 @@ services: #;< REDIS redis: - image: uselagoon/redis-6:24.5.0 + image: uselagoon/redis-6:24.7.0 #;< LAGOON labels: lagoon.type: redis # Change to 'none' if dedicated Redis service is used. See https://docs.lagoon.sh/using-lagoon-advanced/service-types/ @@ -232,7 +235,7 @@ services: # Helper container to wait for services to become available. wait_dependencies: - image: drevops/docker-wait-for-dependencies:24.3.0 + image: drevops/docker-wait-for-dependencies:24.7.0 depends_on: - cli - mariadb diff --git a/phpcs.xml b/phpcs.xml index 46847d7dc..d4989de17 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -20,7 +20,7 @@ - + circle\.yml diff --git a/rector.php b/rector.php index cbba12cfc..2d7cad968 100644 --- a/rector.php +++ b/rector.php @@ -12,16 +12,14 @@ declare(strict_types=1); -use DrupalFinder\DrupalFinder; +use DrupalFinder\DrupalFinderComposerRuntime; use DrupalRector\Set\Drupal10SetList; use DrupalRector\Set\Drupal8SetList; use DrupalRector\Set\Drupal9SetList; use Rector\CodeQuality\Rector\ClassMethod\InlineArrayReturnAssignRector; use Rector\CodeQuality\Rector\Empty_\SimplifyEmptyCheckOnEmptyArrayRector; use Rector\CodingStyle\Rector\ClassMethod\NewlineBeforeNewAssignSetRector; -use Rector\CodingStyle\Rector\FuncCall\ArraySpreadInsteadOfArrayMergeRector; use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector; -use Rector\CodingStyle\Rector\PostInc\PostIncDecToPreIncDecRector; use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector; use Rector\Config\RectorConfig; use Rector\DeadCode\Rector\If_\RemoveAlwaysTrueIfConditionRector; @@ -30,8 +28,7 @@ use Rector\TypeDeclaration\Rector\StmtsAwareInterface\DeclareStrictTypesRector; return static function (RectorConfig $rectorConfig): void { - $drupalFinder = new DrupalFinder(); - $drupalFinder->locateRoot(__DIR__); + $drupalFinder = new DrupalFinderComposerRuntime(); $drupalRoot = $drupalFinder->getDrupalRoot(); $rectorConfig->autoloadPaths([ @@ -69,13 +66,11 @@ $rectorConfig->skip([ // Rules added by Rector's rule sets. - ArraySpreadInsteadOfArrayMergeRector::class, CountArrayToEmptyArrayComparisonRector::class, DisallowedEmptyRuleFixerRector::class, InlineArrayReturnAssignRector::class, NewlineAfterStatementRector::class, NewlineBeforeNewAssignSetRector::class, - PostIncDecToPreIncDecRector::class, RemoveAlwaysTrueIfConditionRector::class, SimplifyEmptyCheckOnEmptyArrayRector::class, // Dependencies. diff --git a/scripts/drevops/notify-github.sh b/scripts/drevops/notify-github.sh index bbbe3b15d..24f55b259 100755 --- a/scripts/drevops/notify-github.sh +++ b/scripts/drevops/notify-github.sh @@ -84,7 +84,7 @@ if [ "${DREVOPS_NOTIFY_EVENT}" = "pre_deployment" ]; then deployment_id="$(echo "${payload}" | extract_json_value "id")" # Check deployment ID. - { [ "${#deployment_id}" != "9" ] || [ "$(expr "x${deployment_id}" : "x[0-9]*$")" -eq 0 ]; } && fail "Unable to get a deployment ID." && exit 1 + { [ "${#deployment_id}" -lt 9 ] || [ "${#deployment_id}" -gt 11 ] || [ "$(expr "x${deployment_id}" : "x[0-9]*$")" -eq 0 ]; } && fail "Failed to get a deployment ID for a started operation. Payload: ${payload}" && exit 1 note "Marked deployment as started." else @@ -101,7 +101,7 @@ else deployment_id="$(echo "${payload}" | extract_json_first_value "id")" # Check deployment ID. - { [ "${#deployment_id}" != "9" ] || [ "$(expr "x${deployment_id}" : "x[0-9]*$")" -eq 0 ]; } && fail "Unable to get a deployment ID." && exit 1 + { [ "${#deployment_id}" -lt 9 ] || [ "${#deployment_id}" -gt 11 ] || [ "$(expr "x${deployment_id}" : "x[0-9]*$")" -eq 0 ]; } && fail "Failed to get a deployment ID for a finished operation. Payload: ${payload}" && exit 1 # Post status update. payload="$(curl \ diff --git a/tests/phpunit/CircleCiConfigTest.php b/tests/phpunit/CircleCiConfigTest.php index 41c5717f3..2fa0ff0e3 100644 --- a/tests/phpunit/CircleCiConfigTest.php +++ b/tests/phpunit/CircleCiConfigTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use Drupal\Core\Serialization\Yaml; +use Drupal\Component\Serialization\Yaml; use PHPUnit\Framework\TestCase; /** @@ -52,7 +52,7 @@ public function testDeployBranchRegex(string $branch, bool $expected = TRUE): vo /** * Data provider for testDeployBranchRegex(). */ - public function dataProviderDeployBranchRegex(): array { + public static function dataProviderDeployBranchRegex(): array { return [ // Positive branches. ['main'], @@ -191,7 +191,7 @@ public function testDeployTagRegex(string $branch, bool $expected = TRUE): void /** * Data provider for testDeployTagRegex(). */ - public function dataProviderDeployTagRegex(): array { + public static function dataProviderDeployTagRegex(): array { return [ // Positive tags. ['1.2.3'], diff --git a/tests/phpunit/Drupal/DatabaseSettingsTest.php b/tests/phpunit/Drupal/DatabaseSettingsTest.php index f70864117..843ae196f 100644 --- a/tests/phpunit/Drupal/DatabaseSettingsTest.php +++ b/tests/phpunit/Drupal/DatabaseSettingsTest.php @@ -29,7 +29,7 @@ public function testDatabases(array $vars, array $expected): void { /** * Data provider for resulting database settings. */ - public function dataProviderDatabases(): array { + public static function dataProviderDatabases(): array { return [ [ [], diff --git a/tests/phpunit/Drupal/EnvironmentSettingsTest.php b/tests/phpunit/Drupal/EnvironmentSettingsTest.php index fddf41dea..271779723 100644 --- a/tests/phpunit/Drupal/EnvironmentSettingsTest.php +++ b/tests/phpunit/Drupal/EnvironmentSettingsTest.php @@ -254,7 +254,7 @@ public function testEnvironmentGeneric(): void { $this->assertConfig($config); $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_SUT; @@ -269,6 +269,7 @@ public function testEnvironmentGeneric(): void { '^.+\.docker\.amazee\.io$', '^nginx$', ]; + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } @@ -298,7 +299,7 @@ public function testEnvironmentLocal(): void { $this->assertConfig($config); $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_LOCAL; @@ -314,6 +315,7 @@ public function testEnvironmentLocal(): void { '^.+\.docker\.amazee\.io$', '^nginx$', ]; + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } @@ -342,7 +344,7 @@ public function testEnvironmentCi(): void { $this->assertConfig($config); $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_CI; @@ -359,7 +361,7 @@ public function testEnvironmentCi(): void { '^.+\.docker\.amazee\.io$', '^nginx$', ]; - + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } @@ -389,7 +391,7 @@ public function testEnvironmentAcquiaDynamic(): void { $this->assertConfig($config); $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_DEV; @@ -402,6 +404,7 @@ public function testEnvironmentAcquiaDynamic(): void { $settings['hash_salt'] = hash('sha256', getenv('MARIADB_HOST') ?: 'localhost'); $settings['trusted_host_patterns'][] = '^.+\.docker\.amazee\.io$'; $settings['trusted_host_patterns'][] = '^nginx$'; + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } @@ -430,7 +433,7 @@ public function testEnvironmentAcquiaDev(): void { $this->assertConfig($config); $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_DEV; @@ -443,6 +446,7 @@ public function testEnvironmentAcquiaDev(): void { $settings['hash_salt'] = hash('sha256', getenv('MARIADB_HOST') ?: 'localhost'); $settings['trusted_host_patterns'][] = '^.+\.docker\.amazee\.io$'; $settings['trusted_host_patterns'][] = '^nginx$'; + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } @@ -471,7 +475,7 @@ public function testEnvironmentAcquiaTest(): void { $this->assertConfig($config); $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_TEST; @@ -484,6 +488,7 @@ public function testEnvironmentAcquiaTest(): void { $settings['hash_salt'] = hash('sha256', getenv('MARIADB_HOST') ?: 'localhost'); $settings['trusted_host_patterns'][] = '^.+\.docker\.amazee\.io$'; $settings['trusted_host_patterns'][] = '^nginx$'; + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } @@ -510,7 +515,7 @@ public function testEnvironmentAcquiaProd(): void { $this->assertConfig($config); $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_PROD; @@ -523,6 +528,7 @@ public function testEnvironmentAcquiaProd(): void { $settings['hash_salt'] = hash('sha256', getenv('MARIADB_HOST') ?: 'localhost'); $settings['trusted_host_patterns'][] = '^.+\.docker\.amazee\.io$'; $settings['trusted_host_patterns'][] = '^nginx$'; + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } // phpcs:ignore #;> ACQUIA @@ -557,7 +563,7 @@ public function testEnvironmentLagoonDynamic(): void { $settings['cache_prefix']['default'] = 'test_project_test_branch'; $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_DEV; @@ -575,6 +581,7 @@ public function testEnvironmentLagoonDynamic(): void { $settings['trusted_host_patterns'][] = '^nginx\-php$'; $settings['trusted_host_patterns'][] = '^.+\.au\.amazee\.io$'; $settings['trusted_host_patterns'][] = '^example1\.com|example2/com$'; + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } @@ -608,7 +615,7 @@ public function testEnvironmentLagoonDev(): void { $settings['cache_prefix']['default'] = 'test_project_develop'; $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_DEV; @@ -626,6 +633,7 @@ public function testEnvironmentLagoonDev(): void { $settings['trusted_host_patterns'][] = '^nginx\-php$'; $settings['trusted_host_patterns'][] = '^.+\.au\.amazee\.io$'; $settings['trusted_host_patterns'][] = '^example1\.com|example2/com$'; + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } @@ -659,7 +667,7 @@ public function testEnvironmentLagoonTest(): void { $settings['cache_prefix']['default'] = 'test_project_master'; $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_TEST; @@ -677,6 +685,7 @@ public function testEnvironmentLagoonTest(): void { $settings['trusted_host_patterns'][] = '^nginx\-php$'; $settings['trusted_host_patterns'][] = '^.+\.au\.amazee\.io$'; $settings['trusted_host_patterns'][] = '^example1\.com|example2/com$'; + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } @@ -709,7 +718,7 @@ public function testEnvironmentLagoonProd(): void { $settings['cache_prefix']['default'] = 'test_project_production'; $settings['config_exclude_modules'] = []; - $settings['config_sync_directory'] = '../config/default'; + $settings['config_sync_directory'] = static::CONFIG_PATH_TESTING; $settings['container_yamls'][0] = $this->app_root . '/' . $this->site_path . '/services.yml'; $settings['entity_update_batch_size'] = 50; $settings['environment'] = static::ENVIRONMENT_PROD; @@ -727,6 +736,7 @@ public function testEnvironmentLagoonProd(): void { $settings['trusted_host_patterns'][] = '^nginx\-php$'; $settings['trusted_host_patterns'][] = '^.+\.au\.amazee\.io$'; $settings['trusted_host_patterns'][] = '^example1\.com|example2/com$'; + $settings['state_cache'] = TRUE; $this->assertSettings($settings); } // phpcs:ignore #;> LAGOON diff --git a/tests/phpunit/Drupal/SettingsTestCase.php b/tests/phpunit/Drupal/SettingsTestCase.php index 41b5ae065..e9cda0cb6 100644 --- a/tests/phpunit/Drupal/SettingsTestCase.php +++ b/tests/phpunit/Drupal/SettingsTestCase.php @@ -59,6 +59,11 @@ abstract class SettingsTestCase extends TestCase { */ final const PRIVATE_PATH_TESTING = '/private-test'; + /** + * Defines a constant for the config directory used in testing. + */ + final const CONFIG_PATH_TESTING = '/config-test'; + /** * Application root. * @@ -127,6 +132,7 @@ protected function setEnvVars(array $vars): void { $vars['LAGOON'] = FALSE; } + $vars['DRUPAL_CONFIG_PATH'] = static::CONFIG_PATH_TESTING; $vars['DRUPAL_TEMPORARY_FILES'] = static::TMP_PATH_TESTING; $vars['DRUPAL_PRIVATE_FILES'] = static::PRIVATE_PATH_TESTING; diff --git a/tests/phpunit/Drupal/SwitchableSettingsTest.php b/tests/phpunit/Drupal/SwitchableSettingsTest.php index d5d469d05..0170ec44a 100644 --- a/tests/phpunit/Drupal/SwitchableSettingsTest.php +++ b/tests/phpunit/Drupal/SwitchableSettingsTest.php @@ -92,7 +92,7 @@ public function testConfigSplit(string $env, array $expected_present, array $exp /** * Data provider for testConfigSplit(). */ - public function dataProviderConfigSplit(): array { + public static function dataProviderConfigSplit(): array { return [ [ static::ENVIRONMENT_LOCAL, @@ -180,7 +180,7 @@ public function testEnvironmentIndicator(string $env, array $expected_present, a /** * Data provider for testEntityPrint(). */ - public function dataProviderEnvironmentIndicator(): array { + public static function dataProviderEnvironmentIndicator(): array { return [ [ static::ENVIRONMENT_LOCAL, @@ -292,7 +292,7 @@ public function testShield(string $env, array $vars, array $expected_present, ar /** * Data provider for testShield(). */ - public function dataProviderShield(): array { + public static function dataProviderShield(): array { return [ [ static::ENVIRONMENT_LOCAL, @@ -410,7 +410,7 @@ public function testStageFileProxy(string $env, array $vars, array $expected_pre /** * Data provider for testStageFileProxy(). */ - public function dataProviderStageFileProxy(): array { + public static function dataProviderStageFileProxy(): array { return [ [ static::ENVIRONMENT_LOCAL, diff --git a/web/modules/custom/ys_core/tests/src/Kernel/ExampleTest.php b/web/modules/custom/ys_core/tests/src/Kernel/ExampleTest.php index 04f4df22a..5585090ec 100644 --- a/web/modules/custom/ys_core/tests/src/Kernel/ExampleTest.php +++ b/web/modules/custom/ys_core/tests/src/Kernel/ExampleTest.php @@ -36,7 +36,7 @@ public function testAdd(int $a, int $b, int $expected, string|null $expectExcept /** * Data provider for testAdd(). */ - public function dataProviderAdd(): array { + public static function dataProviderAdd(): array { return [ [0, 0, 0], [1, 1, 2], @@ -64,7 +64,7 @@ public function testSubtract(int $a, int $b, int $expected, string|null $expectE /** * Data provider for testSubtract(). */ - public function dataProviderSubtract(): array { + public static function dataProviderSubtract(): array { return [ [0, 0, 0], [1, 1, 0], @@ -94,7 +94,7 @@ public function testMultiplication(int $a, int $b, int $expected, string|null $e /** * Data provider for testMultiplication(). */ - public function dataProviderMultiplication(): array { + public static function dataProviderMultiplication(): array { return [ [0, 0, 0], [1, 1, 1], diff --git a/web/modules/custom/ys_core/tests/src/Traits/ReflectionTrait.php b/web/modules/custom/ys_core/tests/src/Traits/ReflectionTrait.php index a12bfa650..60bc531da 100644 --- a/web/modules/custom/ys_core/tests/src/Traits/ReflectionTrait.php +++ b/web/modules/custom/ys_core/tests/src/Traits/ReflectionTrait.php @@ -64,15 +64,8 @@ protected static function callProtectedMethod(object|string $object, string $nam /** * Set protected property value. - * - * @param object $object - * Object to set the value on. - * @param string $property - * Property name to set the value. Property should exists in the object. - * @param mixed $value - * Value to set to the property. */ - protected static function setProtectedValue($object, $property, mixed $value): void { + protected static function setProtectedValue(object $object, string $property, mixed $value): void { $class = new \ReflectionClass($object::class); $property = $class->getProperty($property); $property->setAccessible(TRUE); diff --git a/web/modules/custom/ys_core/tests/src/Unit/ExampleTest.php b/web/modules/custom/ys_core/tests/src/Unit/ExampleTest.php index ea13844df..fbcc09965 100644 --- a/web/modules/custom/ys_core/tests/src/Unit/ExampleTest.php +++ b/web/modules/custom/ys_core/tests/src/Unit/ExampleTest.php @@ -36,7 +36,7 @@ public function testAdd(int $a, int $b, int $expected, string|null $expectExcept /** * Data provider for testAdd(). */ - public function dataProviderAdd(): array { + public static function dataProviderAdd(): array { return [ [0, 0, 0], [1, 1, 2], @@ -64,7 +64,7 @@ public function testSubtract(int $a, int $b, int $expected, string|null $expectE /** * Data provider for testSubtract(). */ - public function dataProviderSubtract(): array { + public static function dataProviderSubtract(): array { return [ [0, 0, 0], [1, 1, 0], @@ -94,7 +94,7 @@ public function testMultiplication(int $a, int $b, int $expected, string|null $e /** * Data provider for testMultiplication(). */ - public function dataProviderMultiplication(): array { + public static function dataProviderMultiplication(): array { return [ [0, 0, 0], [1, 1, 1], diff --git a/web/sites/default/default.services.yml b/web/sites/default/default.services.yml index c4b964fc2..dacb3f7e9 100644 --- a/web/sites/default/default.services.yml +++ b/web/sites/default/default.services.yml @@ -1,4 +1,8 @@ parameters: + # Toggles the super user access policy. If your website has at least one user + # with the Administrator role, it is advised to set this to false. This allows + # you to make user 1 a regular user, strengthening the security of your site. + security.enable_super_user: true session.storage.options: # Default ini options for sessions. # @@ -60,6 +64,11 @@ parameters: # \Drupal\Core\Session\SessionConfiguration::__construct() # @default 6 sid_bits_per_character: 6 + # By default, Drupal generates a session cookie name based on the full + # domain name. Set the name_suffix to a short random string to ensure this + # session cookie name is unique on different installations on the same + # domain and path (for example, when migrating from Drupal 7). + name_suffix: '' twig.config: # Twig debugging: # diff --git a/web/sites/default/default.settings.local.php b/web/sites/default/default.settings.local.php index 41cbec563..85f6a6474 100644 --- a/web/sites/default/default.settings.local.php +++ b/web/sites/default/default.settings.local.php @@ -25,3 +25,6 @@ // Hide admin toolbar. Useful for themeing while logged in as admin. // $settings['hide_admin_toolbar'] = TRUE; + +// Disable state cache. +$settings['state_cache'] = FALSE; diff --git a/web/sites/default/default.settings.php b/web/sites/default/default.settings.php index 8819d6431..264597b16 100644 --- a/web/sites/default/default.settings.php +++ b/web/sites/default/default.settings.php @@ -77,7 +77,7 @@ * * @code * $databases['default']['default'] = [ - * 'database' => 'databasename', + * 'database' => 'database_name', * 'username' => 'sql_username', * 'password' => 'sql_password', * 'host' => 'localhost', @@ -193,7 +193,7 @@ * @code * $databases['default']['default'] = [ * 'driver' => 'pgsql', - * 'database' => 'databasename', + * 'database' => 'database_name', * 'username' => 'sql_username', * 'password' => 'sql_password', * 'host' => 'localhost', @@ -215,7 +215,7 @@ * 'driver' => 'my_driver', * 'namespace' => 'Drupal\my_module\Driver\Database\my_driver', * 'autoload' => 'modules/my_module/src/Driver/Database/my_driver/', - * 'database' => 'databasename', + * 'database' => 'database_name', * 'username' => 'sql_username', * 'password' => 'sql_password', * 'host' => 'localhost', @@ -230,7 +230,7 @@ * 'driver' => 'my_driver', * 'namespace' => 'Drupal\my_module\Driver\Database\my_driver', * 'autoload' => 'modules/my_module/src/Driver/Database/my_driver/', - * 'database' => 'databasename', + * 'database' => 'database_name', * 'username' => 'sql_username', * 'password' => 'sql_password', * 'host' => 'localhost', @@ -355,14 +355,13 @@ * security, or encryption benefits. In an environment where Drupal * is behind a reverse proxy, the real IP address of the client should * be determined such that the correct client IP address is available - * to Drupal's logging, statistics, and access management systems. In - * the most simple scenario, the proxy server will add an - * X-Forwarded-For header to the request that contains the client IP - * address. However, HTTP headers are vulnerable to spoofing, where a - * malicious client could bypass restrictions by setting the - * X-Forwarded-For header directly. Therefore, Drupal's proxy - * configuration requires the IP addresses of all remote proxies to be - * specified in $settings['reverse_proxy_addresses'] to work correctly. + * to Drupal's logging and access management systems. In the most simple + * scenario, the proxy server will add an X-Forwarded-For header to the request + * that contains the client IP address. However, HTTP headers are vulnerable to + * spoofing, where a malicious client could bypass restrictions by setting the + * X-Forwarded-For header directly. Therefore, Drupal's proxy configuration + * requires the IP addresses of all remote proxies to be specified in + * $settings['reverse_proxy_addresses'] to work correctly. * * Enable this setting to get Drupal to determine the client IP from the * X-Forwarded-For header. If you are unsure about this setting, do not have a @@ -808,6 +807,16 @@ */ $settings['entity_update_backup'] = TRUE; +/** + * State caching. + * + * State caching uses the cache collector pattern to cache all requested keys + * from the state API in a single cache entry, which can greatly reduce the + * amount of database queries. However, some sites may use state with a + * lot of dynamic keys which could result in a very large cache. + */ +$settings['state_cache'] = TRUE; + /** * Node migration type. * diff --git a/web/sites/default/settings.php b/web/sites/default/settings.php index 8cf777a48..82e8b62c1 100644 --- a/web/sites/default/settings.php +++ b/web/sites/default/settings.php @@ -58,7 +58,7 @@ $settings['container_yamls'][] = $app_root . '/' . $site_path . '/services.yml'; // Location of the site configuration files. -$settings['config_sync_directory'] = '../config/default'; +$settings['config_sync_directory'] = getenv('DRUPAL_CONFIG_PATH') ?: '../config/default'; // Private directory. $settings['file_private_path'] = getenv('DRUPAL_PRIVATE_FILES') ?: 'sites/default/files/private'; @@ -76,6 +76,9 @@ $config['system.performance']['css']['preprocess'] = TRUE; $config['system.performance']['js']['preprocess'] = TRUE; +// Enable state cache. +$settings['state_cache'] = TRUE; + // The default list of directories that will be ignored by Drupal's file API. $settings['file_scan_ignore_directories'] = [ 'node_modules', diff --git a/web/themes/custom/your_site_theme/tests/src/Kernel/ExampleTest.php b/web/themes/custom/your_site_theme/tests/src/Kernel/ExampleTest.php index 644b139f7..d135ce801 100644 --- a/web/themes/custom/your_site_theme/tests/src/Kernel/ExampleTest.php +++ b/web/themes/custom/your_site_theme/tests/src/Kernel/ExampleTest.php @@ -36,7 +36,7 @@ public function testAdd(int $a, int $b, int $expected, string|null $expectExcept /** * Data provider for testAdd(). */ - public function dataProviderAdd(): array { + public static function dataProviderAdd(): array { return [ [0, 0, 0], [1, 1, 2], @@ -65,7 +65,7 @@ public function testSubtract(int $a, int $b, int $expected, string|null $expectE /** * Data provider for testSubtract(). */ - public function dataProviderSubtract(): array { + public static function dataProviderSubtract(): array { return [ [0, 0, 0], [1, 1, 0], @@ -96,7 +96,7 @@ public function testMultiplication(int $a, int $b, int $expected, string|null $e /** * Data provider for testMultiplication(). */ - public function dataProviderMultiplication(): array { + public static function dataProviderMultiplication(): array { return [ [0, 0, 0], [1, 1, 1], diff --git a/web/themes/custom/your_site_theme/tests/src/Unit/ExampleTest.php b/web/themes/custom/your_site_theme/tests/src/Unit/ExampleTest.php index 914a7d759..523901d0f 100644 --- a/web/themes/custom/your_site_theme/tests/src/Unit/ExampleTest.php +++ b/web/themes/custom/your_site_theme/tests/src/Unit/ExampleTest.php @@ -36,7 +36,7 @@ public function testAdd(int $a, int $b, int $expected, string|null $expectExcept /** * Data provider for testAdd(). */ - public function dataProviderAdd(): array { + public static function dataProviderAdd(): array { return [ [0, 0, 0], [1, 1, 2], @@ -65,7 +65,7 @@ public function testSubtract(int $a, int $b, int $expected, string|null $expectE /** * Data provider for testSubtract(). */ - public function dataProviderSubtract(): array { + public static function dataProviderSubtract(): array { return [ [0, 0, 0], [1, 1, 0], @@ -96,7 +96,7 @@ public function testMultiplication(int $a, int $b, int $expected, string|null $e /** * Data provider for testMultiplication(). */ - public function dataProviderMultiplication(): array { + public static function dataProviderMultiplication(): array { return [ [0, 0, 0], [1, 1, 1],