From 6d88474d213213a8479d00a5499fe27dbb6ac396 Mon Sep 17 00:00:00 2001 From: Twyco Date: Thu, 10 Sep 2026 20:42:33 +0200 Subject: [PATCH] docker & action setup --- .github/dependabot.yml | 12 -- .github/tests/test_and_check_app/action.yml | 18 ++ .github/workflows/ci_cd.yml | 149 ++++++++++++++++ .github/workflows/tests.yml | 38 ---- Dockerfile | 121 +++++++++++++ composer.json | 7 +- docker-compose.yml | 109 ++++++++++++ docker/entrypoint.sh | 26 +++ docker/nginx/nginx.conf.template | 60 +++++++ docker/php-fpm-healthcheck.sh | 7 + package-lock.json | 181 +------------------- phpunit.xml | 1 + 12 files changed, 504 insertions(+), 225 deletions(-) delete mode 100644 .github/dependabot.yml create mode 100644 .github/tests/test_and_check_app/action.yml create mode 100644 .github/workflows/ci_cd.yml delete mode 100644 .github/workflows/tests.yml create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 docker/entrypoint.sh create mode 100644 docker/nginx/nginx.conf.template create mode 100644 docker/php-fpm-healthcheck.sh diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index ae67c4d..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - cooldown: - default-days: 5 - groups: - github-actions: - patterns: - - "*" diff --git a/.github/tests/test_and_check_app/action.yml b/.github/tests/test_and_check_app/action.yml new file mode 100644 index 0000000..dfd1c65 --- /dev/null +++ b/.github/tests/test_and_check_app/action.yml @@ -0,0 +1,18 @@ +name: test_and_check_app +description: Build the test image and run all application checks + +runs: + using: composite + steps: + - name: Test and check app + shell: bash + run: | + set -Eeuo pipefail + + docker buildx build \ + --file Dockerfile \ + --target test \ + --tag "local/scrum-poker-internal-test:${GITHUB_SHA}" \ + --progress plain \ + --load \ + . diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml new file mode 100644 index 0000000..42213a3 --- /dev/null +++ b/.github/workflows/ci_cd.yml @@ -0,0 +1,149 @@ +name: CI/CD + +on: + push: + pull_request: + +permissions: + contents: read + +env: + REGISTRY: git.twyco.de + +jobs: + test_and_check_app: + name: test_and_check_app + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + + - name: Run required application checks + uses: ./.github/tests/test_and_check_app + + publish: + name: Publish immutable image + if: >- + github.event_name == 'push' && + (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')) + needs: + - test_and_check_app + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + fetch-depth: 0 + + - name: Validate ref and calculate image name + id: image + shell: bash + run: | + set -Eeuo pipefail + + image_path="$(printf '%s' "${GITHUB_REPOSITORY}" | tr '[:upper:]' '[:lower:]')" + image="${REGISTRY}/${image_path}" + + case "${GITHUB_REF}" in + refs/heads/main) + printf -v run_attempt '%03d' "${GITHUB_RUN_ATTEMPT}" + tag="main-${GITHUB_RUN_NUMBER}-${run_attempt}-${GITHUB_SHA:0:12}" + environment="staging" + vite_app_version="main-${GITHUB_SHA:0:12}" + vite_reverb_app_key="1af96b48d2ef78983e4ef281eed3a48b" + vite_reverb_host="scrum-poker.twyco-staging.de" + ;; + refs/tags/*) + tag="${GITHUB_REF#refs/tags/}" + + if [[ ! "${tag}" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then + echo "Production tags must match vMAJOR.MINOR.PATCH." >&2 + exit 1 + fi + + git fetch --no-tags origin main:refs/remotes/origin/main + + if ! git merge-base --is-ancestor "${GITHUB_SHA}" origin/main; then + echo "Production tag must point to a commit contained in main." >&2 + exit 1 + fi + + environment="production" + vite_app_version="${tag}" + vite_reverb_app_key="cfd9d925ff339374c04997beb90fbc32" + vite_reverb_host="scrum-poker.petsch-studios.de" + ;; + *) + echo "Unsupported ref: ${GITHUB_REF}" >&2 + exit 1 + ;; + esac + + { + echo "image=${image}" + echo "tag=${tag}" + echo "environment=${environment}" + echo "vite_app_version=${vite_app_version}" + echo "vite_reverb_app_key=${vite_reverb_app_key}" + echo "vite_reverb_host=${vite_reverb_host}" + } >> "${GITHUB_OUTPUT}" + + - name: Log in to private registry + shell: bash + env: + REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} + REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + run: | + set -Eeuo pipefail + + if [[ -z "${REGISTRY_USERNAME}" || -z "${REGISTRY_TOKEN}" ]]; then + echo "Registry credentials are missing." >&2 + exit 1 + fi + + printf '%s' "${REGISTRY_TOKEN}" | + docker login \ + --username "${REGISTRY_USERNAME}" \ + --password-stdin \ + "${REGISTRY}" + + - name: Build and publish runtime image + shell: bash + env: + IMAGE: ${{ steps.image.outputs.image }} + IMAGE_TAG: ${{ steps.image.outputs.tag }} + DEPLOYMENT_ENVIRONMENT: ${{ steps.image.outputs.environment }} + VITE_APP_VERSION: ${{ steps.image.outputs.vite_app_version }} + VITE_REVERB_APP_KEY: ${{ steps.image.outputs.vite_reverb_app_key }} + VITE_REVERB_HOST: ${{ steps.image.outputs.vite_reverb_host }} + VITE_REVERB_PORT: "443" + VITE_REVERB_SCHEME: https + run: | + set -Eeuo pipefail + + if [[ "${DEPLOYMENT_ENVIRONMENT}" == "production" ]] && + docker buildx imagetools inspect "${IMAGE}:${IMAGE_TAG}" >/dev/null 2>&1; then + echo "Production image ${IMAGE}:${IMAGE_TAG} already exists and will not be overwritten." >&2 + exit 1 + fi + + docker buildx build \ + --file Dockerfile \ + --target runtime \ + --build-arg "VITE_APP_VERSION=${VITE_APP_VERSION}" \ + --build-arg "VITE_REVERB_APP_KEY=${VITE_REVERB_APP_KEY}" \ + --build-arg "VITE_REVERB_HOST=${VITE_REVERB_HOST}" \ + --build-arg "VITE_REVERB_PORT=${VITE_REVERB_PORT}" \ + --build-arg "VITE_REVERB_SCHEME=${VITE_REVERB_SCHEME}" \ + --label "org.opencontainers.image.created=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + --label "org.opencontainers.image.revision=${GITHUB_SHA}" \ + --label "org.opencontainers.image.source=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" \ + --label "de.twyco.environment=${DEPLOYMENT_ENVIRONMENT}" \ + --tag "${IMAGE}:${IMAGE_TAG}" \ + --push \ + . + + - name: Remove registry credentials + if: ${{ always() }} + shell: bash + run: docker logout "${REGISTRY}" >/dev/null 2>&1 || true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index 86de102..0000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: tests - -on: - push: - branches: - - main - pull_request: - -permissions: - contents: read - -jobs: - ci: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - - name: Setup PHP - uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2 - with: - php-version: '8.4' - tools: composer:v2 - coverage: none - - - name: Setup Node - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: '22' - - - name: Setup Application - run: composer setup - - - name: Run CI Checks - run: composer ci:check diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d107f92 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,121 @@ +ARG COMPOSER_IMAGE=composer:2.9.5@sha256:698d3801b2a622ace460c4743c781282fcbcb733a4cbf8b31c44731e846585e8 +ARG NODE_IMAGE=node:22-bookworm-slim@sha256:d649c27dae7ba0137b3cef5dd75baa422c08dc3d9e3fc0c23dfb172dc3cc6436 +ARG PHP_IMAGE=php:8.4-fpm-bookworm@sha256:c5fb7a0c02f4efe280691910c8b734995fa83598cdcf3115ef5dcb2e4617681c + +FROM ${COMPOSER_IMAGE} AS composer_binary +FROM ${NODE_IMAGE} AS node_binary + +FROM ${PHP_IMAGE} AS php_base + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + gettext-base \ + git \ + libfcgi-bin \ + libfreetype6-dev \ + libicu-dev \ + libjpeg62-turbo-dev \ + libmagickwand-dev \ + libonig-dev \ + libpng-dev \ + libpq-dev \ + libsqlite3-dev \ + libssl-dev \ + libxml2-dev \ + libzip-dev \ + nginx \ + procps \ + unzip \ + && docker-php-ext-configure gd --with-freetype --with-jpeg \ + && docker-php-ext-install -j"$(nproc)" \ + bcmath \ + gd \ + intl \ + opcache \ + pcntl \ + pdo_mysql \ + pdo_pgsql \ + pdo_sqlite \ + pgsql \ + soap \ + zip \ + && pecl install imagick \ + && docker-php-ext-enable imagick \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +COPY --from=composer_binary /usr/bin/composer /usr/local/bin/composer + +WORKDIR /var/www + +FROM php_base AS build + +ARG VITE_APP_VERSION=local +ARG VITE_REVERB_APP_KEY +ARG VITE_REVERB_HOST +ARG VITE_REVERB_PORT +ARG VITE_REVERB_SCHEME + +ENV VITE_APP_VERSION=${VITE_APP_VERSION} \ + VITE_REVERB_APP_KEY=${VITE_REVERB_APP_KEY} \ + VITE_REVERB_HOST=${VITE_REVERB_HOST} \ + VITE_REVERB_PORT=${VITE_REVERB_PORT} \ + VITE_REVERB_SCHEME=${VITE_REVERB_SCHEME} + +COPY --from=node_binary /usr/local/ /usr/local/ +COPY . /var/www + +RUN composer install --prefer-dist --no-interaction --no-progress \ + && npm ci \ + && npm run build + +FROM build AS test + +RUN touch .env \ + && composer audit --locked --no-interaction \ + && COMPOSER_ALLOW_SUPERUSER=1 composer ci:check + +FROM build AS production_builder + +RUN composer install \ + --classmap-authoritative \ + --no-dev \ + --no-interaction \ + --no-progress \ + --prefer-dist \ + && rm -rf node_modules tests phpunit.xml + +FROM php_base AS runtime + +COPY docker/entrypoint.sh /usr/local/bin/laravel-entrypoint +COPY docker/nginx/nginx.conf.template /etc/nginx/nginx.conf.template +COPY docker/php-fpm-healthcheck.sh /usr/local/bin/php-fpm-healthcheck +COPY --from=production_builder --chown=www-data:www-data /var/www /var/www + +RUN chmod +x /usr/local/bin/laravel-entrypoint /usr/local/bin/php-fpm-healthcheck \ + && mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \ + && printf '%s\n' \ + '[global]' \ + 'daemonize = no' \ + '' \ + '[www]' \ + 'pm.status_path = /status' \ + > /usr/local/etc/php-fpm.d/zz-laravel.conf \ + && mkdir -p \ + /var/www/bootstrap/cache \ + /var/www/storage/app/public \ + /var/www/storage/framework/cache \ + /var/www/storage/framework/sessions \ + /var/www/storage/framework/testing \ + /var/www/storage/framework/views \ + /var/www/storage/logs \ + && ln -s ../storage/app/public /var/www/public/storage \ + && chown -R www-data:www-data /var/www/bootstrap/cache /var/www/storage + +USER www-data + +EXPOSE 8080 9000 + +ENTRYPOINT ["laravel-entrypoint"] +CMD ["php-fpm"] diff --git a/composer.json b/composer.json index bffa8af..5cbe75a 100644 --- a/composer.json +++ b/composer.json @@ -63,12 +63,13 @@ ], "ci:check": [ "Composer\\Config::disableProcessTimeout", - "npm run check", + "npm audit --audit-level=high", + "npm run lint:check", "npm run types:check", "@test" ], "types:check": [ - "phpstan analyse" + "phpstan analyse --memory-limit=512M" ], "test": [ "@php artisan config:clear --ansi", @@ -115,4 +116,4 @@ }, "minimum-stability": "stable", "prefer-stable": true -} \ No newline at end of file +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a2866ee --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,109 @@ +services: + web: + container_name: scrum-poker-web + image: scrum-poker-app:local + build: + context: . + dockerfile: Dockerfile + target: runtime + command: nginx + restart: unless-stopped + ports: + - "8080:8080" + env_file: + - .env.production + environment: + PHP_FPM_UPSTREAM: php-fpm:9000 + networks: + - scrum-poker-web + healthcheck: + test: ["CMD", "curl", "--fail", "--silent", "http://127.0.0.1:8080/up"] + interval: 10s + timeout: 5s + retries: 3 + depends_on: + php-fpm: + condition: service_healthy + + php-fpm: + container_name: scrum-poker-php-fpm + image: scrum-poker-app:local + build: + context: . + dockerfile: Dockerfile + target: runtime + restart: unless-stopped + env_file: + - .env.production + networks: + - scrum-poker-web + - scrum-poker-db + healthcheck: + test: ["CMD-SHELL", "php-fpm-healthcheck || exit 1"] + interval: 10s + timeout: 5s + retries: 3 + depends_on: + mariadb: + condition: service_healthy + + worker: + container_name: scrum-poker-worker + image: scrum-poker-app:local + build: + context: . + dockerfile: Dockerfile + target: runtime + command: php artisan queue:work --sleep=3 --tries=3 --timeout=60 --max-time=3600 + restart: unless-stopped + env_file: + - .env.production + networks: + - scrum-poker-db + depends_on: + mariadb: + condition: service_healthy + + + reverb: + container_name: scrum-poker-reverb + image: scrum-poker-app:local + build: + context: . + dockerfile: Dockerfile + target: runtime + command: php artisan reverb:start + restart: unless-stopped + ports: + - "800:8000" + env_file: + - .env.production + networks: + - scrum-poker-db + depends_on: + mariadb: + condition: service_healthy + + mariadb: + container_name: scrum-poker-db + image: mariadb:11.4 + restart: unless-stopped + env_file: + - .env.mariadb + command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci + volumes: + - mariadb-data-production:/var/lib/mysql + networks: + - scrum-poker-db + healthcheck: + test: [ "CMD", "healthcheck.sh", "--connect", "--innodb_initialized" ] + start_period: 10s + interval: 10s + timeout: 5s + retries: 3 +networks: + scrum-poker-db: + scrum-poker-web: + +volumes: + mariadb-data-production: diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..d6485d2 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,26 @@ +#!/bin/sh +set -eu + +if [ "${1:-}" = "nginx" ]; then + : "${PHP_FPM_UPSTREAM:=127.0.0.1:9000}" + export PHP_FPM_UPSTREAM + + envsubst '${PHP_FPM_UPSTREAM}' \ + < /etc/nginx/nginx.conf.template \ + > /tmp/nginx.conf + + exec nginx -c /tmp/nginx.conf -g 'daemon off;' +fi + +mkdir -p \ + bootstrap/cache \ + storage/framework/cache \ + storage/framework/sessions \ + storage/framework/testing \ + storage/framework/views \ + storage/logs + +php artisan config:cache --no-ansi +php artisan route:cache --no-ansi + +exec "$@" diff --git a/docker/nginx/nginx.conf.template b/docker/nginx/nginx.conf.template new file mode 100644 index 0000000..1cf40b9 --- /dev/null +++ b/docker/nginx/nginx.conf.template @@ -0,0 +1,60 @@ +pid /tmp/nginx.pid; +error_log /dev/stderr warn; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + access_log /dev/stdout; + client_body_temp_path /tmp/client_body; + proxy_temp_path /tmp/proxy; + fastcgi_temp_path /tmp/fastcgi; + uwsgi_temp_path /tmp/uwsgi; + scgi_temp_path /tmp/scgi; + + sendfile on; + keepalive_timeout 65; + client_max_body_size 3m; + + server { + listen 8080; + server_name _; + root /var/www/public; + index index.php; + + location = /nginx-health { + access_log off; + default_type text/plain; + return 200 'ok'; + } + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + location = /index.php { + include /etc/nginx/fastcgi_params; + fastcgi_buffer_size 32k; + fastcgi_buffers 8 32k; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTP_PROXY ''; + fastcgi_param HTTP_X_FORWARDED_FOR $http_x_forwarded_for; + fastcgi_param HTTP_X_FORWARDED_HOST $http_x_forwarded_host; + fastcgi_param HTTP_X_FORWARDED_PORT $http_x_forwarded_port; + fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto; + fastcgi_pass ${PHP_FPM_UPSTREAM}; + } + + location ~ \.php$ { + return 404; + } + + location ~ /\. { + deny all; + } + } +} diff --git a/docker/php-fpm-healthcheck.sh b/docker/php-fpm-healthcheck.sh new file mode 100644 index 0000000..177473e --- /dev/null +++ b/docker/php-fpm-healthcheck.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu + +SCRIPT_NAME=/status \ +SCRIPT_FILENAME=/status \ +REQUEST_METHOD=GET \ +cgi-fcgi -bind -connect 127.0.0.1:9000 2>/dev/null | grep -q '^pool:' diff --git a/package-lock.json b/package-lock.json index e3138e9..7f3e6e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -522,9 +522,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -542,9 +539,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -562,9 +556,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -582,9 +573,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -602,9 +590,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -622,9 +607,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -642,9 +624,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -662,9 +641,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -953,9 +929,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -973,9 +946,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -993,9 +963,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1013,9 +980,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1033,9 +997,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1053,9 +1014,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1073,9 +1031,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1093,9 +1048,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1296,9 +1248,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1315,9 +1264,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1334,9 +1280,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1353,9 +1296,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1372,9 +1312,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1391,9 +1328,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1464,9 +1398,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1641,9 +1572,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1661,9 +1589,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1680,9 +1605,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1700,9 +1622,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1822,6 +1741,7 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -1888,6 +1808,7 @@ "integrity": "sha512-xlvWf4Vs9n1PEVYwP1n4vvG07M6y8WgvJ2t0vbrWTmijsIHp1cS+uJ2kMIRdY3nHZK0nCYKrPeD171+SzF4/zw==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -1944,6 +1865,7 @@ "integrity": "sha512-iPKSE6Ibayey6HFgK1V1/aHgyhx7HSRk1YMi+lnBZGmlIiNV5Uc7xRkD9Su8RDylTxDECK23t7kTHdRKoqSYDQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@testing-library/dom": "^10.4.1", "@testing-library/user-event": "^14.6.1", @@ -2323,9 +2245,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2347,9 +2266,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2371,9 +2287,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2450,9 +2363,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2470,9 +2380,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2490,9 +2397,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2510,9 +2414,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2814,9 +2715,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "optional": true, "os": [ "linux" @@ -2830,9 +2728,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "optional": true, "os": [ "linux" @@ -2846,9 +2741,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "optional": true, "os": [ "linux" @@ -2862,9 +2754,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "optional": true, "os": [ "linux" @@ -2878,9 +2767,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "optional": true, "os": [ "linux" @@ -2894,9 +2780,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "optional": true, "os": [ "linux" @@ -2975,9 +2858,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "optional": true, "os": [ "linux" @@ -2991,9 +2871,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "optional": true, "os": [ "linux" @@ -3007,9 +2884,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "optional": true, "os": [ "linux" @@ -3023,9 +2897,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "optional": true, "os": [ "linux" @@ -3039,9 +2910,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "optional": true, "os": [ "linux" @@ -3055,9 +2923,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "optional": true, "os": [ "linux" @@ -3932,9 +3797,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -3956,9 +3818,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -3979,9 +3838,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -4003,9 +3859,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -4068,9 +3921,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -4328,6 +4178,7 @@ "integrity": "sha512-KjK/XLcXr1DSyonKhsuFqJRiuKqcyG9j3LJ8nkOsrLzGvodBPqzHOKauy10asLMDI0sUpvb+1sxlzff3udZvfg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "tsgolint": "bin/tsgolint.js" }, @@ -4375,6 +4226,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -4458,16 +4310,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/react": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz", - "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -4928,6 +4770,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4948,6 +4791,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", "license": "MIT", + "peer": true, "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", @@ -5244,9 +5088,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5267,9 +5108,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5290,9 +5128,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -5332,6 +5167,7 @@ "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.1.11", "@vitest/mocker": "4.1.11", @@ -5428,6 +5264,7 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.42.tgz", "integrity": "sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.42", "@vue/compiler-sfc": "3.5.42", diff --git a/phpunit.xml b/phpunit.xml index e7f0a48..07eb6ef 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -19,6 +19,7 @@ +