From 63a490d87dbe3cfa2c488582a7812bbbf0ff120a Mon Sep 17 00:00:00 2001 From: Dennis Meckel Date: Sat, 20 Feb 2021 19:54:50 +0100 Subject: [PATCH] Add convenience scripts for building and running application and development containers --- .gitignore | 1 + CHANGELOG.md | 2 ++ README.md | 13 ++++++-- docker/README.md | 61 +++++++++++++++++++++++++++++++++++ docker/bin/build-all | 63 +++++++++++++++++++++++++++++++++++++ docker/bin/run | 35 +++++++++++++++++++++ docker/bin/test-all | 75 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 docker/README.md create mode 100755 docker/bin/build-all create mode 100755 docker/bin/run create mode 100755 docker/bin/test-all diff --git a/.gitignore b/.gitignore index 0007e59..dc4c674 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .php_cs.cache build +builds composer.lock vendor diff --git a/CHANGELOG.md b/CHANGELOG.md index e4a3e4f..ed45a8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ This project adheres to [Semantic Versioning](http://semver.org). * Added support for PHP 7.3, PHP 7.4 and 8.0 * Added Dockerfiles for PHP 7.2, 7.3, 7.4 and 8.0 * The application's Docker image is now utilizing PHP 8.0 +* Added convenience scripts to build all container variants +* Added convenience scripts to run unit tests in development containers ## [1.1.0] diff --git a/README.md b/README.md index 1bb9d70..05fc5a9 100644 --- a/README.md +++ b/README.md @@ -120,8 +120,17 @@ docker run -it --rm -v /my/message:/file rayne/ecoji /file cat /my/message | docker run -i --rm rayne/ecoji ``` -### Build Image +### Docker Images + +The [`docker/README.md`](docker/README.md) explains how to build the application and all optional development images for all supported PHP versions. +Additional convenience scripts run the unit tests with all supported PHP versions. + +## Tests + +The library registers the test runner as composer script. ```bash -docker build -t rayne/ecoji:"$(cat assets/version.txt)" -t rayne/ecoji:latest . +composer test ``` + +All units tests can also be run in the development containers specified in the `docker` directory. diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..e8c5172 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,61 @@ +# Docker Images + +## Files + +- `app`: + Contains the `Dockerfile` for the CLI application + +- `bin`: + This directory contains convenience scripts + + - `bin/build-all`: + Builds the application image and all development images + + - `bin/run`: + Forwards the given arguments to a container running the specified development container, + e.g. `run 8.0 composer test` runs the unit tests inside a development container with PHP 8.0 + + - `bin/test-all`: + Runs unit tests in all supported development containers. + Reports and reusable files for later runs are written to `/builds/$version-dev-php-$php_version`. + As a consequence, bandwidth and time is saved. + Since every application and PHP version has a dedicated directory, + reports are not overwritten by runs with different versions + +- `dev-php-*`: + These directories contain `Dockerfile` files that build development environments for all supported PHP version. + +## Docker Example + +If one does not want to use the previously mentioned convenience scripts, +this is (almost) the second simplest solution to build and execute a development image. + +```bash +cd .. + +docker build \ + -f docker/dev-php-8.0/Dockerfile \ + -t rayne/ecoji:dev-php-8.0 \ + . + +docker run --rm -ti \ + --user "$UID:$UID" \ + --workdir /app \ + -v "$(pwd):/app:rw" \ + rayne/ecoji:dev-php-8.0 composer update + +docker run --rm -ti \ + --user "$UID:$UID" \ + --workdir /app \ + -v "$(pwd):/app:rw" \ + rayne/ecoji:dev-php-8.0 composer test +``` + +The same can be accomplished by building all development images first +and then executing the same `composer` commands. + +```bash +./bin/build-all +./bin/run 8.0 composer update +./bin/run 8.0 composer test +``` diff --git a/docker/bin/build-all b/docker/bin/build-all new file mode 100755 index 0000000..1274a9b --- /dev/null +++ b/docker/bin/build-all @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +set -eux + +cd "$(dirname "$0")/../.." +version="$(cat assets/version.txt)" + +build_app() { + echo "Build app version $version with PHP-8" + + docker build \ + -f docker/app/Dockerfile \ + -t rayne/ecoji:"$version-app" \ + -t rayne/ecoji:"$version" \ + -t rayne/ecoji:latest \ + . +} + +build_dev_8_0() { + echo "Build development version $version with PHP-8.0" + + docker build \ + -f docker/dev-php-8.0/Dockerfile \ + -t rayne/ecoji:"$version-dev-php-8.0" \ + -t rayne/ecoji:"$version-dev-php-8" \ + . +} + +build_dev_7_4() { + echo "Build development version $version with PHP-7.4" + + docker build \ + -f docker/dev-php-7.4/Dockerfile \ + -t rayne/ecoji:"$version-dev-php-7.4" \ + -t rayne/ecoji:"$version-dev-php-7" \ + . +} + +build_dev_7_3() { + echo "Build development version $version with PHP-7.3" + + docker build \ + -f docker/dev-php-7.3/Dockerfile \ + -t rayne/ecoji:"$version-dev-php-7.3" \ + . +} + +build_dev_7_2() { + echo "Build development version $version with PHP-7.2" + + docker build \ + -f docker/dev-php-7.3/Dockerfile \ + -t rayne/ecoji:"$version-dev-php-7.2" \ + . +} + +build_app +build_dev_8_0 +build_dev_7_4 +build_dev_7_3 +build_dev_7_2 + +docker images | grep rayne/ecoji diff --git a/docker/bin/run b/docker/bin/run new file mode 100755 index 0000000..b15b5dd --- /dev/null +++ b/docker/bin/run @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +set -eu + +TEST_USER=${TEST_USER:-1000} +TEST_GROUP=${TEST_GROUP:-"$TEST_USER"} + +cd "$(dirname "$0")/../.." + +PROJECT_DIR="$(pwd)" + +version=$(cat assets/version.txt) + +if [[ "${1-}" == "" ]]; then + echo "Usage: $0 PHP_VERSION [ARGUMENTS]" + echo + echo "Available PHP versions:" + docker images | grep rayne/ecoji | grep dev + echo + echo "> $0 8.0 composer test" + echo + echo 'runs the unit tests in a PHP 8.0 environment.' + exit 1 +fi + +tag="$version-dev-php-$1" +shift + +image="rayne/ecoji:$tag" + +docker run --rm -ti \ + --user "$TEST_USER:$TEST_GROUP" \ + --workdir /app \ + -v "$PROJECT_DIR:/app:rw" \ + "$image" "$@" diff --git a/docker/bin/test-all b/docker/bin/test-all new file mode 100755 index 0000000..bea0231 --- /dev/null +++ b/docker/bin/test-all @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# +# This script updates the dependencies and runs the unit tests with multiple PHP versions. +# Dependencies are installed and results are written to `/builds/$version-dev-php-$php_version`. +# The script utilizes the Docker images built with `build-all`. +# Run the build script first. +# Otherwise updates and tests will fail. +# + +set -eux + +TEST_USER=${TEST_USER:-1000} +TEST_GROUP=${TEST_GROUP:-"$TEST_USER"} + +version=$(cat assets/version.txt) + +tags=( + "$version"-dev-php-8.0 + "$version"-dev-php-7.4 + "$version"-dev-php-7.3 + "$version"-dev-php-7.2 +) + +cd "$(dirname "$0")/../.." +[ -d build ] || mkdir build + +PROJECT_DIR="$(pwd)" + +execute_in_docker(){ + local tag="$1" + local image="rayne/ecoji:$tag" + shift + + local output_dir="$PROJECT_DIR/builds/$tag" + + install -o "$TEST_USER" -g "$TEST_GROUP" -m 755 -d "$PROJECT_DIR/builds" + install -o "$TEST_USER" -g "$TEST_GROUP" -m 755 -d "$output_dir" + + # Create output directories. + local build_dir="$output_dir" + local composer_dir="$output_dir/composer" + local report_dir="$output_dir/report" + local vendor_dir="$output_dir/vendor" + + install -o "$TEST_USER" -g "$TEST_GROUP" -m 755 -d "$composer_dir" + install -o "$TEST_USER" -g "$TEST_GROUP" -m 755 -d "$report_dir" + install -o "$TEST_USER" -g "$TEST_GROUP" -m 755 -d "$vendor_dir" + + # Create empty composer file if the file does not exist yet. + local composer_lock_file="$output_dir/composer.lock" + + touch "$composer_lock_file" + chmod 775 "$composer_lock_file" + chown "$TEST_USER:$TEST_GROUP" "$composer_lock_file" + + if ! docker run --rm -ti \ + --user "$TEST_USER:$TEST_GROUP" \ + --workdir /app \ + -v "$PROJECT_DIR:/app:rw" \ + -v "$build_dir:/app/build:rw" \ + -v "$composer_dir:/home/user/.composer:rw" \ + -v "$composer_lock_file:/app/composer.lock:rw" \ + -v "$vendor_dir:/app/vendor:rw" \ + "$image" "$@"; then + echo + echo "The test failed with image: $image" + + exit $? + fi +} + +for tag in "${tags[@]}"; do + execute_in_docker "$tag" composer update + execute_in_docker "$tag" composer test +done