From bf58be8d4de2c39ad04e56c626f575e20f0bb642 Mon Sep 17 00:00:00 2001 From: Oliver Davies Date: Fri, 15 Dec 2023 14:09:09 +0000 Subject: [PATCH] Add snapshot tests for a basic Drupal project --- .gitignore | 1 + run | 52 ++++++- tests/snapshots/configs/drupal.yaml | 43 ++++++ tests/snapshots/output/drupal/.dockerignore | 2 + tests/snapshots/output/drupal/.env.example | 12 ++ .../output/drupal/.githooks/pre-push | 9 ++ .../drupal/.githooks/prepare-commit-msg | 27 ++++ .../output/drupal/.github/workflows/ci.yml | 25 ++++ tests/snapshots/output/drupal/.gitignore | 42 ++++++ tests/snapshots/output/drupal/.hadolint.yaml | 2 + tests/snapshots/output/drupal/Dockerfile | 64 +++++++++ .../output/drupal/docker-compose.yaml | 77 +++++++++++ tests/snapshots/output/drupal/phpcs.xml.dist | 32 +++++ .../snapshots/output/drupal/phpstan.neon.dist | 9 ++ .../snapshots/output/drupal/phpunit.xml.dist | 37 +++++ tests/snapshots/output/drupal/run | 129 ++++++++++++++++++ .../root/usr/local/bin/docker-entrypoint-php | 7 + .../images/php/root/usr/local/etc/php/php.ini | 4 + 18 files changed, 572 insertions(+), 2 deletions(-) create mode 100644 tests/snapshots/configs/drupal.yaml create mode 100644 tests/snapshots/output/drupal/.dockerignore create mode 100644 tests/snapshots/output/drupal/.env.example create mode 100755 tests/snapshots/output/drupal/.githooks/pre-push create mode 100755 tests/snapshots/output/drupal/.githooks/prepare-commit-msg create mode 100644 tests/snapshots/output/drupal/.github/workflows/ci.yml create mode 100644 tests/snapshots/output/drupal/.gitignore create mode 100644 tests/snapshots/output/drupal/.hadolint.yaml create mode 100644 tests/snapshots/output/drupal/Dockerfile create mode 100644 tests/snapshots/output/drupal/docker-compose.yaml create mode 100644 tests/snapshots/output/drupal/phpcs.xml.dist create mode 100644 tests/snapshots/output/drupal/phpstan.neon.dist create mode 100644 tests/snapshots/output/drupal/phpunit.xml.dist create mode 100755 tests/snapshots/output/drupal/run create mode 100755 tests/snapshots/output/drupal/tools/docker/images/php/root/usr/local/bin/docker-entrypoint-php create mode 100644 tests/snapshots/output/drupal/tools/docker/images/php/root/usr/local/etc/php/php.ini diff --git a/.gitignore b/.gitignore index 73dfcb2..48c4173 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /.direnv /dist/* !/dist/.keep +.ignored/ ###> symfony/framework-bundle ### /.env.local diff --git a/run b/run index d79eeef..ac5f5df 100755 --- a/run +++ b/run @@ -28,7 +28,7 @@ function build { # Generate the phar file. box compile --config box.json.dist - rm -f .env.local.php + rm -f .env.local .env.local.php tree dist/ @@ -37,6 +37,7 @@ function build { function ci:test { nix develop --command composer install + nix develop --command ./run test:snapshots nix develop --command phpunit } @@ -49,10 +50,57 @@ function help { printf "\nExtended help:\n Each task has comments for general usage\n" } - function test { phpunit "${@}" } +# Create a new snapshot for a configuration based on generated files. +function test:create-snapshot { + set -o nounset + config="${1}" + + input_path="tests/snapshots/output/${config}" + output_path=".ignored/snapshots/output/${config}" + + rm -fr "${input_path}" + cp -r "${output_path}" "${input_path}" + + git status "${input_path}" +} + +# Generate a file and ensure it matches the expected version. +function test:snapshots { + rm -rf .ignored/snapshots + mkdir -p .ignored/snapshots + + local configs=( + # TODO: add more configurations for different types and configurations. + drupal + ) + + for config in "${configs[@]}"; do + config_file="tests/snapshots/configs/${config}.yaml" + input_path="tests/snapshots/output/${config}" + output_path=".ignored/snapshots/output/${config}" + + cat "${config_file}" + + ./bin/build-configs app:generate --config-file "${config_file}" --output-dir "${output_path}" + + find "${input_path}" -type f -print0 | while IFS= read -r -d '' original_file; do + generated_file="$output_path/${original_file#"${input_path}"/}" + + if cmp -s "${original_file}" "${generated_file}"; then + echo "Files match: ${original_file}" + else + # TODO: show the diff for all failed files. This will stop after the first failure. + echo "Files do not match: ${original_file}" + diff "${original_file}" "${generated_file}" + exit 1 + fi + done + done +} + TIMEFORMAT=$'\nTask completed in %3lR' time "${@:-help}" diff --git a/tests/snapshots/configs/drupal.yaml b/tests/snapshots/configs/drupal.yaml new file mode 100644 index 0000000..a24b5cc --- /dev/null +++ b/tests/snapshots/configs/drupal.yaml @@ -0,0 +1,43 @@ +name: drupal +language: php +type: drupal + +web: + type: nginx + +database: + type: mariadb + version: 10 + +php: + version: 8.1-fpm-bullseye + phpcs: + paths: + - web/modules/custom + standards: + - Drupal + - DrupalPractice + phpstan: + level: max + paths: + - web/modules/custom + +drupal: + docroot: web + +docker-compose: + services: + - database + - php + - web + +dockerfile: + stages: + build: + commands: + - composer validate + - composer install + +experimental: + createGitHubActionsConfiguration: true + runGitHooksBeforePush: true diff --git a/tests/snapshots/output/drupal/.dockerignore b/tests/snapshots/output/drupal/.dockerignore new file mode 100644 index 0000000..61d63c0 --- /dev/null +++ b/tests/snapshots/output/drupal/.dockerignore @@ -0,0 +1,2 @@ +/README.md +/.github/ \ No newline at end of file diff --git a/tests/snapshots/output/drupal/.env.example b/tests/snapshots/output/drupal/.env.example new file mode 100644 index 0000000..ed69226 --- /dev/null +++ b/tests/snapshots/output/drupal/.env.example @@ -0,0 +1,12 @@ +# Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs. + +export DOCKER_UID=1000 + +export COMPOSE_PROJECT_NAME=drupal +export COMPOSE_PROFILES=web,php,database + +export DOCKER_WEB_VOLUME=.:/app + +export MYSQL_DATABASE=app +export MYSQL_PASSWORD=app +export MYSQL_USER=app diff --git a/tests/snapshots/output/drupal/.githooks/pre-push b/tests/snapshots/output/drupal/.githooks/pre-push new file mode 100755 index 0000000..54ac104 --- /dev/null +++ b/tests/snapshots/output/drupal/.githooks/pre-push @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +# Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs. + +set -o errexit + +export TTY="-T" + +./run test:commit diff --git a/tests/snapshots/output/drupal/.githooks/prepare-commit-msg b/tests/snapshots/output/drupal/.githooks/prepare-commit-msg new file mode 100755 index 0000000..6ff8ea0 --- /dev/null +++ b/tests/snapshots/output/drupal/.githooks/prepare-commit-msg @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs. + +# Load the issue ID from an `.issue-id` file within the project and replace the +# `ISSUE_ID` placeholder within a Git commit message. +# +# For example, running `echo "OD-123" > .issue-id` will add `Refs: OD-123` to +# the commit message. +# +# This also works with multiple issue IDs in the same string, e.g. +# "OD-123 OD-456", or IDs on multiple lines. + +set -o errexit +set -o nounset +set -o pipefail + +PROJECT_DIR=$(git rev-parse --show-toplevel) +ISSUE_FILE="$PROJECT_DIR/.issue-id" + +if [ -f "${ISSUE_FILE}" ]; then + ISSUE_IDS=$(cat "${ISSUE_FILE}" | tr '\n' ',' | tr ' ' ',' | sed 's/,$//' | sed 's/,/, /g') + + if [ -n "${ISSUE_IDS}" ]; then + sed -i.bak "s/# Refs:/Refs: $ISSUE_IDS/" "$1" + fi +fi diff --git a/tests/snapshots/output/drupal/.github/workflows/ci.yml b/tests/snapshots/output/drupal/.github/workflows/ci.yml new file mode 100644 index 0000000..868fe2e --- /dev/null +++ b/tests/snapshots/output/drupal/.github/workflows/ci.yml @@ -0,0 +1,25 @@ +name: CI + +on: + pull_request: + push: + workflow_dispatch: + +env: + COMPOSE_DOCKER_CLI_BUILD: 1 + DOCKER_BUILDKIT: 1 + DOCKER_UID: 1001 + +jobs: + build_and_test: + name: Build and test + + runs-on: ubuntu-latest + + steps: + - name: Checkout the code + uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 + + - name: Build and test + run: | + ./run ci:test diff --git a/tests/snapshots/output/drupal/.gitignore b/tests/snapshots/output/drupal/.gitignore new file mode 100644 index 0000000..f1df0c3 --- /dev/null +++ b/tests/snapshots/output/drupal/.gitignore @@ -0,0 +1,42 @@ +# Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs. + +.editorconfig +.env +.gitattributes +vendor/ +web/.csslintrc +web/.eslintignore +web/.eslintrc.json +web/.ht.router.php +web/.htaccess +web/INSTALL.txt +web/README.md +web/autoload.php +web/core/ +web/example.gitignore +web/index.php +web/modules/README.txt +web/modules/contrib/ +web/profiles/README.txt +web/robots.txt +web/sites/*/files/ +web/sites/*/private/ +web/sites/*/services*.yml +web/sites/*/settings*.php +web/sites/README.txt +web/sites/default/default.services.yml +web/sites/default/default.settings.php +web/sites/development.services.yml +web/sites/example.settings.local.php +web/sites/example.sites.php +web/sites/simpletest/ +web/themes/README.txt +web/themes/contrib/ +web/update.php +web/web.config + +# Docker. +.env +docker-compose.override.yaml + + diff --git a/tests/snapshots/output/drupal/.hadolint.yaml b/tests/snapshots/output/drupal/.hadolint.yaml new file mode 100644 index 0000000..d87bf88 --- /dev/null +++ b/tests/snapshots/output/drupal/.hadolint.yaml @@ -0,0 +1,2 @@ +ignore: + - DL3059 diff --git a/tests/snapshots/output/drupal/Dockerfile b/tests/snapshots/output/drupal/Dockerfile new file mode 100644 index 0000000..7164bf6 --- /dev/null +++ b/tests/snapshots/output/drupal/Dockerfile @@ -0,0 +1,64 @@ +# Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs. + +FROM php:8.1-fpm-bullseye AS base + +COPY --from=composer:2 /usr/bin/composer /usr/bin/composer +RUN which composer && composer -V + +ARG DOCKER_UID=1000 +ENV DOCKER_UID="${DOCKER_UID}" + +WORKDIR /app + +RUN adduser --disabled-password --uid "${DOCKER_UID}" app \ + && chown app:app -R /app + +USER app + +ENV PATH="${PATH}:/app/bin:/app/vendor/bin" + +COPY --chown=app:app composer.* ./ + +################################################################################ + +FROM base AS build + +USER root + + +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + git libpng-dev libjpeg-dev libzip-dev mariadb-client unzip \ + && rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man \ + && apt-get clean + +RUN docker-php-ext-configure gd --with-jpeg + +RUN docker-php-ext-install gd pdo_mysql zip + +COPY --chown=app:app phpunit.xml* ./ + + + +USER app + +RUN composer validate +RUN composer install + +COPY --chown=app:app tools/docker/images/php/root / + +ENTRYPOINT ["/usr/local/bin/docker-entrypoint-php"] +CMD ["php-fpm"] + + + + +################################################################################ + +FROM nginx:1 as web + +EXPOSE 8080 + +WORKDIR /app + +COPY tools/docker/images/web/root / diff --git a/tests/snapshots/output/drupal/docker-compose.yaml b/tests/snapshots/output/drupal/docker-compose.yaml new file mode 100644 index 0000000..fa1f56c --- /dev/null +++ b/tests/snapshots/output/drupal/docker-compose.yaml @@ -0,0 +1,77 @@ +# Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs. + +x-proxy: &default-proxy + networks: + - default + - web + labels: + - "traefik.docker.network=traefik_proxy" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=Host( + `${COMPOSE_PROJECT_NAME}.localhost`, + )" + +x-app: &default-app + volumes: + - "${DOCKER_WEB_VOLUME:-./web:/app/web}" + env_file: + - .env + restart: "${DOCKER_RESTART_POLICY:-unless-stopped}" + networks: + - default + deploy: + resources: + limits: + cpus: "${DOCKER_MYSQL_CPUS:-0}" + memory: "${DOCKER_MYSQL_MEMORY:-0}" + labels: + - "traefik.enabled=false" + tty: true + +services: + web: + <<: [*default-proxy, *default-app] + build: + context: . + target: web + depends_on: + - php + profiles: [web] + + php: + <<: [*default-app] + build: + context: . + target: build + args: + - "DOCKER_UID=${DOCKER_UID:-1000}" + volumes: + - .:/app + depends_on: + - database + profiles: [php] + + database: + image: mariadb:10 + deploy: + resources: + limits: + cpus: "${DOCKER_MYSQL_CPUS:-0}" + memory: "${DOCKER_MYSQL_MEMORY:-0}" + volumes: + - db-data:/var/lib/mysql + + env_file: + - .env + labels: + - "traefik.enabled=false" + environment: + MYSQL_RANDOM_ROOT_PASSWORD: true + profiles: [database] + +volumes: + db-data: {} + +networks: + web: + external: true + name: traefik_proxy diff --git a/tests/snapshots/output/drupal/phpcs.xml.dist b/tests/snapshots/output/drupal/phpcs.xml.dist new file mode 100644 index 0000000..f9e7395 --- /dev/null +++ b/tests/snapshots/output/drupal/phpcs.xml.dist @@ -0,0 +1,32 @@ + + + + + PHPCS configuration file for drupal. + + web/modules/custom + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/snapshots/output/drupal/phpstan.neon.dist b/tests/snapshots/output/drupal/phpstan.neon.dist new file mode 100644 index 0000000..a5a696c --- /dev/null +++ b/tests/snapshots/output/drupal/phpstan.neon.dist @@ -0,0 +1,9 @@ +# Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs. + +parameters: + level: max + excludePaths: + - *Test.php + - *TestBase.php + paths: + - web/modules/custom diff --git a/tests/snapshots/output/drupal/phpunit.xml.dist b/tests/snapshots/output/drupal/phpunit.xml.dist new file mode 100644 index 0000000..179546d --- /dev/null +++ b/tests/snapshots/output/drupal/phpunit.xml.dist @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + ./web/modules/custom/**/tests/**/Functional + + + ./web/modules/custom/**/tests/**/Kernel + + + ./web/modules/custom/**/tests/**/Unit + + + diff --git a/tests/snapshots/output/drupal/run b/tests/snapshots/output/drupal/run new file mode 100755 index 0000000..c70906a --- /dev/null +++ b/tests/snapshots/output/drupal/run @@ -0,0 +1,129 @@ +#!/usr/bin/env bash + +# Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs. + +set -o errexit +set -o pipefail + +# If we're running in CI we need to disable TTY allocation for docker compose +# commands that enable it by default, such as exec and run. +TTY="${TTY:-}" +if [[ ! -t 1 ]]; then + TTY="-T" +fi + +# Run automated tests as part of the Continuous Integration (CI) pipeline. +function ci:test { + lint:dockerfile + + docker compose version + + docker network create traefik_proxy + + cp --no-clobber .env.example .env + + docker compose build --progress plain + + docker compose up --detach + docker compose logs + + composer install --quiet --no-progress + + test --testdox + + quality +} + +# Run a command within the php container. +function cmd { + docker compose exec php "${@}" +} + +function coding-standards { + cmd phpcs "${@}" +} + +function composer { + _exec php composer "${@}" +} + +function drush { + _exec php drush "${@}" +} + +function git-hooks:off { + git config --unset core.hooksPath +} + +function git-hooks:on { + git config core.hooksPath .githooks +} + +# Display a list of all available commands. +function help { + printf "%s [args]\n\nTasks:\n" "${0}" + + compgen -A function | grep -v "^_" | cat -n + + printf "\nExtended help:\n Each task has comments for general usage\n" +} + +function lint:dockerfile { + docker container run --rm -i \ + hadolint/hadolint hadolint --ignore DL3008 --ignore DL3059 -t style "${@}" - < Dockerfile +} + +function quality { + coding-standards + static-analysis +} + +function start { + cp -v --no-clobber .env.example .env + + docker compose up -d +} + +function static-analysis { + cmd phpstan --memory-limit=-1 --no-progress "${@}" +} + +function stop { + docker compose down +} + +function test { + _exec php phpunit --colors=always "${@}" +} + +function test:commit { + test --testdox --testsuite functional + test --testdox --testsuite kernel + test --testdox --testsuite unit + + quality +} + +function _exec { + docker compose exec ${TTY} "${@}" +} + +function _run { + local service="${1}" + local command="${2}" + + docker compose run \ + --entrypoint "${command}" \ + --no-deps \ + --rm \ + ${TTY} \ + "${service}" "${@}" +} + +# Include any local tasks. +[[ -e run.local ]] && source run.local + +TIMEFORMAT=$'\nTask completed in %3lR' +time "${@:-help}" + +# vim: ft=bash diff --git a/tests/snapshots/output/drupal/tools/docker/images/php/root/usr/local/bin/docker-entrypoint-php b/tests/snapshots/output/drupal/tools/docker/images/php/root/usr/local/bin/docker-entrypoint-php new file mode 100755 index 0000000..dbd9900 --- /dev/null +++ b/tests/snapshots/output/drupal/tools/docker/images/php/root/usr/local/bin/docker-entrypoint-php @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +# Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs. + +[[ -f composer.json && ! -d vendor ]] && composer install + +eval "$@" diff --git a/tests/snapshots/output/drupal/tools/docker/images/php/root/usr/local/etc/php/php.ini b/tests/snapshots/output/drupal/tools/docker/images/php/root/usr/local/etc/php/php.ini new file mode 100644 index 0000000..aa883a1 --- /dev/null +++ b/tests/snapshots/output/drupal/tools/docker/images/php/root/usr/local/etc/php/php.ini @@ -0,0 +1,4 @@ +# Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs. + +max_vars_input = 1000 +memory_limit = 128M