diff --git a/.travis.yml b/.travis.yml
index 2aed90d..dad2347 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -52,9 +52,16 @@ before_script:
# Build (multiple tries due to network outages)
- max=100; i=0; while [ $i -lt $max ]; do if make build-base-${PHP//.}; then break; else i=$((i+1)); fi; done; if [ $i -gt 98 ]; then false; fi
+ - make test-base-${PHP//.}
+
- max=100; i=0; while [ $i -lt $max ]; do if make build-mods-${PHP//.}; then break; else i=$((i+1)); fi; done; if [ $i -gt 98 ]; then false; fi
+ - make test-mods-${PHP//.}
+
- max=100; i=0; while [ $i -lt $max ]; do if make build-prod-${PHP//.}; then break; else i=$((i+1)); fi; done; if [ $i -gt 98 ]; then false; fi
+ - make test-prod-${PHP//.}
+
- max=100; i=0; while [ $i -lt $max ]; do if make build-work-${PHP//.}; then break; else i=$((i+1)); fi; done; if [ $i -gt 98 ]; then false; fi
+ - make test-work-${PHP//.}
# Test if PHP modules have changed
- ./build/gen-readme.sh "${PHP}"
diff --git a/Dockerfiles/work/data/docker-entrypoint.d/40-mysqldump-secure.sh b/Dockerfiles/work/data/docker-entrypoint.d/40-mysqldump-secure.sh
index 71cb805..64e5f8b 100755
--- a/Dockerfiles/work/data/docker-entrypoint.d/40-mysqldump-secure.sh
+++ b/Dockerfiles/work/data/docker-entrypoint.d/40-mysqldump-secure.sh
@@ -13,7 +13,10 @@ set -o pipefail
### Setup Postfix for catch-all
###
fix_mds_permissions() {
- local debug="${1}"
+ local user="${1}"
+ local group="${2}"
+ local debug="${3}"
+
local mds_cfg=/etc/mysqldump-secure.conf
local mds_cnf=/etc/mysqldump-secure.cnf
local mds_log=/var/log/mysqldump-secure.log
@@ -23,10 +26,10 @@ fix_mds_permissions() {
run "mkdir -p ${mds_dir}" "${debug}"
fi
- run "chown ${MY_USER}:${MY_GROUP} ${mds_cfg}" "${debug}"
- run "chown ${MY_USER}:${MY_GROUP} ${mds_cnf}" "${debug}"
- run "chown ${MY_USER}:${MY_GROUP} ${mds_log}" "${debug}"
- run "chown ${MY_USER}:${MY_GROUP} ${mds_dir}" "${debug}"
+ run "chown ${user}:${group} ${mds_cfg}" "${debug}"
+ run "chown ${user}:${group} ${mds_cnf}" "${debug}"
+ run "chown ${user}:${group} ${mds_log}" "${debug}"
+ run "chown ${user}:${group} ${mds_dir}" "${debug}"
}
set_mds_settings() {
diff --git a/Dockerfiles/work/data/docker-entrypoint.sh b/Dockerfiles/work/data/docker-entrypoint.sh
index 01bba0f..1a36ea1 100755
--- a/Dockerfiles/work/data/docker-entrypoint.sh
+++ b/Dockerfiles/work/data/docker-entrypoint.sh
@@ -134,7 +134,7 @@ copy_ini_files "${PHP_CUST_INI_DIR}" "${PHP_INI_DIR}" "${DEBUG_LEVEL}"
###
### mysqldump-secure
###
-fix_mds_permissions "${DEBUG_LEVEL}"
+fix_mds_permissions "${MY_USER}" "${MY_GROUP}" "${DEBUG_LEVEL}"
set_mds_settings "MYSQL_BACKUP_USER" "MYSQL_BACKUP_PASS" "MYSQL_BACKUP_HOST" "${DEBUG_LEVEL}"
diff --git a/Makefile b/Makefile
index e6947ca..45343ef 100644
--- a/Makefile
+++ b/Makefile
@@ -258,3 +258,60 @@ pull-from-71:
docker pull $(shell grep FROM $(location)/base/Dockerfile-7.1 | sed 's/^FROM//g'; done)
pull-from-72:
docker pull $(shell grep FROM $(location)/base/Dockerfile-7.2 | sed 's/^FROM//g'; done)
+
+
+
+###
+### Tests
+###
+test-base-54:
+ ./tests/test.sh 5.4 base
+test-base-55:
+ ./tests/test.sh 5.5 base
+test-base-56:
+ ./tests/test.sh 5.6 base
+test-base-70:
+ ./tests/test.sh 7.0 base
+test-base-71:
+ ./tests/test.sh 7.1 base
+test-base-72:
+ ./tests/test.sh 7.2 base
+
+test-mods-54:
+ ./tests/test.sh 5.4 mods
+test-mods-55:
+ ./tests/test.sh 5.5 mods
+test-mods-56:
+ ./tests/test.sh 5.6 mods
+test-mods-70:
+ ./tests/test.sh 7.0 mods
+test-mods-71:
+ ./tests/test.sh 7.1 mods
+test-mods-72:
+ ./tests/test.sh 7.2 mods
+
+test-prod-54:
+ ./tests/test.sh 5.4 prod
+test-prod-55:
+ ./tests/test.sh 5.5 prod
+test-prod-56:
+ ./tests/test.sh 5.6 prod
+test-prod-70:
+ ./tests/test.sh 7.0 prod
+test-prod-71:
+ ./tests/test.sh 7.1 prod
+test-prod-72:
+ ./tests/test.sh 7.2 prod
+
+test-work-54:
+ ./tests/test.sh 5.4 work
+test-work-55:
+ ./tests/test.sh 5.5 work
+test-work-56:
+ ./tests/test.sh 5.6 work
+test-work-70:
+ ./tests/test.sh 7.0 work
+test-work-71:
+ ./tests/test.sh 7.1 work
+test-work-72:
+ ./tests/test.sh 7.2 work
diff --git a/README.md b/README.md
index a353018..a6a813e 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,95 @@
# Docker PHP-FPM images
+
Options
+### Environment variables
-## Available PHP Modules
+Have a look at the following table to see all supported environment variables for each Docker image flavour.
+
+
+
+
+ | Image |
+ Env Variable |
+ Type |
+ Default |
+ Description |
+
+
+
+
+ base
mods
prod
work |
+ DEBUG_ENTRYPOINT |
+ int |
+ 0 |
+ Set debug level for startup.
0 Only warnings and errors are shown.
1 All log messages are shown
2 All log messages and executed commands are shown. |
+
+
+ NEW_UID |
+ int |
+ 1000 |
+ Assign the PHP-FPM user a new uid in order to syncronize file system permissions with your host computer and the Docker container. You should use a value that matches your host systems local user. (Type id for your uid). |
+
+
+ NEW_GID |
+ int |
+ 1000 |
+ Assign the PHP-FPM group a new gid in order to syncronize file system permissions with your host computer and the Docker container. You should use a value that matches your host systems local group. (Type id for your gid). |
+
+
+ |
+
+
+ prod
work |
+ TIMEZONE |
+ string |
+ UTC |
+ Set docker OS timezone as well as PHP timezone. (Example: Europe/Berlin) |
+
+
+ DOCKER_LOGS |
+ bool |
+ 1 |
+ By default all Docker images are configured to output their PHP-FPM access and error logs to stdout and stderr. Those which support it can change the behaviour to log into files inside the container. Their respective directories are available as volumes that can be mounted to the host computer. This feature might help developer who are more comfortable with tailing or searching through actual files instead of using docker logs.
Set this variable to 0 in order to enable logging to files. Log files are avilable under /var/log/php/ which is also a docker volume that can be mounted locally. |
+
+
+ ENABLE_MAIL |
+ bool |
+ 0 |
+ Enable local email catch-all. Postfix will be configured for local delivery and all mails sent (even to real domains) will be catched locally. No email will ever go out. They will all be stored in a local devilbox account. Value: 0 or 1 |
+
+
+ FORWARD_PORTS_TO_LOCALHOST |
+ string |
+ |
+ List of remote ports to forward to 127.0.0.1. Format:
<local-port>:<remote-host>:<remote-port> You can separate multiple entries by comma. Example:
3306:mysqlhost:3306, 6379:192.0.1.1:6379 |
+
+
+ |
+
+
+ | work |
+ MYSQL_BACKUP_USER |
+ string |
+ '' |
+ Username for mysql backups used for bundled mysqldump-secure |
+
+
+ MYSQL_BACKUP_PASS |
+ string |
+ '' |
+ Password for mysql backups used for bundled mysqldump-secure |
+
+
+ MYSQL_BACKUP_HOST |
+ string |
+ '' |
+ Hostname for mysql backups used for bundled mysqldump-secure |
+
+
+
+
+
Modules
diff --git a/tests/.lib.sh b/tests/.lib.sh
new file mode 100755
index 0000000..321c4f2
--- /dev/null
+++ b/tests/.lib.sh
@@ -0,0 +1,168 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+set -o pipefail
+
+
+###
+### Run
+###
+function run() {
+ local cmd="${1}"
+ local to_stderr=0
+
+ # Output to stderr instead?
+ if [ "${#}" -eq "2" ]; then
+ to_stderr="${2}"
+ fi
+
+ local red="\033[0;31m"
+ local green="\033[0;32m"
+ local yellow="\033[0;33m"
+ local reset="\033[0m"
+
+ if [ "${to_stderr}" -eq "0" ]; then
+ printf "${yellow}[%s] ${red}%s \$ ${green}${cmd}${reset}\n" "$(hostname)" "$(whoami)"
+ else
+ printf "${yellow}[%s] ${red}%s \$ ${green}${cmd}${reset}\n" "$(hostname)" "$(whoami)" >&2
+ fi
+
+ if sh -c "LANG=C LC_ALL=C ${cmd}"; then
+ if [ "${to_stderr}" -eq "0" ]; then
+ printf "${green}[%s]${reset}\n" "OK"
+ else
+ printf "${green}[%s]${reset}\n" "OK" >&2
+ fi
+ return 0
+ else
+ if [ "${to_stderr}" -eq "0" ]; then
+ printf "${red}[%s]${reset}\n" "NO"
+ else
+ printf "${red}[%s]${reset}\n" "NO" >&2
+ fi
+ return 1
+ fi
+}
+###
+### Run (must fail in order to succeed)
+###
+function run_fail() {
+ local cmd="${1}"
+ local to_stderr=0
+
+ # Output to stderr instead?
+ if [ "${#}" -eq "2" ]; then
+ to_stderr="${2}"
+ fi
+
+ local red="\033[0;31m"
+ local green="\033[0;32m"
+ local yellow="\033[0;33m"
+ local reset="\033[0m"
+
+ if [ "${to_stderr}" -eq "0" ]; then
+ printf "${yellow}[%s] ${red}%s \$ ${yellow}[NOT] ${green}${cmd}${reset}\n" "$(hostname)" "$(whoami)"
+ else
+ printf "${yellow}[%s] ${red}%s \$ ${yellow}[NOT] ${green}${cmd}${reset}\n" "$(hostname)" "$(whoami)" >&2
+ fi
+
+ if ! sh -c "LANG=C LC_ALL=C ${cmd}"; then
+ if [ "${to_stderr}" -eq "0" ]; then
+ printf "${green}[%s]${reset}\n" "OK"
+ else
+ printf "${green}[%s]${reset}\n" "OK" >&2
+ fi
+ return 0
+ else
+ if [ "${to_stderr}" -eq "0" ]; then
+ printf "${red}[%s]${reset}\n" "NO"
+ else
+ printf "${red}[%s]${reset}\n" "NO" >&2
+ fi
+ return 1
+ fi
+}
+
+###
+### Get 15 character random word
+###
+function get_random_name() {
+ local chr=(a b c d e f g h i j k l m o p q r s t u v w x y z)
+ local len="${#chr[@]}"
+ local name=
+
+ for i in {1..15}; do
+ rand="$( shuf -i 0-${len} -n 1 )"
+ rand=$(( rand - 1 ))
+ name="${name}${chr[$rand]}"
+ i="${i}" # simply to get rid of shellcheck complaints
+ done
+ echo "${name}"
+}
+
+
+###
+### Docker run
+###
+function docker_run() {
+ local image_name="${1}"
+
+ shift
+ local args="${*}"
+
+ # Returns docker-id
+ did="$( run "docker run -d --name $( get_random_name ) ${args} ${image_name}" "1" )"
+ sleep 4
+
+ # If it fails, start again in foreground to fail again, but show errors
+ if ! docker exec -it ${did} ls >/dev/null 2>&1; then
+ docker run "${args}" "${image_name}" "1"
+ return 1
+ fi
+
+ # Only get 8 digits of docker id
+ echo "${did}" | grep -Eo '^[0-9a-zA-Z]{8}'
+}
+
+
+###
+### Show Docker logs
+###
+function docker_logs() {
+ local docker_id="${1}"
+
+ run "docker logs ${docker_id}"
+}
+
+
+###
+### Docker exec
+###
+function docker_exec() {
+ local did="${1}"
+ local cmd="${2}"
+ shift
+ shift
+ local args="${*}"
+
+ run "docker exec ${args} -it ${did} ${cmd}"
+}
+
+
+###
+### Stop container
+###
+function docker_stop() {
+ local did="${1}"
+ local name=
+ name="$( docker ps --no-trunc --format='{{.ID}} {{.Names}}' | grep "${did}" | head -1 | awk '{print $2}' )"
+ # Stop
+ run "docker stop ${did} >/dev/null"
+ if docker ps | grep -q "${did}"; then
+ run "docker kill ${did} >/dev/null" || true
+ fi
+
+ # Remove if still exist
+ run "docker rm ${name} >/dev/null 2>&1 || true"
+}
diff --git a/tests/base/01-test-env-entrypoint.sh b/tests/base/01-test-env-entrypoint.sh
new file mode 100755
index 0000000..fff1d9b
--- /dev/null
+++ b/tests/base/01-test-env-entrypoint.sh
@@ -0,0 +1,97 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+set -o pipefail
+
+CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"
+
+IMAGE="${1}"
+VERSION="${2}"
+FLAVOUR="${3}"
+
+# shellcheck disable=SC1090
+. "${CWD}/../.lib.sh"
+
+
+
+############################################################
+# Tests
+############################################################
+
+
+###
+### Debug == 0
+###
+did="$( docker_run "${IMAGE}:${VERSION}-${FLAVOUR}" "-e DEBUG_ENTRYPOINT=0" )"
+if ! run_fail "docker logs ${did} 2>&1 | grep 'Debug level'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! run_fail "docker logs ${did} 2>&1 | grep '\[INFO\]'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! run_fail "docker logs ${did} 2>&1 | grep -E '\[(ERR|\?\?\?)\]'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+docker_stop "${did}"
+
+
+###
+### Debug == 1
+###
+did="$( docker_run "${IMAGE}:${VERSION}-${FLAVOUR}" "-e DEBUG_ENTRYPOINT=1" )"
+
+if ! run "docker logs ${did} 2>&1 | grep 'Debug level: 1'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! run "docker logs ${did} 2>&1 | grep '\[INFO\]'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! run_fail "docker logs ${did} 2>&1 | grep -E '\[(ERR|\?\?\?)\]'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+docker_stop "${did}"
+
+
+###
+### Debug == 2
+###
+did="$( docker_run "${IMAGE}:${VERSION}-${FLAVOUR}" "-e DEBUG_ENTRYPOINT=2" )"
+
+if ! run "docker logs ${did} 2>&1 | grep 'Debug level: 2'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! run "docker logs ${did} 2>&1 | grep '\[INFO\]'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! run_fail "docker logs ${did} 2>&1 | grep -E '\[(ERR|\?\?\?)\]'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+docker_stop "${did}"
diff --git a/tests/base/02-test-env-uid.sh b/tests/base/02-test-env-uid.sh
new file mode 100755
index 0000000..dd28fb3
--- /dev/null
+++ b/tests/base/02-test-env-uid.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+set -o pipefail
+
+CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"
+
+IMAGE="${1}"
+VERSION="${2}"
+FLAVOUR="${3}"
+
+# shellcheck disable=SC1090
+. "${CWD}/../.lib.sh"
+
+
+
+############################################################
+# Tests
+############################################################
+
+###
+### uid: 1005 (new uid)
+###
+did="$( docker_run "${IMAGE}:${VERSION}-${FLAVOUR}" "-e DEBUG_ENTRYPOINT=2 -e NEW_UID=1005" )"
+
+if ! run "docker logs ${did} 2>&1 | grep -q '1005'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! docker_exec "${did}" "id | grep 'uid=1005'" "--user=devilbox"; then
+ docker_logs "${did}"
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+docker_stop "${did}"
+
+###
+### uid: 1000 (same uid)
+###
+did="$( docker_run "${IMAGE}:${VERSION}-${FLAVOUR}" "-e DEBUG_ENTRYPOINT=2 -e NEW_UID=1000" )"
+
+if ! run "docker logs ${did} 2>&1 | grep -q '1000'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! docker_exec "${did}" "id | grep 'uid=1000'" "--user=devilbox"; then
+ docker_logs "${did}"
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+docker_stop "${did}"
+
+###
+### uid: 33 (existing uid)
+###
+did="$( docker_run "${IMAGE}:${VERSION}-${FLAVOUR}" "-e DEBUG_ENTRYPOINT=2 -e NEW_UID=33" )"
+
+if ! run "docker logs ${did} 2>&1 | grep -q '33'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! docker_exec "${did}" "id | grep 'uid=33'" "--user=devilbox"; then
+ docker_logs "${did}"
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+docker_stop "${did}"
diff --git a/tests/base/03-test-env-gid.sh b/tests/base/03-test-env-gid.sh
new file mode 100755
index 0000000..e9ea0d8
--- /dev/null
+++ b/tests/base/03-test-env-gid.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+set -o pipefail
+
+CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"
+
+IMAGE="${1}"
+VERSION="${2}"
+FLAVOUR="${3}"
+
+# shellcheck disable=SC1090
+. "${CWD}/../.lib.sh"
+
+
+
+############################################################
+# Tests
+############################################################
+
+###
+### gid: 1005 (new gid)
+###
+did="$( docker_run "${IMAGE}:${VERSION}-${FLAVOUR}" "-e DEBUG_ENTRYPOINT=2 -e NEW_GID=1005" )"
+
+if ! run "docker logs ${did} 2>&1 | grep -q '1005'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! docker_exec "${did}" "id | grep 'gid=1005'" "--user=devilbox"; then
+ docker_logs "${did}"
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+docker_stop "${did}"
+
+###
+### gid: 1000 (same gid)
+###
+did="$( docker_run "${IMAGE}:${VERSION}-${FLAVOUR}" "-e DEBUG_ENTRYPOINT=2 -e NEW_GID=1000" )"
+
+if ! run "docker logs ${did} 2>&1 | grep -q '1000'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! docker_exec "${did}" "id | grep 'gid=1000'" "--user=devilbox"; then
+ docker_logs "${did}"
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+docker_stop "${did}"
+
+###
+### gid: 33 (existing gid)
+###
+did="$( docker_run "${IMAGE}:${VERSION}-${FLAVOUR}" "-e DEBUG_ENTRYPOINT=2 -e NEW_GID=33" )"
+
+if ! run "docker logs ${did} 2>&1 | grep -q '33'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! docker_exec "${did}" "id | grep 'gid=33'" "--user=devilbox"; then
+ docker_logs "${did}"
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+docker_stop "${did}"
diff --git a/tests/prod/01-test-env-timezone.sh b/tests/prod/01-test-env-timezone.sh
new file mode 100755
index 0000000..6dcab4f
--- /dev/null
+++ b/tests/prod/01-test-env-timezone.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+set -o pipefail
+
+CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"
+
+IMAGE="${1}"
+VERSION="${2}"
+FLAVOUR="${3}"
+
+# shellcheck disable=SC1090
+. "${CWD}/../.lib.sh"
+
+
+
+############################################################
+# Tests
+############################################################
+
+###
+### Europe/Berlin
+###
+did="$( docker_run "${IMAGE}:${VERSION}-${FLAVOUR}" "-e DEBUG_ENTRYPOINT=2 -e TIMEZONE=Europe/Berlin" )"
+if ! run "docker logs ${did} 2>&1 | grep -q 'Europe/Berlin'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! docker_exec "${did}" "date | grep -E 'CE(S)*T'"; then
+ docker_exec "${did}" "date"
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+if ! docker_exec "${did}" "php -i | grep -E 'date\.timezone' | grep 'Europe/Berlin'"; then
+ docker_logs "${did}" || true
+ docker_stop "${did}" || true
+ echo "Failed"
+ exit 1
+fi
+docker_stop "${did}"
diff --git a/tests/test.sh b/tests/test.sh
new file mode 100755
index 0000000..c874caf
--- /dev/null
+++ b/tests/test.sh
@@ -0,0 +1,107 @@
+#!/usr/bin/env bash
+
+###
+### Settings
+###
+
+# Be strict
+set -e
+set -u
+set -o pipefail
+
+# Loop over newlines instead of spaces
+IFS=$'\n'
+
+
+###
+### Variables
+###
+
+# Current directory
+CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"
+
+# Array of tests to run
+declare -a BASE_TESTS=()
+declare -a MODS_TESTS=()
+declare -a PROD_TESTS=()
+declare -a WORK_TESTS=()
+
+
+###
+### Source libs
+###
+# shellcheck disable=SC1090
+. "${CWD}/.lib.sh"
+
+
+###
+### Sanity check
+###
+if [ "${#}" -ne "2" ]; then
+ echo "Usage: start.ci "
+ exit 1
+fi
+
+
+###
+### Find test files
+###
+FILES="$( find ${CWD} -regex "${CWD}/base/[0-9].+.*\.sh" | sort -u )"
+for f in ${FILES}; do
+ BASE_TESTS+=("${f}")
+done
+
+FILES="$( find ${CWD} -regex "${CWD}/mods/[0-9].+.*\.sh" | sort -u )"
+for f in ${FILES}; do
+ MODS_TESTS+=("${f}")
+done
+
+FILES="$( find ${CWD} -regex "${CWD}/prod/[0-9].+.*\.sh" | sort -u )"
+for f in ${FILES}; do
+ PROD_TESTS+=("${f}")
+done
+
+FILES="$( find ${CWD} -regex "${CWD}/work/[0-9].+.*\.sh" | sort -u )"
+for f in ${FILES}; do
+ WORK_TESTS+=("${f}")
+done
+
+
+###
+### Run tests
+###
+if [ "${2}" = "base" ] || [ "${2}" = "mods" ] || [ "${2}" = "prod" ] || [ "${2}" = "work" ]; then
+ for t in "${BASE_TESTS[@]}"; do
+ printf "\n\n\033[0;33m%s\033[0m\n" "################################################################################"
+ printf "\033[0;33m%s %s\033[0m\n" "#" "[${1}-${2}]: ${t}"
+ printf "\033[0;33m%s\033[0m\n\n" "################################################################################"
+ time ${t} devilbox/php-fpm ${1} ${2}
+ done
+fi
+
+if [ "${2}" = "mods" ] || [ "${2}" = "prod" ] || [ "${2}" = "work" ]; then
+ for t in "${MODS_TESTS[@]}"; do
+ printf "\n\n\033[0;33m%s\033[0m\n" "################################################################################"
+ printf "\033[0;33m%s %s\033[0m\n" "#" "[${1}-${2}]: ${t}"
+ printf "\033[0;33m%s\033[0m\n\n" "################################################################################"
+ time ${t} devilbox/php-fpm ${1} ${2}
+ done
+fi
+
+if [ "${2}" = "prod" ] || [ "${2}" = "work" ]; then
+ for t in "${PROD_TESTS[@]}"; do
+ printf "\n\n\033[0;33m%s\033[0m\n" "################################################################################"
+ printf "\033[0;33m%s %s\033[0m\n" "#" "[${1}-${2}]: ${t}"
+ printf "\033[0;33m%s\033[0m\n\n" "################################################################################"
+ time ${t} devilbox/php-fpm ${1} ${2}
+ done
+fi
+
+if [ "${2}" = "work" ]; then
+ for t in "${WORK_TESTS[@]}"; do
+ printf "\n\n\033[0;33m%s\033[0m\n" "################################################################################"
+ printf "\033[0;33m%s %s\033[0m\n" "#" "[${1}-${2}]: ${t}"
+ printf "\033[0;33m%s\033[0m\n\n" "################################################################################"
+ time ${t} devilbox/php-fpm ${1} ${2}
+ done
+fi