diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..869e6be0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.git* +bin +vendor +.phpunit.result.cache diff --git a/.gitattributes b/.gitattributes index 899e65fe..281921e9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,10 +1,13 @@ /.github export-ignore +/local export-ignore /tests export-ignore +.dockerignore export-ignore .gitattributes export-ignore .gitignore export-ignore .php-cs-fixer.php export-ignore composer.lock export-ignore -merge infection.json.dist export-ignore +Makefile export-ignore phpstan.neon export-ignore phpstan-rector.neon export-ignore phpunit.xml.dist export-ignore diff --git a/.gitignore b/.gitignore index fc8c8425..f82c644a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /vendor phpunit.xml /.phpunit.result.cache +/local/.env diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..70ec5761 --- /dev/null +++ b/Makefile @@ -0,0 +1,47 @@ +DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +PROJECT_NAME = lendable_json_serializer_dev +CONTAINER = runner +PUID ?= 1000 +PGID ?= 1000 +EXEC_SHELL = /bin/sh +EXEC_USER = app + +DOCKER_COMPOSE = docker compose \ + -f ${DIR}/local/docker-compose.yaml \ + --project-directory $(DIR)/local \ + -p ${PROJECT_NAME} + +init: + @mkdir -p $(HOME)/.composer && (chown $(PUID):$(PGID) $(HOME)/.composer || echo "No need to chown $(HOME)/.composer"); + +build: + $(DOCKER_COMPOSE) build + +up: + $(DOCKER_COMPOSE) up -d + +down: + $(DOCKER_COMPOSE) down -v + +start: + $(DOCKER_COMPOSE) start + +stop: + $(DOCKER_COMPOSE) stop + +restart: + $(DOCKER_COMPOSE) restart + +ps: + $(DOCKER_COMPOSE) ps + +logs: + $(DOCKER_COMPOSE) logs -f + +shell: + $(DOCKER_COMPOSE) exec -u $(EXEC_USER) $(CONTAINER) $(EXEC_SHELL) + +clean: + @$(DOCKER_COMPOSE) down -v --rmi local + +.PHONY: init build up down start stop restart ps logs shell clean diff --git a/README.md b/README.md index 97da0c8a..0f0db49e 100644 --- a/README.md +++ b/README.md @@ -41,3 +41,45 @@ Deserializes a JSON string into an `array`. Throws `DeserializationFailed` on failure to deserialize. Throws `InvalidDeserializedData` if the data type of the resulting deserialized data is not an `array`. + +## Local development + +Everything runs inside Docker - no PHP or Composer is needed on the host. The +environment is defined in `local/` (`Dockerfile`, `docker-compose.yaml`, +`.env.dist`) and driven from the `Makefile`. + +### Prerequisites + +- Docker with Compose v2 + +### Getting started + +```shell +make up # builds the image (on first run) and starts the container +make shell # opens a shell inside the container, in /app +make down # stops and removes the container +``` + +From the shell: + +```shell +composer install +composer ci +``` + +### Common targets + +| Target | Description | +| --- | --- | +| `make build` | Build the container image | +| `make up` / `make down` | Start / tear down the environment | +| `make start` / `make stop` / `make restart` | Control the running container | +| `make ps` / `make logs` | Inspect the environment | +| `make shell` | Shell into the container as the `app` user | +| `make clean` | Tear down and remove the locally built image | + +### Xdebug + +Xdebug is installed but disabled by default. Copy `local/.env.dist` to +`local/.env`, set `XDEBUG_ENABLED=1` (optionally with `XDEBUG_HOST`, +`XDEBUG_PORT` and `XDEBUG_IDE_KEY`), then run `make restart`. diff --git a/local/.env.dist b/local/.env.dist new file mode 100644 index 00000000..5eef0b14 --- /dev/null +++ b/local/.env.dist @@ -0,0 +1,2 @@ +XDEBUG_ENABLED=0 +PHP_IDE_CONFIG=serverName=json-serializer diff --git a/local/Dockerfile b/local/Dockerfile new file mode 100644 index 00000000..8b7de1a2 --- /dev/null +++ b/local/Dockerfile @@ -0,0 +1,36 @@ +FROM public.ecr.aws/docker/library/php:8.4-cli-alpine AS base + +ARG USER_ID=1000 +ARG GROUP_ID=1000 + +RUN addgroup --gid "${GROUP_ID}" "app" && \ + adduser \ + --disabled-password \ + --gecos "" \ + --home "/app-home" \ + --ingroup "app" \ + --uid "${USER_ID}" \ + -s "/bin/sh" \ + "app" + +COPY --from=composer/composer:2.10.2-bin /composer /usr/bin/composer + +RUN apk add --no-cache git + +WORKDIR /app + +FROM base AS dev + +ARG XDEBUG_VERSION="3.5.1" +RUN apk add --no-cache autoconf file g++ gcc libc-dev make pkgconf re2c linux-headers \ + && apk add --no-cache bash git \ + && pecl install "xdebug-${XDEBUG_VERSION}" pcov \ + && docker-php-ext-enable pcov \ + && apk del autoconf file g++ gcc libc-dev make pkgconf re2c linux-headers + +COPY xdebug-entrypoint.sh /usr/local/bin/docker-php-xdebug-entrypoint + +RUN touch /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini /usr/local/bin/noxdebug \ + && chown app:app /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini /usr/local/bin/noxdebug + +USER app diff --git a/local/docker-compose.yaml b/local/docker-compose.yaml new file mode 100644 index 00000000..5b2a97db --- /dev/null +++ b/local/docker-compose.yaml @@ -0,0 +1,15 @@ +services: + runner: + entrypoint: "/usr/local/bin/docker-php-xdebug-entrypoint" + tty: true + build: + context: . + target: dev + environment: + XDEBUG_ENABLED: "${XDEBUG_ENABLED:-}" + XDEBUG_HOST: "${XDEBUG_HOST:-}" + XDEBUG_PORT: "${XDEBUG_PORT:-}" + XDEBUG_IDE_KEY: "${XDEBUG_IDE_KEY:-}" + PHP_IDE_CONFIG: "${PHP_IDE_CONFIG:-}" + volumes: + - "..:/app:rw" diff --git a/local/xdebug-entrypoint.sh b/local/xdebug-entrypoint.sh new file mode 100755 index 00000000..8d37eb33 --- /dev/null +++ b/local/xdebug-entrypoint.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +set -e + +if [ "${XDEBUG_ENABLED:-0}" = "1" ]; then + XDEBUG_HOST=${XDEBUG_HOST:-$(route -n | egrep "^0.0.0.0" | awk '{print $2}')} + + if [ "${XDEBUG_HOST}" = "" ]; then + echo "XDebug remote host could not be configured"; + exit 1; + fi + + XDEBUG_PORT="${XDEBUG_PORT:-9003}" + + echo "Configuring PHP for remote XDebug server ${XDEBUG_PORT}" + echo "zend_extension=xdebug.so +xdebug.mode = debug +xdebug.start_with_request = 1 +xdebug.client_host = ${XDEBUG_HOST} +xdebug.client_port = ${XDEBUG_PORT} +xdebug.idekey = ${XDEBUG_IDE_KEY:-PHPSTORM} +xdebug.max_nesting_level = 999999" > /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini + + echo '#!/bin/sh +php -dxdebug.mode\=off "$@"' > /usr/local/bin/noxdebug + + chmod 755 /usr/local/bin/noxdebug + +else + echo "Disabling XDebug per configuration" +fi + +/bin/sh