[Experiment] Add container to run php unit tests in docker (https://github.com/woocommerce/woocommerce-blocks/pull/2004)

* Add container to run php unit tests in docker

* Improvemnets to entrypoints

* Simplfiy dockerfile
This commit is contained in:
Mike Jolley 2020-03-31 11:47:40 +01:00 committed by GitHub
parent 6df879a922
commit bf8715707d
6 changed files with 347 additions and 21 deletions

View File

@ -1,10 +1,8 @@
# WordPress container environment
WORDPRESS_DB_HOST=db
WORDPRESS_DB_NAME=testdb
WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wordpress
WORDPRESS_DB_PASSWORD=wordpress
WORDPRESS_TABLE_PREFIX=wp_
WORDPRESS_DEBUG=1
# WordPress CLI environment
WORDPRESS_PORT=8084

View File

@ -6,12 +6,33 @@ services:
image: mariadb:10.4
restart: on-failure
environment:
MYSQL_DATABASE: testdb
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
volumes:
- db:/var/lib/mysql
- db:/var/lib/mysql
wordpress-unit-tests:
container_name: wordpress_test
depends_on:
- db
build:
context: ./tests/bin
ports:
- 8085:80
restart: on-failure
environment:
WORDPRESS_DB_HOST:
WORDPRESS_DB_NAME:
WORDPRESS_DB_USER:
WORDPRESS_DB_PASSWORD:
WORDPRESS_TABLE_PREFIX: wp_test_
WP_CORE_DIR: /var/www/html
WP_TESTS_DIR: /tmp/wordpress-tests-lib
volumes:
- './:/var/www/html/wp-content/plugins/woocommerce-gutenberg-products-block'
- wordpress:/var/www/html
wordpress-www:
depends_on:
@ -26,8 +47,8 @@ services:
WORDPRESS_DB_NAME:
WORDPRESS_DB_USER:
WORDPRESS_DB_PASSWORD:
WORDPRESS_TABLE_PREFIX:
WORDPRESS_DEBUG:
WORDPRESS_TABLE_PREFIX: wp_
WORDPRESS_DEBUG: 1
volumes:
- "./:/var/www/html/wp-content/plugins/woocommerce-gutenberg-products-block"
- wordpress:/var/www/html

View File

@ -45,6 +45,7 @@
"package-plugin": "./bin/build-plugin-zip.sh",
"package-plugin:dev": "./bin/build-plugin-zip.sh -d",
"package-plugin:zip-only": "./bin/build-plugin-zip.sh -z",
"phpunit": "docker-compose up -d db && docker-compose up -d --build wordpress-unit-tests && docker exec -it --workdir /var/www/html/wp-content/plugins/woocommerce-gutenberg-products-block wordpress_test php ./vendor/bin/phpunit",
"reformat-files": "prettier --ignore-path .eslintignore --write \"**/*.{js,jsx,json,ts,tsx}\"",
"test": "wp-scripts test-unit-js --config tests/js/jest.config.json",
"test:help": "wp-scripts test-unit-js --help",

View File

@ -0,0 +1,21 @@
FROM wordpress:latest
CMD echo "Installing dependencies..."
RUN apt-get update && \
apt-get -y install subversion unzip wget git-all
CMD echo "Installing tests..."
ENV WP_TESTS_DIR=/tmp/wordpress-tests-lib
ENV WP_CORE_DIR=/usr/src/wordpress
COPY install-wp-tests.sh /usr/local/bin/dockerInit
RUN chmod +x /usr/local/bin/dockerInit
RUN dockerInit wordpress wordpress wordpress db latest true
# This is the entrypoint script from the WordPress Docker package.
CMD ["docker-entrypoint.sh"]
# Keep container active
CMD ["apache2-foreground"]

View File

@ -0,0 +1,290 @@
#!/bin/bash
set -euo pipefail
# usage: file_env VAR [DEFAULT]
# ie: file_env 'XYZ_DB_PASSWORD' 'example'
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
file_env() {
local var="$1"
local fileVar="${var}_FILE"
local def="${2:-}"
if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
exit 1
fi
local val="$def"
if [ "${!var:-}" ]; then
val="${!var}"
elif [ "${!fileVar:-}" ]; then
val="$(< "${!fileVar}")"
fi
export "$var"="$val"
unset "$fileVar"
}
if [[ "$1" == apache2* ]] || [ "$1" == php-fpm ]; then
if [ "$(id -u)" = '0' ]; then
case "$1" in
apache2*)
user="${APACHE_RUN_USER:-www-data}"
group="${APACHE_RUN_GROUP:-www-data}"
# strip off any '#' symbol ('#1000' is valid syntax for Apache)
pound='#'
user="${user#$pound}"
group="${group#$pound}"
;;
*) # php-fpm
user='www-data'
group='www-data'
;;
esac
else
user="$(id -u)"
group="$(id -g)"
fi
if [ ! -e index.php ] && [ ! -e wp-includes/version.php ]; then
# if the directory exists and WordPress doesn't appear to be installed AND the permissions of it are root:root, let's chown it (likely a Docker-created directory)
if [ "$(id -u)" = '0' ] && [ "$(stat -c '%u:%g' .)" = '0:0' ]; then
chown "$user:$group" .
fi
echo >&2 "WordPress not found in $PWD - copying now..."
if [ -n "$(ls -A)" ]; then
echo >&2 "WARNING: $PWD is not empty! (copying anyhow)"
fi
sourceTarArgs=(
--create
--file -
--directory /usr/src/wordpress
--owner "$user" --group "$group"
)
targetTarArgs=(
--extract
--file -
)
if [ "$user" != '0' ]; then
# avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted"
targetTarArgs+=( --no-overwrite-dir )
fi
tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}"
echo >&2 "Complete! WordPress has been successfully copied to $PWD"
if [ ! -e .htaccess ]; then
# NOTE: The "Indexes" option is disabled in the php:apache base image
cat > .htaccess <<-'EOF'
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
EOF
chown "$user:$group" .htaccess
fi
fi
# allow any of these "Authentication Unique Keys and Salts." to be specified via
# environment variables with a "WORDPRESS_" prefix (ie, "WORDPRESS_AUTH_KEY")
uniqueEnvs=(
AUTH_KEY
SECURE_AUTH_KEY
LOGGED_IN_KEY
NONCE_KEY
AUTH_SALT
SECURE_AUTH_SALT
LOGGED_IN_SALT
NONCE_SALT
)
envs=(
WORDPRESS_DB_HOST
WORDPRESS_DB_USER
WORDPRESS_DB_PASSWORD
WORDPRESS_DB_NAME
WORDPRESS_DB_CHARSET
WORDPRESS_DB_COLLATE
"${uniqueEnvs[@]/#/WORDPRESS_}"
WORDPRESS_TABLE_PREFIX
WORDPRESS_DEBUG
WORDPRESS_CONFIG_EXTRA
)
haveConfig=
for e in "${envs[@]}"; do
file_env "$e"
if [ -z "$haveConfig" ] && [ -n "${!e}" ]; then
haveConfig=1
fi
done
# linking backwards-compatibility
if [ -n "${!MYSQL_ENV_MYSQL_*}" ]; then
haveConfig=1
# host defaults to "mysql" below if unspecified
: "${WORDPRESS_DB_USER:=${MYSQL_ENV_MYSQL_USER:-root}}"
if [ "$WORDPRESS_DB_USER" = 'root' ]; then
: "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_ROOT_PASSWORD:-}}"
else
: "${WORDPRESS_DB_PASSWORD:=${MYSQL_ENV_MYSQL_PASSWORD:-}}"
fi
: "${WORDPRESS_DB_NAME:=${MYSQL_ENV_MYSQL_DATABASE:-}}"
fi
# only touch "wp-config.php" if we have environment-supplied configuration values
if [ "$haveConfig" ]; then
: "${WORDPRESS_DB_HOST:=mysql}"
: "${WORDPRESS_DB_USER:=root}"
: "${WORDPRESS_DB_PASSWORD:=}"
: "${WORDPRESS_DB_NAME:=wordpress}"
: "${WORDPRESS_DB_CHARSET:=utf8}"
: "${WORDPRESS_DB_COLLATE:=}"
# version 4.4.1 decided to switch to windows line endings, that breaks our seds and awks
# https://github.com/docker-library/wordpress/issues/116
# https://github.com/WordPress/WordPress/commit/1acedc542fba2482bab88ec70d4bea4b997a92e4
sed -ri -e 's/\r$//' wp-config*
if [ ! -e wp-config.php ]; then
awk '
/^\/\*.*stop editing.*\*\/$/ && c == 0 {
c = 1
system("cat")
if (ENVIRON["WORDPRESS_CONFIG_EXTRA"]) {
print "// WORDPRESS_CONFIG_EXTRA"
print ENVIRON["WORDPRESS_CONFIG_EXTRA"] "\n"
}
}
{ print }
' wp-config-sample.php > wp-config.php <<'EOPHP'
// If we're behind a proxy server and using HTTPS, we need to alert WordPress of that fact
// see also http://codex.wordpress.org/Administration_Over_SSL#Using_a_Reverse_Proxy
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
EOPHP
chown "$user:$group" wp-config.php
elif [ -e wp-config.php ] && [ -n "$WORDPRESS_CONFIG_EXTRA" ] && [[ "$(< wp-config.php)" != *"$WORDPRESS_CONFIG_EXTRA"* ]]; then
# (if the config file already contains the requested PHP code, don't print a warning)
echo >&2
echo >&2 'WARNING: environment variable "WORDPRESS_CONFIG_EXTRA" is set, but "wp-config.php" already exists'
echo >&2 ' The contents of this variable will _not_ be inserted into the existing "wp-config.php" file.'
echo >&2 ' (see https://github.com/docker-library/wordpress/issues/333 for more details)'
echo >&2
fi
# see http://stackoverflow.com/a/2705678/433558
sed_escape_lhs() {
echo "$@" | sed -e 's/[]\/$*.^|[]/\\&/g'
}
sed_escape_rhs() {
echo "$@" | sed -e 's/[\/&]/\\&/g'
}
php_escape() {
local escaped="$(php -r 'var_export(('"$2"') $argv[1]);' -- "$1")"
if [ "$2" = 'string' ] && [ "${escaped:0:1}" = "'" ]; then
escaped="${escaped//$'\n'/"' + \"\\n\" + '"}"
fi
echo "$escaped"
}
set_config() {
key="$1"
value="$2"
var_type="${3:-string}"
start="(['\"])$(sed_escape_lhs "$key")\2\s*,"
end="\);"
if [ "${key:0:1}" = '$' ]; then
start="^(\s*)$(sed_escape_lhs "$key")\s*="
end=";"
fi
sed -ri -e "s/($start\s*).*($end)$/\1$(sed_escape_rhs "$(php_escape "$value" "$var_type")")\3/" wp-config.php
}
set_config 'DB_HOST' "$WORDPRESS_DB_HOST"
set_config 'DB_USER' "$WORDPRESS_DB_USER"
set_config 'DB_PASSWORD' "$WORDPRESS_DB_PASSWORD"
set_config 'DB_NAME' "$WORDPRESS_DB_NAME"
set_config 'DB_CHARSET' "$WORDPRESS_DB_CHARSET"
set_config 'DB_COLLATE' "$WORDPRESS_DB_COLLATE"
for unique in "${uniqueEnvs[@]}"; do
uniqVar="WORDPRESS_$unique"
if [ -n "${!uniqVar}" ]; then
set_config "$unique" "${!uniqVar}"
else
# if not specified, let's generate a random value
currentVal="$(sed -rn -e "s/define\(\s*(([\'\"])$unique\2\s*,\s*)(['\"])(.*)\3\s*\);/\4/p" wp-config.php)"
if [ "$currentVal" = 'put your unique phrase here' ]; then
set_config "$unique" "$(head -c1m /dev/urandom | sha1sum | cut -d' ' -f1)"
fi
fi
done
if [ "$WORDPRESS_TABLE_PREFIX" ]; then
set_config '$table_prefix' "$WORDPRESS_TABLE_PREFIX"
fi
if [ "$WORDPRESS_DEBUG" ]; then
set_config 'WP_DEBUG' 1 boolean
fi
if ! TERM=dumb php -- <<'EOPHP'
<?php
// database might not exist, so let's try creating it (just to be safe)
$stderr = fopen('php://stderr', 'w');
// https://codex.wordpress.org/Editing_wp-config.php#MySQL_Alternate_Port
// "hostname:port"
// https://codex.wordpress.org/Editing_wp-config.php#MySQL_Sockets_or_Pipes
// "hostname:unix-socket-path"
list($host, $socket) = explode(':', getenv('WORDPRESS_DB_HOST'), 2);
$port = 0;
if (is_numeric($socket)) {
$port = (int) $socket;
$socket = null;
}
$user = getenv('WORDPRESS_DB_USER');
$pass = getenv('WORDPRESS_DB_PASSWORD');
$dbName = getenv('WORDPRESS_DB_NAME');
$maxTries = 10;
do {
$mysql = new mysqli($host, $user, $pass, '', $port, $socket);
if ($mysql->connect_error) {
fwrite($stderr, "\n" . 'MySQL Connection Error: (' . $mysql->connect_errno . ') ' . $mysql->connect_error . "\n");
--$maxTries;
if ($maxTries <= 0) {
exit(1);
}
sleep(3);
}
} while ($mysql->connect_error);
if (!$mysql->query('CREATE DATABASE IF NOT EXISTS `' . $mysql->real_escape_string($dbName) . '`')) {
fwrite($stderr, "\n" . 'MySQL "CREATE DATABASE" Error: ' . $mysql->error . "\n");
$mysql->close();
exit(1);
}
$mysql->close();
EOPHP
then
echo >&2
echo >&2 "WARNING: unable to establish a database connection to '$WORDPRESS_DB_HOST'"
echo >&2 ' continuing anyways (which might have unexpected results)'
echo >&2
fi
fi
# now that we're definitely done writing configuration, let's clear out the relevant envrionment variables (so that stray "phpinfo()" calls don't leak secrets from our code)
for e in "${envs[@]}"; do
unset "$e"
done
fi
exec "$@"

View File

@ -20,7 +20,7 @@ WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress/}
download() {
if [ `which curl` ]; then
curl -s "$1" > "$2";
curl -s -L "$1" > "$2";
elif [ `which wget` ]; then
wget -nv -O "$2" "$1"
fi
@ -148,31 +148,26 @@ install_db() {
mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
}
install_deps() {
install_woocommerce() {
# get built plugin from .org
download https://downloads.wordpress.org/plugin/woocommerce.zip "$TMPDIR/woocommerce.zip"
unzip -q $TMPDIR/woocommerce.zip -d "$WP_CORE_DIR/wp-content/plugins"
# Script Variables
BRANCH=$TRAVIS_BRANCH
REPO=$TRAVIS_REPO_SLUG
WORKING_DIR="$PWD"
# Get github version
if [ "$TRAVIS_PULL_REQUEST_BRANCH" != "" ]; then
BRANCH=$TRAVIS_PULL_REQUEST_BRANCH
REPO=$TRAVIS_PULL_REQUEST_SLUG
fi
# checkout dev version of woocommerce
cd "$WP_CORE_DIR/wp-content/plugins"
git clone --depth 1 "https://github.com/woocommerce/woocommerce.git"
# install dependencies
cd woocommerce
npm install
composer install --no-dev
# Back to original dir
cd "$WORKING_DIR"
git clone --depth 1 "https://github.com/woocommerce/woocommerce.git" "$TMPDIR/woocommerce-git"
mv "$TMPDIR/woocommerce-git/tests" "$WP_CORE_DIR/wp-content/plugins/woocommerce"
}
install_wp
install_test_suite
install_db
install_deps
install_woocommerce