diff --git a/README.md b/README.md index 0929471..5d64f72 100644 --- a/README.md +++ b/README.md @@ -10,18 +10,19 @@ The recommended way to set up Drupal core for development is with the Composer project template `joachim-n/drupal-core-development-project`. This addon can also be used with Drupal installed directly on a git clone of core. -``` +``` bash +# Use either of step 1A or 1B. # 1A: Install with Composer project template (recommended) # If you already installed a project using the template following the # instructions in its README then skip to step 2. -ddev config --project-type=drupal --php-version=8.3 +ddev config --project-type=drupal --docroot=web --php-version=8.3 ddev start ddev composer create joachim-n/drupal-core-development-project ddev config --update ddev restart -# 1B: Install directly on a git clone -git clone https://git.drupalcode.org/project/drupal.git drupal +# 1B: Install directly on a git clone (advanced) +git clone --branch=11.x https://git.drupalcode.org/project/drupal.git drupal cd drupal ddev config --disable-settings-management ddev start @@ -36,11 +37,24 @@ ddev drush si -y --account-pass==admin ## Running tests -### PHPUnit tests +### DDEV Commands Usage +```bash +ddev phpcs core/modules/user/src/RegisterForm.php (from repos/drupal directory) +ddev phpcbf core/modules/user/src/RegisterForm.php (from repos/drupal directory) +ddev phpstan core/modules/user/src/RegisterForm.php (from repos/drupal directory) +ddev phpunit core/modules/user/tests/src/Functional/UserAdminTest.php (from repos/drupal directory) +ddev code-check (ddev equivalent of running sh core/scripts/dev/commit-code-check.sh) +ddev cspell-check (Checks for forbidden and new words which are not present in dictonary) +ddev install (Installs new site) +ddev drush [arguments] (from project root) ``` + +### PHPUnit tests + +```bash # Run PHPUnit tests -ddev phpunit web/core/modules/sdc +ddev phpunit core/modules/sdc ``` ### Nightwatch tests @@ -50,42 +64,50 @@ for Chrome and https://drupal.ddev.site:7901 for Firefox. The password is "secret". YMMV using Firefox as core tests don't currently run on it. Only core tests -``` + +```bash ddev nightwatch --tag core ``` Skip running core tests -``` + +```bash ddev nightwatch --skiptags core ``` Run a single test -``` + +```bash ddev nightwatch tests/Drupal/Nightwatch/Tests/exampleTest.js ``` a11y tests for both the admin and default themes -``` + +```bash ddev nightwatch --tag a11y ``` a11y tests for the admin theme only -``` + +```bash ddev nightwatch --tag a11y:admin ``` a11y tests for the default theme only -``` + +```bash ddev nightwatch --tag a11y:default ``` a11y test for a custom theme used as the default theme -``` + +```bash ddev nightwatch --tag a11y:default --defaultTheme bartik ``` a11y test for a custom admin theme -``` + +```bash ddev nightwatch --tag a11y:admin --adminTheme seven ``` @@ -93,7 +115,7 @@ ddev nightwatch --tag a11y:admin --adminTheme seven This will run static tests against core standards. -``` +``` bash ddev drupal lint:phpstan ddev drupal lint:phpcs ddev drupal lint:js diff --git a/commands/web/code-check b/commands/web/code-check new file mode 100755 index 0000000..3ff81ff --- /dev/null +++ b/commands/web/code-check @@ -0,0 +1,543 @@ +#!/bin/bash + +#ddev-generated + +## Description: This script performs code quality checks. +## Usage: code-check [flags] +## Example: "ddev code-check" or "ddev code-check --cached" + +# This script performs code quality checks. +# +# @internal +# This script is not covered by Drupal core's backwards compatibility promise. +# It exists only for core development purposes. +# +# The script makes the following checks: +# - Spell checking. +# - File modes. +# - No changes to core/node_modules directory. +# - PHPCS checks PHP and YAML files. +# - PHPStan checks PHP files. +# - ESLint checks JavaScript and YAML files. +# - Stylelint checks CSS files. +# - Checks .pcss.css and .css files are equivalent. + +# cSpell:disable + +TOP_LEVEL="/var/www/html/repos/drupal" +cd $TOP_LEVEL/core + +printf "\033[0;33mIf you have just started DDEV wait for couple of minutes \n" +printf "before using {ddev code-check} command, mutagen file sync of \n" +printf "node_modules takes time.\n\033[0m" + +corepack enable + +echo "NPM Version :" +npm --version + +echo "Yarn Version :" +yarn --version + +# Installs dependencies if not already run. +if [ ! -d /var/www/html/repos/drupal/core/node_modules/.bin ]; then + + corepack enable + + yarn --cwd /var/www/html/repos/drupal/core install + +fi + +cd $TOP_LEVEL + +# Searches an array. +contains_element() { + local e + for e in ${@:2}; do [[ "$e" == "$1" ]] && return 0; done + return 1 +} + +CACHED=0 +DRUPALCI=0 +BRANCH="" +while test $# -gt 0; do + case "$1" in + -h|--help) + echo "Drupal code quality checks" + echo " " + echo "options:" + echo "-h, --help show brief help" + echo "--branch BRANCH creates list of files to check by comparing against a branch" + echo "--cached checks staged files" + echo "--drupalci a special mode for DrupalCI" + echo " " + echo "Example usage: sh ./core/scripts/dev/commit-code-check.sh --branch 9.2.x" + exit 0 + ;; + --branch) + BRANCH="$2" + if [[ "$BRANCH" == "" ]]; then + printf "The --branch option requires a value. For example: --branch 9.2.x\n" + exit; + fi + shift 2 + ;; + --cached) + CACHED=1 + shift + ;; + --drupalci) + DRUPALCI=1 + shift + ;; + *) + break + ;; + esac +done + +# Set up variables to make colored output simple. Color output is disabled on +# DrupalCI because it is breaks reporting. +# @todo https://www.drupal.org/project/drupalci_testbot/issues/3181869 +if [[ "$DRUPALCI" == "1" ]]; then + red="" + green="" + reset="" + DRUPAL_VERSION=$(php -r "include 'vendor/autoload.php'; print preg_replace('#\.[0-9]+-dev#', '.x', \Drupal::VERSION);") + GIT="sudo -u www-data git" +else + red=$(tput setaf 1 && tput bold) + green=$(tput setaf 2) + reset=$(tput sgr0) + GIT="git" +fi + +# Gets list of files to check. +if [[ "$BRANCH" != "" ]]; then + FILES=$($GIT diff --name-only $BRANCH HEAD); +elif [[ "$CACHED" == "0" ]]; then + # For DrupalCI patch testing or when running without --cached or --branch, + # list of all changes in the working directory. + FILES=$($GIT ls-files --other --modified --exclude-standard --exclude=vendor --exclude=node_modules --exclude=sites --exclude=*.patch --exclude=*.diff --exclude=.DS_Store) +else + # Check staged files only. + if $GIT rev-parse --verify HEAD >/dev/null 2>&1 + then + AGAINST=HEAD + else + # Initial commit: diff against an empty tree object + AGAINST=4b825dc642cb6eb9a060e54bf8d69288fbee4904 + fi + FILES=$($GIT diff --cached --name-only $AGAINST); +fi + +if [[ "$FILES" == "" ]] && [[ "$DRUPALCI" == "1" ]]; then + # If the FILES is empty we might be testing a merge request on DrupalCI. We + # need to diff against the Drupal branch or tag related to the Drupal version. + printf "Creating list of files to check by comparing branch to %s\n" "$DRUPAL_VERSION" + # On DrupalCI there's a merge commit so we can compare to HEAD~1. + FILES=$($GIT diff --name-only HEAD~1 HEAD); +fi + +TOP_LEVEL=$($GIT rev-parse --show-toplevel) + +# This variable will be set to one when the file core/phpcs.xml.dist is changed. +PHPCS_XML_DIST_FILE_CHANGED=0 + +# This variable will be set to one when the files core/.phpstan-baseline.php or +# core/phpstan.neon.dist are changed. +PHPSTAN_DIST_FILE_CHANGED=0 + +# This variable will be set to one when one of the eslint config file is +# changed: +# - core/.eslintrc.passing.json +# - core/.eslintrc.json +# - core/.eslintrc.jquery.json +ESLINT_CONFIG_PASSING_FILE_CHANGED=0 + +# This variable will be set to one when the stylelint config file is changed. +# changed: +# - core/.stylelintignore +# - core/.stylelintrc.json +STYLELINT_CONFIG_FILE_CHANGED=0 + +# This variable will be set to one when JavaScript packages files are changed. +# changed: +# - core/package.json +# - core/yarn.lock +JAVASCRIPT_PACKAGES_CHANGED=0 + +# This variable will be set when a Drupal-specific CKEditor 5 plugin has changed +# it is used to make sure the compiled JS is valid. +CKEDITOR5_PLUGINS_CHANGED=0 + +# This variable will be set to when the dictionary has changed. +CSPELL_DICTIONARY_FILE_CHANGED=0 + +# Build up a list of absolute file names. +ABS_FILES= +for FILE in $FILES; do + if [ -f "$TOP_LEVEL/$FILE" ]; then + ABS_FILES="$ABS_FILES $TOP_LEVEL/$FILE" + fi + + if [[ $FILE == "core/phpcs.xml.dist" ]]; then + PHPCS_XML_DIST_FILE_CHANGED=1; + fi; + + if [[ $FILE == "core/.phpstan-baseline.php" || $FILE == "core/phpstan.neon.dist" ]]; then + PHPSTAN_DIST_FILE_CHANGED=1; + fi; + + if [[ $FILE == "core/.eslintrc.json" || $FILE == "core/.eslintrc.passing.json" || $FILE == "core/.eslintrc.jquery.json" ]]; then + ESLINT_CONFIG_PASSING_FILE_CHANGED=1; + fi; + + if [[ $FILE == "core/.stylelintignore" || $FILE == "core/.stylelintrc.json" ]]; then + STYLELINT_CONFIG_FILE_CHANGED=1; + fi; + + # If JavaScript packages change, then rerun all JavaScript style checks. + if [[ $FILE == "core/package.json" || $FILE == "core/yarn.lock" ]]; then + ESLINT_CONFIG_PASSING_FILE_CHANGED=1; + STYLELINT_CONFIG_FILE_CHANGED=1; + JAVASCRIPT_PACKAGES_CHANGED=1; + fi; + + if [[ -f "$TOP_LEVEL/$FILE" ]] && [[ $FILE =~ \.js$ ]] && [[ $FILE =~ ^core/modules/ckeditor5/js/build || $FILE =~ ^core/modules/ckeditor5/js/ckeditor5_plugins ]]; then + CKEDITOR5_PLUGINS_CHANGED=1; + fi; + + if [[ $FILE == "core/misc/cspell/dictionary.txt" || $FILE == "core/misc/cspell/drupal-dictionary.txt" ]]; then + CSPELL_DICTIONARY_FILE_CHANGED=1; + fi +done + +# Exit early if there are no files. +if [[ "$ABS_FILES" == "" ]]; then + printf "There are no files to check. If you have staged a commit use the --cached option.\n" + exit; +fi; + +# This script assumes that composer install and yarn install have already been +# run and all dependencies are updated. +FINAL_STATUS=0 + +DEPENDENCIES_NEED_INSTALLING=0 +# Ensure PHP development dependencies are installed. +# @todo https://github.com/composer/composer/issues/4497 Improve this to +# determine if dependencies in the lock file match the installed versions. +# Using composer install --dry-run is not valid because it would depend on +# user-facing strings in Composer. +if ! [[ -f 'vendor/bin/phpcs' ]]; then + printf "Drupal's PHP development dependencies are not installed. Run 'composer install' from the root directory.\n" + DEPENDENCIES_NEED_INSTALLING=1; +fi + +cd "$TOP_LEVEL/core" + +# Ensure JavaScript development dependencies are installed. +yarn --version +yarn >/dev/null + +# Check all files for spelling in one go for better performance. +if [[ $CSPELL_DICTIONARY_FILE_CHANGED == "1" ]] ; then + printf "\nRunning spellcheck on *all* files.\n" + yarn run spellcheck:core --no-must-find-files --no-progress +else + # Check all files for spelling in one go for better performance. We pipe the + # list files in so we obey the globs set on the spellcheck:core command in + # core/package.json. + echo "${ABS_FILES}" | tr ' ' '\n' | yarn run spellcheck:core --no-must-find-files --file-list stdin +fi + +if [ "$?" -ne "0" ]; then + # If there are failures set the status to a number other than 0. + FINAL_STATUS=1 + printf "\nCSpell: ${red}failed${reset}\n" +else + printf "\nCSpell: ${green}passed${reset}\n" +fi +cd "$TOP_LEVEL" + +# Add a separator line to make the output easier to read. +printf "\n" +printf -- '-%.0s' {1..100} +printf "\n" + +# Run PHPStan on all files on DrupalCI or when phpstan files are changed. +# APCu is disabled to ensure that the composer classmap is not corrupted. +if [[ $PHPSTAN_DIST_FILE_CHANGED == "1" ]] || [[ "$DRUPALCI" == "1" ]]; then + printf "\nRunning PHPStan on *all* files.\n" + php -d apc.enabled=0 -d apc.enable_cli=0 vendor/bin/phpstan analyze --no-progress --configuration="$TOP_LEVEL/core/phpstan.neon.dist" +else + # Only run PHPStan on changed files locally. + printf "\nRunning PHPStan on changed files.\n" + php -d apc.enabled=0 -d apc.enable_cli=0 vendor/bin/phpstan analyze --memory-limit=2G --no-progress --configuration="$TOP_LEVEL/core/phpstan-partial.neon" $ABS_FILES +fi + +if [ "$?" -ne "0" ]; then + # If there are failures set the status to a number other than 0. + FINAL_STATUS=1 + printf "\nPHPStan: ${red}failed${reset}\n" +else + printf "\nPHPStan: ${green}passed${reset}\n" +fi + +# Add a separator line to make the output easier to read. +printf "\n" +printf -- '-%.0s' {1..100} +printf "\n" + +# Run PHPCS on all files on DrupalCI or when phpcs files are changed. +if [[ $PHPCS_XML_DIST_FILE_CHANGED == "1" ]] || [[ "$DRUPALCI" == "1" ]]; then + # Test all files with phpcs rules. + vendor/bin/phpcs -ps --parallel="$( (nproc || sysctl -n hw.logicalcpu || echo 4) 2>/dev/null)" --standard="$TOP_LEVEL/core/phpcs.xml.dist" + PHPCS=$? + if [ "$PHPCS" -ne "0" ]; then + # If there are failures set the status to a number other than 0. + FINAL_STATUS=1 + printf "\nPHPCS: ${red}failed${reset}\n" + else + printf "\nPHPCS: ${green}passed${reset}\n" + fi + # Add a separator line to make the output easier to read. + printf "\n" + printf -- '-%.0s' {1..100} + printf "\n" +fi + +# When the eslint config has been changed, then eslint must check all files. +if [[ $ESLINT_CONFIG_PASSING_FILE_CHANGED == "1" ]]; then + cd "$TOP_LEVEL/core" + yarn run lint:core-js-passing "$TOP_LEVEL/core" + CORRECTJS=$? + if [ "$CORRECTJS" -ne "0" ]; then + # If there are failures set the status to a number other than 0. + FINAL_STATUS=1 + printf "\neslint: ${red}failed${reset}\n" + else + printf "\neslint: ${green}passed${reset}\n" + fi + cd $TOP_LEVEL + # Add a separator line to make the output easier to read. + printf "\n" + printf -- '-%.0s' {1..100} + printf "\n" +fi + +# When the stylelint config has been changed, then stylelint must check all files. +if [[ $STYLELINT_CONFIG_FILE_CHANGED == "1" ]]; then + cd "$TOP_LEVEL/core" + yarn run lint:css + if [ "$?" -ne "0" ]; then + # If there are failures set the status to a number other than 0. + FINAL_STATUS=1 + printf "\nstylelint: ${red}failed${reset}\n" + else + printf "\nstylelint: ${green}passed${reset}\n" + fi + cd $TOP_LEVEL + # Add a separator line to make the output easier to read. + printf "\n" + printf -- '-%.0s' {1..100} + printf "\n" +fi + +# When a Drupal-specific CKEditor 5 plugin changed ensure that it is compiled +# properly. Only check on DrupalCI, since we're concerned about the build being +# run with the expected package versions and making sure the result of the build +# is in sync and conform to expectations. +if [[ "$DRUPALCI" == "1" ]] && [[ $CKEDITOR5_PLUGINS_CHANGED == "1" ]]; then + cd "$TOP_LEVEL/core" + yarn run check:ckeditor5 + if [ "$?" -ne "0" ]; then + # If there are failures set the status to a number other than 0. + FINAL_STATUS=1 + printf "\nDrupal-specific CKEditor 5 plugins: ${red}failed${reset}\n" + else + printf "\nDrupal-specific CKEditor 5 plugins: ${green}passed${reset}\n" + fi + cd $TOP_LEVEL + # Add a separator line to make the output easier to read. + printf "\n" + printf -- '-%.0s' {1..100} + printf "\n" +fi + +# When JavaScript packages change, then rerun all JavaScript style checks. +if [[ "$JAVASCRIPT_PACKAGES_CHANGED" == "1" ]]; then + cd "$TOP_LEVEL/core" + yarn run build:css --check + CORRECTCSS=$? + if [ "$CORRECTCSS" -ne "0" ]; then + FINAL_STATUS=1 + printf "\n${red}ERROR: The compiled CSS from the PCSS files" + printf "\n does not match the current CSS files. Some added" + printf "\n or updated JavaScript package made changes." + printf "\n Recompile the CSS with: yarn run build:css${reset}\n\n" + fi + cd $TOP_LEVEL + # Add a separator line to make the output easier to read. + printf "\n" + printf -- '-%.0s' {1..100} + printf "\n" +fi + +for FILE in $FILES; do + STATUS=0; + # Print a line to separate spellcheck output from per file output. + printf "Checking %s\n" "$FILE" + printf "\n" + + # Ensure the file still exists (i.e. is not being deleted). + if [ -a $FILE ]; then + if [ ${FILE: -3} != ".sh" ]; then + if [ -x $FILE ]; then + printf "${red}check failed:${reset} file $FILE should not be executable\n" + STATUS=1 + fi + fi + fi + + # Don't commit changes to vendor. + if [[ "$FILE" =~ ^vendor/ ]]; then + printf "${red}check failed:${reset} file in vendor directory being committed ($FILE)\n" + STATUS=1 + fi + + # Don't commit changes to core/node_modules. + if [[ "$FILE" =~ ^core/node_modules/ ]]; then + printf "${red}check failed:${reset} file in core/node_modules directory being committed ($FILE)\n" + STATUS=1 + fi + + ############################################################################ + ### PHP AND YAML FILES + ############################################################################ + if [[ -f "$TOP_LEVEL/$FILE" ]] && [[ $FILE =~ \.(inc|install|module|php|profile|test|theme|yml)$ ]] && [[ $PHPCS_XML_DIST_FILE_CHANGED == "0" ]] && [[ "$DRUPALCI" == "0" ]]; then + # Test files with phpcs rules. + vendor/bin/phpcs "$TOP_LEVEL/$FILE" --standard="$TOP_LEVEL/core/phpcs.xml.dist" + PHPCS=$? + if [ "$PHPCS" -ne "0" ]; then + # If there are failures set the status to a number other than 0. + STATUS=1 + else + printf "PHPCS: $FILE ${green}passed${reset}\n" + fi + fi + + ############################################################################ + ### YAML FILES + ############################################################################ + if [[ -f "$TOP_LEVEL/$FILE" ]] && [[ $FILE =~ \.yml$ ]]; then + # Test files with ESLint. + cd "$TOP_LEVEL/core" + node ./node_modules/eslint/bin/eslint.js --quiet --resolve-plugins-relative-to . "$TOP_LEVEL/$FILE" + YAMLLINT=$? + if [ "$YAMLLINT" -ne "0" ]; then + # If there are failures set the status to a number other than 0. + STATUS=1 + else + printf "ESLint: $FILE ${green}passed${reset}\n" + fi + cd $TOP_LEVEL + fi + + ############################################################################ + ### JAVASCRIPT FILES + ############################################################################ + if [[ -f "$TOP_LEVEL/$FILE" ]] && [[ $FILE =~ \.js$ ]]; then + cd "$TOP_LEVEL/core" + # Check the coding standards. + node ./node_modules/eslint/bin/eslint.js --quiet --config=.eslintrc.passing.json "$TOP_LEVEL/$FILE" + JSLINT=$? + if [ "$JSLINT" -ne "0" ]; then + # No need to write any output the node command will do this for us. + STATUS=1 + else + printf "ESLint: $FILE ${green}passed${reset}\n" + fi + cd $TOP_LEVEL + fi + + ############################################################################ + ### CSS FILES + ############################################################################ + if [[ -f "$TOP_LEVEL/$FILE" ]] && [[ $FILE =~ \.css$ ]]; then + # Work out the root name of the CSS so we can ensure that the PostCSS + # version has been compiled correctly. + if [[ $FILE =~ \.pcss\.css$ ]]; then + BASENAME=${FILE%.pcss.css} + COMPILE_CHECK=1 + else + BASENAME=${FILE%.css} + # We only need to compile check if the .pcss.css file is not also + # changing. This is because the compile check will occur for the + # .pcss.css file. This might occur if the compiled stylesheets have + # changed. + contains_element "$BASENAME.pcss.css" "${FILES[@]}" + HASPOSTCSS=$? + if [ "$HASPOSTCSS" -ne "0" ]; then + COMPILE_CHECK=1 + else + COMPILE_CHECK=0 + fi + fi + # PostCSS + if [[ "$COMPILE_CHECK" == "1" ]] && [[ -f "$TOP_LEVEL/$BASENAME.pcss.css" ]]; then + cd "$TOP_LEVEL/core" + yarn run build:css --check --file "$TOP_LEVEL/$BASENAME.pcss.css" + CORRECTCSS=$? + if [ "$CORRECTCSS" -ne "0" ]; then + # If the CSS does not match the PCSS, set the status to a number other + # than 0. + STATUS=1 + printf "\n${red}ERROR: The compiled CSS from" + printf "\n ${BASENAME}.pcss.css" + printf "\n does not match its CSS file. Recompile the CSS with:" + printf "\n yarn run build:css${reset}\n\n" + fi + cd $TOP_LEVEL + fi + fi + if [[ -f "$TOP_LEVEL/$FILE" ]] && [[ $FILE =~ \.css$ ]] && [[ -f "core/node_modules/.bin/stylelint" ]]; then + BASENAME=${FILE%.css} + # We only need to use stylelint on the .pcss.css file. So if this CSS file + # has a corresponding .pcss don't do stylelint. + if [[ $FILE =~ \.pcss\.css$ ]] || [[ ! -f "$TOP_LEVEL/$BASENAME.pcss.css" ]]; then + cd "$TOP_LEVEL/core" + node_modules/.bin/stylelint --allow-empty-input "$TOP_LEVEL/$FILE" + if [ "$?" -ne "0" ]; then + STATUS=1 + else + printf "STYLELINT: $FILE ${green}passed${reset}\n" + fi + cd $TOP_LEVEL + fi + fi + + if [[ "$STATUS" == "1" ]]; then + FINAL_STATUS=1 + # There is no need to print a failure message. The fail will be described + # already. + else + printf "%s ${green}passed${reset}\n" "$FILE" + fi + + # Print a line to separate each file's checks. + printf "\n" + printf -- '-%.0s' {1..100} + printf "\n" +done + +if [[ "$FINAL_STATUS" == "1" ]] && [[ "$DRUPALCI" == "1" ]]; then + printf "${red}Drupal code quality checks failed.${reset}\n" + printf "To reproduce this output locally:\n" + printf "* Apply the change as a patch\n" + printf "* Run this command locally: sh ./core/scripts/dev/commit-code-check.sh\n" + printf "OR:\n" + printf "* From the merge request branch\n" + printf "* Run this command locally: sh ./core/scripts/dev/commit-code-check.sh --branch %s\n" "$DRUPAL_VERSION" +fi +exit $FINAL_STATUS diff --git a/commands/web/cspell-check b/commands/web/cspell-check new file mode 100755 index 0000000..be9a58f --- /dev/null +++ b/commands/web/cspell-check @@ -0,0 +1,20 @@ +#!/bin/bash + +#ddev-generated + +## Description: This script performs cspell checks. +## Usage: cspell-check [flags] +## Example: "ddev cspell-check" + +# Installs dependencies if not already run. +if [ ! -d /var/www/html/repos/drupal/core/node_modules/.bin ]; then + + corepack enable + + yarn --cwd /var/www/html/repos/drupal/core install +fi + +TOP_LEVEL="/var/www/html/repos/drupal/core" +cd $TOP_LEVEL + +yarn run spellcheck:core --no-must-find-files --cache --cache-strategy content diff --git a/commands/web/install b/commands/web/install new file mode 100755 index 0000000..f14ddae --- /dev/null +++ b/commands/web/install @@ -0,0 +1,10 @@ +#!/bin/bash + +#ddev-generated + +## Description: Performs a default drupal installation +## Usage: install +## Example: "ddev install" + +drush site:install standard --account-name=admin --account-pass=admin --site-name="Drupal 11" -y +# drush en admin_toolbar admin_toolbar_tools devel diff --git a/commands/web/nightwatch b/commands/web/nightwatch index b6bc976..954af04 100644 --- a/commands/web/nightwatch +++ b/commands/web/nightwatch @@ -1,10 +1,16 @@ #!/bin/bash #ddev-generated + ## Description: Run Nightwatch ## Usage: nightwatch ## Example: ddev nightwatch --tag core echo "Clearing old webdriver sessions" curl -f -s http://chrome:4444/status | jq -r '.value.nodes[].slots[].session.sessionId' | while read -r session; do if [ "$session" != "null" ]; then curl -X DELETE "http://chrome:4444/session/$session"; fi; done -cd web/core && yarn test:nightwatch "$@" + +if [ ! -d /var/www/html/repos/drupal/core/node_modules ]; then + yarn --cwd /var/www/html/repos/drupal/core install +fi + +yarn --cwd /var/www/html/repos/drupal/core test:nightwatch $@ diff --git a/commands/web/phpcbf b/commands/web/phpcbf new file mode 100755 index 0000000..1854bb0 --- /dev/null +++ b/commands/web/phpcbf @@ -0,0 +1,18 @@ +#!/bin/bash + +#ddev-generated + +## Description: Run phpcbf +## Usage: phpcbf [flags] [args] +## Example: "ddev phpcbf core/modules/user/src/RegisterForm.php" + +TOP_LEVEL="/var/www/html/repos/drupal" +cd $TOP_LEVEL + +if ! command -v /var/www/html/vendor/bin/phpcbf >/dev/null; then + echo "phpcbf is not in PATH in the web container. You probably forgot to 'ddev composer install'" + exit 2 +fi + +/var/www/html/vendor/bin/phpcbf --standard="$TOP_LEVEL/core/phpcs.xml.dist" $@ || \ +echo "Return code ignored" diff --git a/commands/web/phpcs b/commands/web/phpcs new file mode 100755 index 0000000..7355ead --- /dev/null +++ b/commands/web/phpcs @@ -0,0 +1,18 @@ +#!/bin/bash + +#ddev-generated + +## Description: Run phpcs +## Usage: phpcs [flags] [args] +## Example: "ddev phpcs core/modules/user/src/RegisterForm.php" + +TOP_LEVEL="/var/www/html/repos/drupal" +cd $TOP_LEVEL + +if ! command -v /var/www/html/vendor/bin/phpcs >/dev/null; then + echo "phpcs is not in PATH in the web container. You probably forgot to 'ddev composer install'" + exit 2 +fi + +/var/www/html/vendor/bin/phpcs --standard="$TOP_LEVEL/core/phpcs.xml.dist" $@ || \ +echo "Return code ignored" diff --git a/commands/web/phpstan b/commands/web/phpstan new file mode 100755 index 0000000..90cefdd --- /dev/null +++ b/commands/web/phpstan @@ -0,0 +1,18 @@ +#!/bin/bash + +#ddev-generated + +## Description: Run phpstan +## Usage: phpstan [flags] [args] +## Example: "ddev phpstan core/modules/migrate_drupal_ui" + +TOP_LEVEL="/var/www/html/repos/drupal" +cd $TOP_LEVEL + +if ! command -v /var/www/html/vendor/bin/phpstan >/dev/null; then + echo "phpstan is not in PATH in the web container. You probably forgot to 'ddev composer install'" + exit 2 +fi + +/var/www/html/vendor/bin/phpstan analyze --configuration="$TOP_LEVEL/core/phpstan.neon.dist" --xdebug --no-ansi --memory-limit=2G $@ || \ +echo "Return code ignored" diff --git a/commands/web/phpunit b/commands/web/phpunit index 37984d3..3e4480f 100644 --- a/commands/web/phpunit +++ b/commands/web/phpunit @@ -1,23 +1,28 @@ #!/bin/bash #ddev-generated + ## Description: Run PHPUnit ## Usage: phpunit -## Example: "ddev phpunit core/modules/field" +## Example: "ddev phpunit core/modules/user/tests/src/Functional/UserAdminTest.php" + +TOP_LEVEL="/var/www/html/repos/drupal" +cd $TOP_LEVEL -if ! command -v phpunit >/dev/null; then +if ! command -v /var/www/html/vendor/bin/phpunit >/dev/null; then echo "phpunit is not in PATH in the web container. You probably forgot to 'ddev composer install'" exit 2 fi + echo "Clearing old webdriver sessions" curl -f -s http://chrome:4444/status | jq -r '.value.nodes[].slots[].session.sessionId' | while read -r session; do if [ "$session" != "null" ]; then curl -X DELETE "http://chrome:4444/session/$session"; fi; done # Prefer a phpunit.xml file in the project root if one exists; fall back on the # one in core if not. -if [ ! -f 'phpunit.xml' ]; then - phpunit_c_option="-c core" +if [ ! -f '/var/www/html/phpunit.xml' ]; then + PHPUNIT_C_OPTION="-c /var/www/html/web/core/phpunit.xml.dist" else - phpunit_c_option="" + PHPUNIT_C_OPTION="" fi -phpunit $phpunit_c_option "$@" +/var/www/html/vendor/bin/phpunit $PHPUNIT_C_OPTION "$@" diff --git a/commands/web/tests-cleanup b/commands/web/tests-cleanup new file mode 100755 index 0000000..b128b67 --- /dev/null +++ b/commands/web/tests-cleanup @@ -0,0 +1,21 @@ +#!/bin/bash + +#ddev-generated + +## Description: Clean up test results +## Usage: tests-cleanup +## Example: "ddev tests-cleanup" + +TOP_LEVEL="/var/www/html" +cd $TOP_LEVEL + +if [ ! -d "./test_output" ] +then + echo "The expected folder test_output does not exist." + exit 2 +fi + +rm ./test_output/*.counter +rm ./test_output/*.html + +echo "Test files removed." diff --git a/config.ddev-drupal-core-dev.yaml b/config.ddev-drupal-core-dev.yaml index 6c12f31..554b0e4 100644 --- a/config.ddev-drupal-core-dev.yaml +++ b/config.ddev-drupal-core-dev.yaml @@ -8,3 +8,14 @@ upload_dirs: # but with DDEV + mutagen that isn't possible. # so just redirect the upload_dirs. - .ddev/tmp +web_environment: + - BROWSERTEST_OUTPUT_DIRECTORY=/var/www/html/test_output + - BROWSERTEST_OUTPUT_BASE_URL=${DDEV_PRIMARY_URL} + - SIMPLETEST_BASE_URL=${DDEV_PRIMARY_URL} + - SIMPLETEST_DB=mysql://root:root@db/phpunit +corepack_enable: true +nodejs_version: "20" +hooks: + post-start: + - exec: mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS phpunit; GRANT ALL ON phpunit.* to 'db'@'%';" + service: db diff --git a/install.yaml b/install.yaml index f8717de..582f9cb 100644 --- a/install.yaml +++ b/install.yaml @@ -10,6 +10,13 @@ project_files: - commands/web/drupal - commands/web/phpunit - commands/web/nightwatch + - commands/web/install + - commands/web/code-check + - commands/web/cspell-check + - commands/web/phpcbf + - commands/web/phpcs + - commands/web/phpstan + - commands/web/tests-cleanup - core-dev/gitignore - core-dev/.env - core-dev/src/Command/AdminLoginCommand.php @@ -26,20 +33,21 @@ project_files: - core-dev/src/Command/LintCommand.php post_install_actions: - - cp core-dev/phpunit-chrome.xml ../phpunit.xml + - cp ../repos/drupal/core/phpunit.xml.dist ../phpunit.xml - perl -pi -e "s|DRUPAL_CORE_DDEV_URL|$DDEV_PRIMARY_URL|g" ../phpunit.xml - perl -pi -e "'$DDEV_DOCROOT' and s|DDEV_DOCROOT|$DDEV_DOCROOT/|g" ../phpunit.xml - cp core-dev/.env ../.env - cp core-dev/gitignore ../.gitignore - mkdir -p ../test_output - - chmod +w ../test_output - - cd ../web/core && ddev yarn + - chmod -R 777 ../test_output + # - cd ../web/core && ddev yarn removal_actions: - | - for item in ../core/phpunit.xml ../core/.env ../.gitignore; do + for item in ../phpunit.xml ../.env ../.gitignore; do if grep '#ddev-generated' ${item} >/dev/null; then rm -f ${item} fi done + - echo removing test_output directory - rm -rf ../test_output